Skip to content

Commit 627c705

Browse files
authored
Merge pull request #3839 from MattFromRVA/SA1001_Change
Skip Warnings for Commas After Conditional Directives
2 parents ed98563 + ee242c4 commit 627c705

File tree

3 files changed

+154
-1
lines changed

3 files changed

+154
-1
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1001UnitTests.cs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,124 @@ public void TestMethod()
349349
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
350350
}
351351

352+
[Fact]
353+
[WorkItem(3816, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3816")]
354+
public async Task TestCommaFollowingPreprocessorDirectiveAsync()
355+
{
356+
var testCode = @"
357+
interface IFormattable {}
358+
interface ISpanFormattable {}
359+
360+
partial struct Money : IFormattable
361+
#if true
362+
, ISpanFormattable
363+
#endif
364+
{
365+
}
366+
";
367+
368+
var expected = DiagnosticResult.EmptyDiagnosticResults;
369+
370+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
371+
}
372+
373+
[Fact]
374+
[WorkItem(3816, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3816")]
375+
public async Task TestCommaFollowingElifDirectiveAsync()
376+
{
377+
var testCode = @"
378+
interface IFormattable {}
379+
interface ISpanFormattable {}
380+
381+
partial struct Money : IFormattable
382+
#if false
383+
#elif true
384+
, ISpanFormattable
385+
#endif
386+
{
387+
}
388+
";
389+
390+
var expected = DiagnosticResult.EmptyDiagnosticResults;
391+
392+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
393+
}
394+
395+
[Fact]
396+
[WorkItem(3816, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3816")]
397+
public async Task TestCommaFollowingElseDirectiveAsync()
398+
{
399+
var testCode = @"
400+
interface IFormattable {}
401+
interface ISpanFormattable {}
402+
403+
partial struct Money : IFormattable
404+
#if false
405+
#else
406+
, ISpanFormattable
407+
#endif
408+
{
409+
}
410+
";
411+
412+
var expected = DiagnosticResult.EmptyDiagnosticResults;
413+
414+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
415+
}
416+
417+
[Fact]
418+
[WorkItem(3816, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3816")]
419+
public async Task TestCommaFollowingEndIfDirectiveAsync()
420+
{
421+
var testCode = @"
422+
interface IFormattable {}
423+
interface ISpanFormattable {}
424+
425+
partial struct Money : IFormattable
426+
#if false
427+
#endif
428+
, ISpanFormattable
429+
{
430+
}
431+
";
432+
433+
var expected = DiagnosticResult.EmptyDiagnosticResults;
434+
435+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
436+
}
437+
438+
[Fact]
439+
[WorkItem(3816, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3816")]
440+
public async Task TestCommaNotFollowingDirectiveAsync()
441+
{
442+
var testCode = @"
443+
interface IFormattable {}
444+
interface ISpanFormattable {}
445+
446+
partial struct Money : IFormattable
447+
{|#0:,|} ISpanFormattable
448+
{
449+
}
450+
";
451+
452+
var fixedCode = @"
453+
interface IFormattable {}
454+
interface ISpanFormattable {}
455+
456+
partial struct Money : IFormattable,
457+
ISpanFormattable
458+
{
459+
}
460+
";
461+
462+
var expected = new[]
463+
{
464+
Diagnostic().WithLocation(0).WithArguments(" not", "preceded"),
465+
};
466+
467+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
468+
}
469+
352470
private Task TestCommaInStatementOrDeclAsync(string originalStatement, DiagnosticResult expected, string fixedStatement)
353471
{
354472
return this.TestCommaInStatementOrDeclAsync(originalStatement, new[] { expected }, fixedStatement);

StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1001CommasMustBeSpacedCorrectly.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace StyleCop.Analyzers.SpacingRules
77
{
88
using System;
99
using System.Collections.Immutable;
10+
using System.Linq;
1011
using Microsoft.CodeAnalysis;
1112
using Microsoft.CodeAnalysis.CSharp;
1213
using Microsoft.CodeAnalysis.Diagnostics;
@@ -76,6 +77,9 @@ private static void HandleCommaToken(SyntaxTreeAnalysisContext context, SyntaxTo
7677
return;
7778
}
7879

80+
// Check if the comma follows a conditional preprocessor directive
81+
bool followsDirective = token.HasLeadingTrivia && IsPrecededByDirectiveTrivia(token.LeadingTrivia);
82+
7983
// check for a following space
8084
bool missingFollowingSpace = true;
8185

@@ -102,7 +106,7 @@ private static void HandleCommaToken(SyntaxTreeAnalysisContext context, SyntaxTo
102106
}
103107
}
104108

105-
if (token.IsFirstInLine() || token.IsPrecededByWhitespace(context.CancellationToken))
109+
if (!followsDirective && (token.IsFirstInLine() || token.IsPrecededByWhitespace(context.CancellationToken)))
106110
{
107111
// comma should{ not} be {preceded} by whitespace
108112
context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.RemovePrecedingPreserveLayout, " not", "preceded"));
@@ -120,5 +124,30 @@ private static void HandleCommaToken(SyntaxTreeAnalysisContext context, SyntaxTo
120124
context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.RemoveFollowing, " not", "followed"));
121125
}
122126
}
127+
128+
private static bool IsPrecededByDirectiveTrivia(SyntaxTriviaList triviaList)
129+
{
130+
int triviaIndex = triviaList.Count - 1;
131+
while (triviaIndex >= 0)
132+
{
133+
switch (triviaList[triviaIndex].Kind())
134+
{
135+
case SyntaxKind.WhitespaceTrivia:
136+
triviaIndex--;
137+
break;
138+
139+
case SyntaxKind.IfDirectiveTrivia:
140+
case SyntaxKind.ElifDirectiveTrivia:
141+
case SyntaxKind.ElseDirectiveTrivia:
142+
case SyntaxKind.EndIfDirectiveTrivia:
143+
return true;
144+
145+
default:
146+
return false;
147+
}
148+
}
149+
150+
return false;
151+
}
123152
}
124153
}

documentation/SA1001.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ A comma should be followed by a single space, except in the following cases.
2828
* A comma may appear at the end of a line
2929
* A comma should not be followed by a space when used in an open generic type in a `typeof` expression
3030
* A comma is part of a string interpolation alignment component. For example:`$"{x,3}"`
31+
* A comma follows a conditional preprocessor directive (#if, #elif, #else, #endif). For example:
32+
```csharp
33+
partial struct Money : IFormattable
34+
#if !NETSTANDARD
35+
, ISpanFormattable
36+
#endif
3137

3238
A comma should never be preceded by a space or appear as the first token on a line.
3339

0 commit comments

Comments
 (0)