diff --git a/ChangeLog.md b/ChangeLog.md index 38a52973de..791a697856 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix analyzer [RCS1203](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1203) ([PR](https://github.com/dotnet/roslynator/pull/1282)) - Fix analyzer [RCS1046](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1046) ([PR](https://github.com/dotnet/roslynator/pull/1283)) - Fix analyzer [RCS1158](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1158) ([PR](https://github.com/dotnet/roslynator/pull/1288)) +- Fix analyzer [RCS1032](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1032) ([PR](https://github.com/dotnet/roslynator/pull/1289)) ## [4.6.4] - 2023-11-24 diff --git a/src/Analyzers/CSharp/Analysis/RemoveRedundantParenthesesAnalyzer.cs b/src/Analyzers/CSharp/Analysis/RemoveRedundantParenthesesAnalyzer.cs index 39a24105ad..cb92ba36b2 100644 --- a/src/Analyzers/CSharp/Analysis/RemoveRedundantParenthesesAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/RemoveRedundantParenthesesAnalyzer.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Text; namespace Roslynator.CSharp.Analysis; @@ -83,7 +84,7 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con case SyntaxKind.SwitchStatement: case SyntaxKind.ArrayRankSpecifier: { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); break; } case SyntaxKind.LessThanExpression: @@ -97,7 +98,7 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con if (expression.IsKind(SyntaxKind.IdentifierName) || expression is LiteralExpressionSyntax) { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); } break; @@ -120,12 +121,12 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con if (kind == SyntaxKind.IdentifierName || expression is LiteralExpressionSyntax) { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); } else if (kind == parentKind && ((BinaryExpressionSyntax)parent).Left == parenthesizedExpression) { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); } break; @@ -141,7 +142,7 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con case SyntaxKind.ElementAccessExpression: case SyntaxKind.ConditionalAccessExpression: { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); break; } } @@ -162,12 +163,12 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con { if (((AssignmentExpressionSyntax)parent).Left == parenthesizedExpression) { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); } else if (expression.IsKind(SyntaxKind.IdentifierName) || expression is LiteralExpressionSyntax) { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); } break; @@ -178,7 +179,7 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con && !expression.DescendantNodes().Any(f => f.IsKind(SyntaxKind.AliasQualifiedName)) && ((InterpolationSyntax)parent).Expression == parenthesizedExpression) { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); } break; @@ -189,7 +190,7 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con return; if (CSharpFacts.GetOperatorPrecedence(expression.Kind()) <= CSharpFacts.GetOperatorPrecedence(SyntaxKind.AwaitExpression)) - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); break; } @@ -197,7 +198,7 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con case SyntaxKind.CollectionInitializerExpression: { if (expression is not AssignmentExpressionSyntax) - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); break; } @@ -215,7 +216,7 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con case SyntaxKind.AddAssignmentExpression: case SyntaxKind.SubtractAssignmentExpression: { - ReportDiagnostic(); + ReportDiagnostic(context, parenthesizedExpression); break; } #if DEBUG @@ -231,16 +232,35 @@ private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext con } } - void ReportDiagnostic() + static void ReportDiagnostic(SyntaxNodeAnalysisContext context, ParenthesizedExpressionSyntax parenthesizedExpression) { + if (parenthesizedExpression.Expression.IsKind(SyntaxKind.LessThanExpression) + && parenthesizedExpression.IsParentKind(SyntaxKind.Argument) + && parenthesizedExpression.Parent.Parent is BaseArgumentListSyntax argumentList) + { + SeparatedSyntaxList arguments = argumentList.Arguments; + int index = arguments.IndexOf((ArgumentSyntax)parenthesizedExpression.Parent); + + if (index < arguments.Count - 1) + { + string syntax = parenthesizedExpression.Expression + + argumentList.ToString(TextSpan.FromBounds(arguments[index].Span.End, arguments[index + 1].Span.End)); + + NameSyntax name = SyntaxFactory.ParseName(syntax); + + if (name.IsKind(SyntaxKind.GenericName)) + return; + } + } + DiagnosticHelpers.ReportDiagnostic( context, DiagnosticRules.RemoveRedundantParentheses, - openParen.GetLocation(), - additionalLocations: ImmutableArray.Create(closeParen.GetLocation())); + parenthesizedExpression.OpenParenToken.GetLocation(), + additionalLocations: ImmutableArray.Create(parenthesizedExpression.CloseParenToken.GetLocation())); - DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantParenthesesFadeOut, openParen); - DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantParenthesesFadeOut, closeParen); + DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantParenthesesFadeOut, parenthesizedExpression.OpenParenToken); + DiagnosticHelpers.ReportToken(context, DiagnosticRules.RemoveRedundantParenthesesFadeOut, parenthesizedExpression.CloseParenToken); } } } diff --git a/src/Tests/Analyzers.Tests/RCS1032RemoveRedundantParenthesesTests.cs b/src/Tests/Analyzers.Tests/RCS1032RemoveRedundantParenthesesTests.cs index 4235586f21..24f3d30b04 100644 --- a/src/Tests/Analyzers.Tests/RCS1032RemoveRedundantParenthesesTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1032RemoveRedundantParenthesesTests.cs @@ -589,6 +589,31 @@ async Task M() }); } } +"); + } + + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.RemoveRedundantParentheses)] + public async Task TestNoDiagnostic_GrammarAmbiguity() + { + await VerifyNoDiagnosticAsync(@" +using System; + +public class Foo +{ + public static void F(bool p1, bool p2) + { + int x = 0; + int y = 0; + Bar d = null; + F((x < y), d > (d ?? d)); + } +} + +public class Bar +{ + public static bool operator >(Bar left, Bar right) => throw new NotImplementedException(); + public static bool operator <(Bar left, Bar right) => throw new NotImplementedException(); +} "); } }