Skip to content

Commit 493f304

Browse files
committed
Fix SA1127 handling of multi-line declarations
Fixes #1476
1 parent 310da2f commit 493f304

2 files changed

Lines changed: 63 additions & 39 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1127UnitTests.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,64 @@ private void Method<T>()
7070
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
7171
}
7272

73+
/// <summary>
74+
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1476:
75+
/// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1476
76+
/// </summary>
77+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
78+
[Fact]
79+
public async Task TestViolationWithObsoleteMethodDeclarationAsync()
80+
{
81+
var testCode = @"
82+
class Foo
83+
{
84+
[System.Obsolete]
85+
private void Method<T>() where T : class { }
86+
}";
87+
var fixedCode = @"
88+
class Foo
89+
{
90+
[System.Obsolete]
91+
private void Method<T>()
92+
where T : class
93+
{ }
94+
}";
95+
var expected = this.CSharpDiagnostic().WithLocation(5, 30);
96+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
97+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
98+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
99+
}
100+
101+
/// <summary>
102+
/// This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1476:
103+
/// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1476
104+
/// </summary>
105+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
106+
[Fact]
107+
public async Task TestViolationWithMethodDeclarationMultiLineParametersAsync()
108+
{
109+
var testCode = @"
110+
class Foo
111+
{
112+
private void Method<T>(
113+
int a,
114+
int b) where T : class { }
115+
}";
116+
var fixedCode = @"
117+
class Foo
118+
{
119+
private void Method<T>(
120+
int a,
121+
int b)
122+
where T : class
123+
{ }
124+
}";
125+
var expected = this.CSharpDiagnostic().WithLocation(6, 16);
126+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
127+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
128+
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
129+
}
130+
73131
[Fact]
74132
public async Task TestViolationWithExpressionBodiedMethodDeclarationAsync()
75133
{

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1127GenericTypeConstraintsMustBeOnOwnLine.cs

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -52,49 +52,15 @@ public override void Initialize(AnalysisContext context)
5252

5353
private static void HandleCompilationStart(CompilationStartAnalysisContext context)
5454
{
55-
context.RegisterSyntaxNodeActionHonorExclusions(HandleMethodDeclaration, SyntaxKind.MethodDeclaration);
56-
context.RegisterSyntaxNodeActionHonorExclusions(HandleTypeDeclaration, SyntaxKind.ClassDeclaration);
57-
context.RegisterSyntaxNodeActionHonorExclusions(HandleTypeDeclaration, SyntaxKind.StructDeclaration);
58-
context.RegisterSyntaxNodeActionHonorExclusions(HandleTypeDeclaration, SyntaxKind.InterfaceDeclaration);
55+
context.RegisterSyntaxNodeActionHonorExclusions(HandleTypeParameterConstraintClause, SyntaxKind.TypeParameterConstraintClause);
5956
}
6057

61-
private static void HandleMethodDeclaration(SyntaxNodeAnalysisContext context)
58+
private static void HandleTypeParameterConstraintClause(SyntaxNodeAnalysisContext context)
6259
{
63-
var declaration = (MethodDeclarationSyntax)context.Node;
64-
var declarationLineSpan = declaration.GetLineSpan();
65-
66-
if (declaration.TypeParameterList?.Parameters.Count > 0)
67-
{
68-
Analyze(context, declarationLineSpan, declaration.ConstraintClauses);
69-
}
70-
}
71-
72-
private static void HandleTypeDeclaration(SyntaxNodeAnalysisContext context)
73-
{
74-
var declaration = (TypeDeclarationSyntax)context.Node;
75-
var declarationLineSpan = declaration.GetLineSpan();
76-
77-
if (declaration.TypeParameterList?.Parameters.Count > 0)
60+
var syntax = (TypeParameterConstraintClauseSyntax)context.Node;
61+
if (!syntax.WhereKeyword.IsFirstInLine())
7862
{
79-
Analyze(context, declarationLineSpan, declaration.ConstraintClauses);
80-
}
81-
}
82-
83-
private static void Analyze(
84-
SyntaxNodeAnalysisContext context,
85-
FileLinePositionSpan declarationLineSpan,
86-
SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses)
87-
{
88-
int currentLine = declarationLineSpan.StartLinePosition.Line;
89-
foreach (var constraint in constraintClauses)
90-
{
91-
int constraintLine = constraint.GetLineSpan().StartLinePosition.Line;
92-
if (currentLine == constraintLine)
93-
{
94-
context.ReportDiagnostic(Diagnostic.Create(Descriptor, constraint.GetLocation()));
95-
}
96-
97-
currentLine = constraintLine;
63+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, syntax.GetLocation()));
9864
}
9965
}
10066
}

0 commit comments

Comments
 (0)