diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1009UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1009UnitTests.cs index 39543398f..508d12ef9 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1009UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1009UnitTests.cs @@ -232,49 +232,23 @@ public async Task TestLambdaExpressionWithNoSpaceAfterClosingParenthesisAsync() await this.TestWhitespaceInStatementOrDeclAsync(invalidStatement, validStatement, expected).ConfigureAwait(false); } + /// + /// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#255 and + /// DotNetAnalyzers/StyleCopAnalyzers#256. + /// + /// The operator to test. + /// A representing the asynchronous operation. [Theory] [InlineData("+")] [InlineData("-")] - [InlineData("*")] - [InlineData("/")] - public async Task TestSpaceAfterParenthisisInArithmeticOperationAsync(string operatorValue) - { - // e.g. var i = (1 + 1) + 2 - var validStatement = string.Format(@"var i = (1 + 1) {0} 2;", operatorValue); - - await this.TestWhitespaceInStatementOrDeclAsync(validStatement, string.Empty, EmptyDiagnosticResults).ConfigureAwait(false); - } - - [Fact] - public async Task TestNoSpaceAfterParenthisisInAddOperationAsync() - { - // Note - this looks wrong but according to comments in the implementation "this will be reported as SA1022" - var invalidStatement = @"var i = (1 + 1)+ 2;"; - - await this.TestWhitespaceInStatementOrDeclAsync(invalidStatement, string.Empty, EmptyDiagnosticResults).ConfigureAwait(false); - } - - [Fact] - public async Task TestNoSpaceAfterParenthisisInSubtractOperationAsync() - { - // Note - this looks wrong but according to comments in the implementation "this will be reported as SA1021" - var invalidStatement = @"var i = (1 + 1)- 2;"; - - await this.TestWhitespaceInStatementOrDeclAsync(invalidStatement, string.Empty, EmptyDiagnosticResults).ConfigureAwait(false); - } - - [Theory] - [InlineData("*")] - [InlineData("/")] - public async Task TestNoSpaceAfterParenthisisInArithmeticOperationAsync(string operatorValue) + public async Task TestNotReportedWhenFollowedByUnaryPlusOrMinusAsync(string operatorToken) { - // e.g. var i = (1 + 1)* 2; - var invalidStatement = string.Format(@"var i = (1 + 1){0} 2;", operatorValue); - var validStatement = string.Format(@"var i = (1 + 1) {0} 2;", operatorValue); + // This will be reported as SA1021 or SA1022 + var ignoredStatement = $"var i = (int) {operatorToken}2;"; + var correctStatement = $"var i = (int){operatorToken}2;"; - DiagnosticResult expected = this.CSharpDiagnostic().WithArguments(string.Empty, "followed").WithLocation(7, 27); - - await this.TestWhitespaceInStatementOrDeclAsync(invalidStatement, validStatement, expected).ConfigureAwait(false); + await this.TestWhitespaceInStatementOrDeclAsync(ignoredStatement, string.Empty, EmptyDiagnosticResults).ConfigureAwait(false); + await this.TestWhitespaceInStatementOrDeclAsync(correctStatement, string.Empty, EmptyDiagnosticResults).ConfigureAwait(false); } [Fact] @@ -835,6 +809,83 @@ void Method() await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false); } + /// + /// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#2409. + /// + /// The operator to test. + /// A representing the asynchronous operation. + [Theory] + [InlineData("*")] + [InlineData("/")] + [InlineData("%")] + [InlineData("+")] + [InlineData("-")] + [InlineData("<<")] + [InlineData(">>")] + [InlineData("<")] + [InlineData(">")] + [InlineData("<=")] + [InlineData(">=")] + [InlineData("==")] + [InlineData("!=")] + [InlineData("&")] + [InlineData("^")] + [InlineData("|")] + public async Task TestFollowedByBinaryOperatorAsync(string operatorToken) + { + string testCode = $"var x = (3 + 2){operatorToken} 4;"; + string fixedCode = $"var x = (3 + 2) {operatorToken} 4;"; + + DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 27).WithArguments(string.Empty, "followed"); + + await this.TestWhitespaceInStatementOrDeclAsync(testCode, fixedCode, expected).ConfigureAwait(false); + } + + /// + /// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#2409. + /// + /// The operator to test. + /// A representing the asynchronous operation. + [Theory] + [InlineData("&&")] + [InlineData("||")] + public async Task TestFollowedByConditionalOperatorAsync(string operatorToken) + { + string testCode = $"var x = (true){operatorToken} false;"; + string fixedCode = $"var x = (true) {operatorToken} false;"; + + DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 26).WithArguments(string.Empty, "followed"); + + await this.TestWhitespaceInStatementOrDeclAsync(testCode, fixedCode, expected).ConfigureAwait(false); + } + + /// + /// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#2409. + /// + /// The operator to test. + /// A representing the asynchronous operation. + [Theory] + [InlineData("=")] + [InlineData("+=")] + [InlineData("-=")] + [InlineData("*=")] + [InlineData("/=")] + [InlineData("%=")] + [InlineData("&=")] + [InlineData("|=")] + [InlineData("^=")] + [InlineData("<<=")] + [InlineData(">>=")] + public async Task TestFollowedByAssignmentOperatorAsync(string operatorToken) + { + string testCode = $"var x = 0; (x){operatorToken} 4;"; + string fixedCode = $"var x = 0; (x) {operatorToken} 4;"; + + DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 26).WithArguments(string.Empty, "followed"); + + await this.TestWhitespaceInStatementOrDeclAsync(testCode, fixedCode, expected).ConfigureAwait(false); + } + [Fact] public async Task TestMissingTokenAsync() { diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1009ClosingParenthesisMustBeSpacedCorrectly.cs b/StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1009ClosingParenthesisMustBeSpacedCorrectly.cs index 452fffb82..3398892e3 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1009ClosingParenthesisMustBeSpacedCorrectly.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1009ClosingParenthesisMustBeSpacedCorrectly.cs @@ -4,7 +4,6 @@ namespace StyleCop.Analyzers.SpacingRules { using System; - using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -94,10 +93,13 @@ private static void HandleCloseParenToken(SyntaxTreeAnalysisContext context, Syn case SyntaxKind.SemicolonToken: case SyntaxKind.CommaToken: case SyntaxKind.DoubleQuoteToken: - case SyntaxKind.GreaterThanToken: precedesStickyCharacter = true; break; + case SyntaxKind.GreaterThanToken: + precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.TypeArgumentList); + break; + case SyntaxKind.QuestionToken: if (nextToken.Parent.IsKind(SyntaxKind.ConditionalAccessExpression)) { @@ -116,14 +118,14 @@ private static void HandleCloseParenToken(SyntaxTreeAnalysisContext context, Syn precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryPlusExpression); // this will be reported as SA1022 - suppressFollowingSpaceError = true; + suppressFollowingSpaceError = precedesStickyCharacter; break; case SyntaxKind.MinusToken: precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryMinusExpression); // this will be reported as SA1021 - suppressFollowingSpaceError = true; + suppressFollowingSpaceError = precedesStickyCharacter; break; case SyntaxKind.DotToken: