Skip to content

Commit 995e93d

Browse files
committed
Merge pull request #702 from sharwell/fix-689
Fix SA1509 getting reported for consecutive blocks
2 parents c7e6ed8 + 81250fe commit 995e93d

4 files changed

Lines changed: 199 additions & 20 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/LayoutRules/SA1509UnitTests.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,158 @@ void Bar()
637637
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
638638
}
639639

640+
[Fact]
641+
public async Task TestBlockStatementsAsync()
642+
{
643+
var testCode = @"
644+
class Foo
645+
{
646+
void Bar()
647+
{
648+
649+
{
650+
}
651+
652+
{
653+
}
654+
}
655+
}";
656+
657+
var fixedCode = @"
658+
class Foo
659+
{
660+
void Bar()
661+
{
662+
{
663+
}
664+
665+
{
666+
}
667+
}
668+
}";
669+
670+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 9);
671+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
672+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
673+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
674+
}
675+
676+
[Fact]
677+
public async Task TestBlockStatementsWithBlockCommentAsync()
678+
{
679+
var testCode = @"
680+
class Foo
681+
{
682+
void Bar()
683+
{
684+
/* Comment */
685+
686+
{
687+
}
688+
689+
{
690+
}
691+
}
692+
}";
693+
694+
var fixedCode = @"
695+
class Foo
696+
{
697+
void Bar()
698+
{
699+
/* Comment */
700+
{
701+
}
702+
703+
{
704+
}
705+
}
706+
}";
707+
708+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(8, 9);
709+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
710+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
711+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
712+
}
713+
714+
[Fact]
715+
public async Task TestBlockStatementsWithLineCommentAsync()
716+
{
717+
var testCode = @"
718+
class Foo
719+
{
720+
void Bar()
721+
{
722+
// Comment
723+
724+
{
725+
}
726+
727+
{
728+
}
729+
}
730+
}";
731+
732+
var fixedCode = @"
733+
class Foo
734+
{
735+
void Bar()
736+
{
737+
// Comment
738+
{
739+
}
740+
741+
{
742+
}
743+
}
744+
}";
745+
746+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(8, 9);
747+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
748+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
749+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
750+
}
751+
752+
[Fact]
753+
public async Task TestBlockStatementsWithRegionAsync()
754+
{
755+
var testCode = @"
756+
class Foo
757+
{
758+
void Bar()
759+
{
760+
#region Region
761+
762+
{
763+
}
764+
765+
{
766+
}
767+
#endregion
768+
}
769+
}";
770+
771+
var fixedCode = @"
772+
class Foo
773+
{
774+
void Bar()
775+
{
776+
#region Region
777+
{
778+
}
779+
780+
{
781+
}
782+
#endregion
783+
}
784+
}";
785+
786+
DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(8, 9);
787+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
788+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
789+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
790+
}
791+
640792
[Fact]
641793
public async Task TestComplex1Async()
642794
{

StyleCop.Analyzers/StyleCop.Analyzers/LayoutRules/SA1509OpeningBracesMustNotBePrecededByBlankLine.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace StyleCop.Analyzers.LayoutRules
88
using System.Linq;
99
using Microsoft.CodeAnalysis;
1010
using Microsoft.CodeAnalysis.CSharp;
11+
using Microsoft.CodeAnalysis.CSharp.Syntax;
1112
using Microsoft.CodeAnalysis.Diagnostics;
1213
using StyleCop.Analyzers.Helpers;
1314

@@ -74,19 +75,21 @@ private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
7475
{
7576
var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);
7677

77-
var openBraces = syntaxRoot.DescendantTokens()
78-
.Where(t => t.IsKind(SyntaxKind.OpenBraceToken));
79-
80-
foreach (var openBrace in openBraces)
78+
SyntaxToken previousToken = default(SyntaxToken);
79+
foreach (var token in syntaxRoot.DescendantTokens())
8180
{
82-
AnalyzeOpenBrace(context, openBrace);
81+
if (token.IsKind(SyntaxKind.OpenBraceToken) && !previousToken.IsKind(SyntaxKind.CloseBraceToken))
82+
{
83+
AnalyzeOpenBrace(context, token, previousToken);
84+
}
85+
86+
previousToken = token;
8387
}
8488
}
8589

86-
private static void AnalyzeOpenBrace(SyntaxTreeAnalysisContext context, SyntaxToken openBrace)
90+
private static void AnalyzeOpenBrace(SyntaxTreeAnalysisContext context, SyntaxToken openBrace, SyntaxToken previousToken)
8791
{
88-
var prevToken = openBrace.GetPreviousToken();
89-
var triviaList = TriviaHelper.MergeTriviaLists(prevToken.TrailingTrivia, openBrace.LeadingTrivia);
92+
var triviaList = TriviaHelper.MergeTriviaLists(previousToken.TrailingTrivia, openBrace.LeadingTrivia);
9093

9194
var done = false;
9295
var eolCount = 0;

documentation/SA1509.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,43 @@ An opening brace within a C# element, statement, or expression is preceded by a
2121

2222
## Rule description
2323

24-
To improve the readability of the code, StyleCop requires blank lines in certain situations, and prohibits blank lines in other situations. This results in a consistent visual pattern across the code, which can improve recognition and readability of unfamiliar code.
24+
To improve the readability of the code, StyleCop requires blank lines in certain situations, and prohibits blank lines
25+
in other situations. This results in a consistent visual pattern across the code, which can improve recognition and
26+
readability of unfamiliar code.
2527

26-
A violation of this rule occurs when an opening brace is preceded by a blank line. For example:
28+
In general, a violation of this rule occurs when an opening brace is preceded by a blank line. For example, the
29+
following above would generate two instances of this violation, since there are two places where opening braces are
30+
preceded by blank lines.
2731

2832
```csharp
2933
public bool Enabled
3034

3135
{
32-
get
36+
get
3337

34-
{
35-
return this.enabled;
38+
{
39+
return this.enabled;
3640
}
3741
}
3842
```
3943

40-
The code above would generate two instances of this violation, since there are two places where opening braces are preceded by blank lines.
44+
An exception to this rule occurs when the opening brace is preceded by a closing brace. When this occurs, a blank line
45+
will be required by [SA1513](SA1513.md). The following example shows correct use of blank lines:
46+
47+
```csharp
48+
public bool Enabled
49+
{
50+
get
51+
{
52+
{
53+
}
54+
55+
{
56+
return this.enabled;
57+
}
58+
}
59+
}
60+
```
4161

4262
## How to fix violations
4363

documentation/SA1513.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,24 @@ A closing brace within a C# element, statement, or expression is not followed by
2121

2222
## Rule description
2323

24-
To improve the readability of the code, StyleCop requires blank lines in certain situations, and prohibits blank lines in other situations. This results in a consistent visual pattern across the code, which can improve recognition and readability of unfamiliar code.
24+
To improve the readability of the code, StyleCop requires blank lines in certain situations, and prohibits blank lines
25+
in other situations. This results in a consistent visual pattern across the code, which can improve recognition and
26+
readability of unfamiliar code.
2527

26-
A violation of this rule occurs when a closing brace is not followed by a blank line. For example:
28+
A violation of this rule occurs when a closing brace is not followed by a blank line. For example, the following code
29+
would generate one instance of this violation, since there is one place where a closing brace is not followed by a blank
30+
line.
2731

2832
```csharp
2933
public bool Enabled
3034
{
31-
get
32-
{
33-
return this.enabled;
35+
get
36+
{
37+
return this.enabled;
3438
}}
3539
```
3640

37-
The code above would generate one instance of this violation, since there is one place where a closing brace is not followed by a blank line.
41+
3842

3943
## How to fix violations
4044

0 commit comments

Comments
 (0)