Skip to content

Commit

Permalink
Merge pull request #2411 from sharwell/fix-sa1009-operators
Browse files Browse the repository at this point in the history
Fix behavior of SA1009 for closing parenthesis before binary operator
  • Loading branch information
sharwell authored Jun 15, 2017
2 parents ca4acb4 + b8d237b commit 9849873
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -232,49 +232,23 @@ public async Task TestLambdaExpressionWithNoSpaceAfterClosingParenthesisAsync()
await this.TestWhitespaceInStatementOrDeclAsync(invalidStatement, validStatement, expected).ConfigureAwait(false);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#255 and
/// DotNetAnalyzers/StyleCopAnalyzers#256.
/// </summary>
/// <param name="operatorToken">The operator to test.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[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]
Expand Down Expand Up @@ -835,6 +809,83 @@ void Method()
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#2409.
/// </summary>
/// <param name="operatorToken">The operator to test.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[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);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#2409.
/// </summary>
/// <param name="operatorToken">The operator to test.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[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);
}

/// <summary>
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#2409.
/// </summary>
/// <param name="operatorToken">The operator to test.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
[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()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
{
Expand All @@ -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:
Expand Down

0 comments on commit 9849873

Please sign in to comment.