Skip to content

Commit cfd10f9

Browse files
committed
Allow directive trivia in parameter list
1 parent ac225c9 commit cfd10f9

4 files changed

Lines changed: 125 additions & 51 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1114UnitTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,35 @@ private void SomeOtherMethod(int someParameter)
10671067
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
10681068
}
10691069

1070+
/// <summary>
1071+
/// Verifies that directive trivia will not result in diagnostics.
1072+
/// This is a regression test for #1623
1073+
/// </summary>
1074+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
1075+
[Fact]
1076+
public async Task TestWithDirectiveTriviaAsync()
1077+
{
1078+
var testCode = @"
1079+
public interface ITestInterface1 { }
1080+
1081+
public interface ITestInterface2 { }
1082+
1083+
public class TestClass
1084+
{
1085+
public void TestMethod(
1086+
#if TESTSYMBOL
1087+
ITestInterface1 instance)
1088+
#else
1089+
ITestInterface2 instance)
1090+
#endif
1091+
{
1092+
}
1093+
}
1094+
";
1095+
1096+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
1097+
}
1098+
10701099
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
10711100
{
10721101
yield return new SA1114ParameterListMustFollowDeclaration();

StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1115UnitTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,36 @@ public class Foo
10991099
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
11001100
}
11011101

1102+
/// <summary>
1103+
/// Verifies that directive trivia will not result in diagnostics.
1104+
/// This is a regression test for #1623
1105+
/// </summary>
1106+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
1107+
[Fact]
1108+
public async Task TestWithDirectiveTriviaAsync()
1109+
{
1110+
var testCode = @"
1111+
public interface ITestInterface1 { }
1112+
1113+
public interface ITestInterface2 { }
1114+
1115+
public class TestClass
1116+
{
1117+
public void TestMethod(
1118+
int parameter1,
1119+
#if TESTSYMBOL
1120+
ITestInterface1 instance)
1121+
#else
1122+
ITestInterface2 instance)
1123+
#endif
1124+
{
1125+
}
1126+
}
1127+
";
1128+
1129+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
1130+
}
1131+
11021132
protected override IEnumerable<DiagnosticAnalyzer> GetCSharpDiagnosticAnalyzers()
11031133
{
11041134
yield return new SA1115ParameterMustFollowComma();

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1114ParameterListMustFollowDeclaration.cs

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
namespace StyleCop.Analyzers.ReadabilityRules
55
{
6+
using System;
67
using System.Collections.Immutable;
8+
using System.Linq;
79
using Microsoft.CodeAnalysis;
810
using Microsoft.CodeAnalysis.CSharp;
911
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -52,17 +54,9 @@ internal class SA1114ParameterListMustFollowDeclaration : DiagnosticAnalyzer
5254
private static readonly DiagnosticDescriptor Descriptor =
5355
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.ReadabilityRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
5456

55-
private static readonly ImmutableArray<DiagnosticDescriptor> SupportedDiagnosticsValue =
56-
ImmutableArray.Create(Descriptor);
57-
5857
/// <inheritdoc/>
59-
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
60-
{
61-
get
62-
{
63-
return SupportedDiagnosticsValue;
64-
}
65-
}
58+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
59+
ImmutableArray.Create(Descriptor);
6660

6761
/// <inheritdoc/>
6862
public override void Initialize(AnalysisContext context)
@@ -72,9 +66,8 @@ public override void Initialize(AnalysisContext context)
7266

7367
private static void HandleCompilationStart(CompilationStartAnalysisContext context)
7468
{
75-
context.RegisterSyntaxNodeActionHonorExclusions(HandleMethodDeclaration, SyntaxKind.MethodDeclaration);
69+
context.RegisterSyntaxNodeActionHonorExclusions(HandleBaseMethodDeclaration, SyntaxKind.MethodDeclaration, SyntaxKind.ConstructorDeclaration, SyntaxKind.OperatorDeclaration);
7670
context.RegisterSyntaxNodeActionHonorExclusions(HandleMethodInvocation, SyntaxKind.InvocationExpression);
77-
context.RegisterSyntaxNodeActionHonorExclusions(HandleConstructorDeclaration, SyntaxKind.ConstructorDeclaration);
7871
context.RegisterSyntaxNodeActionHonorExclusions(HandleObjectCreation, SyntaxKind.ObjectCreationExpression);
7972
context.RegisterSyntaxNodeActionHonorExclusions(HandleIndexerDeclaration, SyntaxKind.IndexerDeclaration);
8073
context.RegisterSyntaxNodeActionHonorExclusions(HandleArrayCreation, SyntaxKind.ArrayCreationExpression);
@@ -85,13 +78,6 @@ private static void HandleCompilationStart(CompilationStartAnalysisContext conte
8578
context.RegisterSyntaxNodeActionHonorExclusions(HandleAnonymousMethod, SyntaxKind.AnonymousMethodExpression);
8679
context.RegisterSyntaxNodeActionHonorExclusions(HandleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression);
8780
context.RegisterSyntaxNodeActionHonorExclusions(HandleConversionOperatorDeclaration, SyntaxKind.ConversionOperatorDeclaration);
88-
context.RegisterSyntaxNodeActionHonorExclusions(HandleOperatorDeclaration, SyntaxKind.OperatorDeclaration);
89-
}
90-
91-
private static void HandleOperatorDeclaration(SyntaxNodeAnalysisContext context)
92-
{
93-
var operatorDeclaration = (OperatorDeclarationSyntax)context.Node;
94-
AnalyzeParametersList(context, operatorDeclaration.ParameterList);
9581
}
9682

9783
private static void HandleConversionOperatorDeclaration(SyntaxNodeAnalysisContext context)
@@ -163,21 +149,15 @@ private static void HandleObjectCreation(SyntaxNodeAnalysisContext context)
163149
}
164150
}
165151

166-
private static void HandleConstructorDeclaration(SyntaxNodeAnalysisContext context)
167-
{
168-
var constructorDeclaration = (ConstructorDeclarationSyntax)context.Node;
169-
AnalyzeParametersList(context, constructorDeclaration.ParameterList);
170-
}
171-
172152
private static void HandleMethodInvocation(SyntaxNodeAnalysisContext context)
173153
{
174154
var invocationExpression = (InvocationExpressionSyntax)context.Node;
175155
AnalyzeArgumentList(context, invocationExpression.ArgumentList);
176156
}
177157

178-
private static void HandleMethodDeclaration(SyntaxNodeAnalysisContext context)
158+
private static void HandleBaseMethodDeclaration(SyntaxNodeAnalysisContext context)
179159
{
180-
var methodDeclaration = (MethodDeclarationSyntax)context.Node;
160+
var methodDeclaration = (BaseMethodDeclarationSyntax)context.Node;
181161

182162
AnalyzeParametersList(context, methodDeclaration.ParameterList);
183163
}
@@ -399,24 +379,40 @@ private static void AnalyzeParametersList(SyntaxNodeAnalysisContext context, Par
399379
}
400380

401381
var firstParameter = parameterListSyntax.Parameters[0];
382+
int firstParameterLine;
402383

403-
var firstParameterLineSpan = firstParameter.GetLineSpan();
404-
if (!firstParameterLineSpan.IsValid)
384+
if (firstParameter.HasLeadingTrivia && firstParameter.GetLeadingTrivia().All(trivia => IsValidTrivia(trivia)))
405385
{
406-
return;
386+
firstParameterLine = firstParameter.SyntaxTree.GetLineSpan(firstParameter.FullSpan).StartLinePosition.Line;
407387
}
408-
409-
var openParenLineSpan = parameterListSyntax.OpenParenToken.GetLineSpan();
410-
if (!openParenLineSpan.IsValid)
388+
else
411389
{
412-
return;
390+
firstParameterLine = firstParameter.GetLineSpan().StartLinePosition.Line;
413391
}
414392

415-
if (openParenLineSpan.EndLinePosition.Line != firstParameterLineSpan.StartLinePosition.Line &&
416-
openParenLineSpan.EndLinePosition.Line != (firstParameterLineSpan.StartLinePosition.Line - 1))
393+
var parenLine = parameterListSyntax.OpenParenToken.GetLineSpan().EndLinePosition.Line;
394+
395+
if ((firstParameterLine - parenLine) > 1)
417396
{
418397
context.ReportDiagnostic(Diagnostic.Create(Descriptor, firstParameter.GetLocation()));
419398
}
420399
}
400+
401+
private static bool IsValidTrivia(SyntaxTrivia trivia)
402+
{
403+
switch (trivia.Kind())
404+
{
405+
case SyntaxKind.IfDirectiveTrivia:
406+
case SyntaxKind.ElseDirectiveTrivia:
407+
case SyntaxKind.ElifDirectiveTrivia:
408+
case SyntaxKind.EndIfDirectiveTrivia:
409+
case SyntaxKind.DisabledTextTrivia:
410+
case SyntaxKind.WhitespaceTrivia:
411+
return true;
412+
413+
default:
414+
return false;
415+
}
416+
}
421417
}
422418
}

StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1115ParameterMustFollowComma.cs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
namespace StyleCop.Analyzers.ReadabilityRules
55
{
66
using System.Collections.Immutable;
7+
using System.Linq;
78
using Microsoft.CodeAnalysis;
89
using Microsoft.CodeAnalysis.CSharp;
910
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -53,17 +54,9 @@ internal class SA1115ParameterMustFollowComma : DiagnosticAnalyzer
5354
private static readonly DiagnosticDescriptor Descriptor =
5455
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.ReadabilityRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
5556

56-
private static readonly ImmutableArray<DiagnosticDescriptor> SupportedDiagnosticsValue =
57-
ImmutableArray.Create(Descriptor);
58-
5957
/// <inheritdoc/>
60-
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
61-
{
62-
get
63-
{
64-
return SupportedDiagnosticsValue;
65-
}
66-
}
58+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
59+
ImmutableArray.Create(Descriptor);
6760

6861
/// <inheritdoc/>
6962
public override void Initialize(AnalysisContext context)
@@ -277,18 +270,44 @@ private static void AnalyzeParameterList(SyntaxNodeAnalysisContext context, Base
277270
return;
278271
}
279272

280-
var previousLine = parameterListSyntax.Parameters[0].GetLineSpan().EndLinePosition.Line;
273+
var previousParameterLine = parameterListSyntax.Parameters[0].GetLineSpan().EndLinePosition.Line;
281274
for (int i = 1; i < parameterListSyntax.Parameters.Count; i++)
282275
{
283276
var currentParameter = parameterListSyntax.Parameters[i];
284-
var lineSpan = currentParameter.GetLineSpan();
285-
var currentLine = lineSpan.StartLinePosition.Line;
286-
if (currentLine - previousLine > 1)
277+
int currentParameterLine;
278+
279+
if (currentParameter.HasLeadingTrivia && currentParameter.GetLeadingTrivia().All(trivia => IsValidTrivia(trivia)))
280+
{
281+
currentParameterLine = currentParameter.SyntaxTree.GetLineSpan(currentParameter.FullSpan).StartLinePosition.Line;
282+
}
283+
else
284+
{
285+
currentParameterLine = currentParameter.GetLineSpan().StartLinePosition.Line;
286+
}
287+
288+
if (currentParameterLine - previousParameterLine > 1)
287289
{
288290
context.ReportDiagnostic(Diagnostic.Create(Descriptor, currentParameter.GetLocation()));
289291
}
290292

291-
previousLine = lineSpan.EndLinePosition.Line;
293+
previousParameterLine = currentParameterLine;
294+
}
295+
}
296+
297+
private static bool IsValidTrivia(SyntaxTrivia trivia)
298+
{
299+
switch (trivia.Kind())
300+
{
301+
case SyntaxKind.IfDirectiveTrivia:
302+
case SyntaxKind.ElseDirectiveTrivia:
303+
case SyntaxKind.ElifDirectiveTrivia:
304+
case SyntaxKind.EndIfDirectiveTrivia:
305+
case SyntaxKind.DisabledTextTrivia:
306+
case SyntaxKind.WhitespaceTrivia:
307+
return true;
308+
309+
default:
310+
return false;
292311
}
293312
}
294313
}

0 commit comments

Comments
 (0)