| File: Simplification\Reducers\CSharpMiscellaneousReducer.cs | Web Access |
| Project: src\roslyn\src\Workspaces\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Workspaces.csproj (Microsoft.CodeAnalysis.CSharp.Workspaces) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Simplification; internal sealed partial class CSharpMiscellaneousReducer : AbstractCSharpReducer { private static readonly ObjectPool<IReductionRewriter> s_pool = new( () => new Rewriter(s_pool)); private static readonly Func<ParameterSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode> s_simplifyParameter = SimplifyParameter; public CSharpMiscellaneousReducer() : base(s_pool) { } protected override bool IsApplicable(CSharpSimplifierOptions options) => true; private static bool CanRemoveTypeFromParameter( ParameterSyntax parameterSyntax, SemanticModel semanticModel, CancellationToken cancellationToken) { // We reduce any the parameters that are contained inside ParameterList if (parameterSyntax.IsParentKind(SyntaxKind.ParameterList) && parameterSyntax.Parent.IsParentKind(SyntaxKind.ParenthesizedLambdaExpression)) { if (parameterSyntax.Type != null) { var annotation = new SyntaxAnnotation(); var newParameterSyntax = parameterSyntax.WithType(null).WithAdditionalAnnotations(annotation); var oldLambda = parameterSyntax.FirstAncestorOrSelf<ParenthesizedLambdaExpressionSyntax>(); var newLambda = oldLambda.ReplaceNode(parameterSyntax, newParameterSyntax); var speculationAnalyzer = new SpeculationAnalyzer(oldLambda, newLambda, semanticModel, cancellationToken); newParameterSyntax = (ParameterSyntax)speculationAnalyzer.ReplacedExpression.GetAnnotatedNodesAndTokens(annotation).First(); var oldSymbol = semanticModel.GetDeclaredSymbol(parameterSyntax, cancellationToken); var newSymbol = speculationAnalyzer.SpeculativeSemanticModel.GetDeclaredSymbol(newParameterSyntax, cancellationToken); if (oldSymbol != null && newSymbol != null && Equals(oldSymbol.Type, newSymbol.Type)) { return !speculationAnalyzer.ReplacementChangesSemantics(); } } } return false; } private static SyntaxNode SimplifyParameter( ParameterSyntax node, SemanticModel semanticModel, SimplifierOptions options, CancellationToken cancellationToken) { if (CanRemoveTypeFromParameter(node, semanticModel, cancellationToken)) { var newParameterSyntax = node.WithType(null); newParameterSyntax = SimplificationHelpers.CopyAnnotations(node, newParameterSyntax).WithoutAnnotations(Simplifier.Annotation); return newParameterSyntax; } return node; } private static readonly Func<ParenthesizedLambdaExpressionSyntax, SemanticModel, SimplifierOptions, CancellationToken, SyntaxNode> s_simplifyParenthesizedLambdaExpression = SimplifyParenthesizedLambdaExpression; private static SyntaxNode SimplifyParenthesizedLambdaExpression( ParenthesizedLambdaExpressionSyntax parenthesizedLambda, SemanticModel semanticModel, SimplifierOptions options, CancellationToken cancellationToken) { if (parenthesizedLambda.ParameterList != null && parenthesizedLambda.ParameterList.Parameters.Count == 1) { var parameter = parenthesizedLambda.ParameterList.Parameters.First(); if (CanRemoveTypeFromParameter(parameter, semanticModel, cancellationToken)) { var newParameterSyntax = parameter.WithType(null); var newSimpleLambda = SyntaxFactory.SimpleLambdaExpression( parenthesizedLambda.AsyncKeyword, newParameterSyntax.WithTrailingTrivia(parenthesizedLambda.ParameterList.GetTrailingTrivia()), parenthesizedLambda.ArrowToken, parenthesizedLambda.Body); return SimplificationHelpers.CopyAnnotations(parenthesizedLambda, newSimpleLambda).WithoutAnnotations(Simplifier.Annotation); } } return parenthesizedLambda; } private static readonly Func<BlockSyntax, SemanticModel, CSharpSimplifierOptions, CancellationToken, SyntaxNode> s_simplifyBlock = SimplifyBlock; private static SyntaxNode SimplifyBlock( BlockSyntax node, SemanticModel semanticModel, CSharpSimplifierOptions options, CancellationToken cancellationToken) { if (node.Statements.Count != 1) { return node; } if (!CanHaveEmbeddedStatement(node.Parent)) { return node; } switch (options.PreferBraces.Value) { case PreferBracesPreference.Always: default: return node; case PreferBracesPreference.WhenMultiline: // Braces are optional in several scenarios for 'when_multiline', but are only automatically removed // in a subset of cases where all of the following are met: // // 1. This is an 'if' statement // 1. The 'if' statement does not have an 'else' clause and is not part of a larger 'if'/'else if'/'else' sequence // 2. The 'if' statement is not considered multiline if (!node.Parent.IsKind(SyntaxKind.IfStatement)) { // Braces are only removed for 'if' statements return node; } if (node.Parent?.Parent is (kind: SyntaxKind.IfStatement or SyntaxKind.ElseClause)) { // Braces are not removed from more complicated 'if' sequences return node; } if (!FormattingRangeHelper.AreTwoTokensOnSameLine(node.Statements[0].GetFirstToken(), node.Statements[0].GetLastToken())) { // Braces are not removed when the embedded statement is multiline return node; } if (!FormattingRangeHelper.AreTwoTokensOnSameLine(node.Parent.GetFirstToken(), node.GetFirstToken().GetPreviousToken())) { // Braces are not removed when the part of the 'if' statement preceding the embedded statement // is multiline. return node; } break; case PreferBracesPreference.None: break; } return node.Statements[0]; } private static bool CanHaveEmbeddedStatement(SyntaxNode node) { if (node != null) { switch (node.Kind()) { case SyntaxKind.IfStatement: case SyntaxKind.ElseClause: case SyntaxKind.ForStatement: case SyntaxKind.ForEachStatement: case SyntaxKind.ForEachVariableStatement: case SyntaxKind.WhileStatement: case SyntaxKind.DoStatement: case SyntaxKind.UsingStatement: case SyntaxKind.LockStatement: return true; } } return false; } }