| File: Simplification\Reducers\CSharpCastReducer.Rewriter.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.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Simplification; namespace Microsoft.CodeAnalysis.CSharp.Simplification; internal sealed partial class CSharpCastReducer { private sealed class Rewriter : AbstractReductionRewriter { public Rewriter(ObjectPool<IReductionRewriter> pool) : base(pool) { } public override SyntaxNode VisitCastExpression(CastExpressionSyntax node) { return SimplifyNode( node, newNode: base.VisitCastExpression(node), simplifier: s_simplifyCast); } public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node) { var result = base.VisitBinaryExpression(node); var reducedNode = result as BinaryExpressionSyntax; if (reducedNode != node && reducedNode != null) { if ((node.Left.IsKind(SyntaxKind.CastExpression) && !reducedNode.Left.IsKind(SyntaxKind.CastExpression)) || (node.Right.IsKind(SyntaxKind.CastExpression) && !reducedNode.Right.IsKind(SyntaxKind.CastExpression))) { // Cast simplification inside a binary expression, check if we need to parenthesize the binary expression to avoid breaking parent syntax. // For example, cast removal in below case leads to syntax errors in error free code, unless parenting binary expression is parenthesized: // Original: Goo(x < (int)i, x > y) // Incorrect cast removal: Goo(x < i, x > y) // Correct cast removal: Goo((x < i), x > y) // We'll do the following to detect such cases: // 1) Get the topmostExpressionAncestor of node. // 2) Get the reducedAncestor after replacing node with reducedNode within it. // 3) Reparse the reducedAncestor to get reparsedAncestor. // 4) Check for syntax equivalence of reducedAncestor and reparsedAncestor. If not syntactically equivalent, // then cast removal breaks the syntax and needs explicit parentheses around the binary expression. var topmostExpressionAncestor = node .AncestorsAndSelf() .OfType<ExpressionSyntax>() .LastOrDefault(); if (topmostExpressionAncestor != null && topmostExpressionAncestor != node) { var reducedAncestor = topmostExpressionAncestor.ReplaceNode(node, reducedNode); var reparsedAncestor = SyntaxFactory.ParseExpression(reducedAncestor.ToFullString()); if (reparsedAncestor != null && !reparsedAncestor.IsEquivalentTo(reducedAncestor)) { return SyntaxFactory.ParenthesizedExpression(reducedNode) .WithAdditionalAnnotations(Simplifier.Annotation); } } } } return result; } } }