Skip to content

Commit 4c07be7

Browse files
committed
Update SA1003 for relational and logical patterns
1 parent 3371d96 commit 4c07be7

File tree

3 files changed

+76
-5
lines changed

3 files changed

+76
-5
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/SpacingRules/SA1003CSharp9UnitTests.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,62 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp9.SpacingRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp8.SpacingRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.SpacingRules.SA1003SymbolsMustBeSpacedCorrectly;
12+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
13+
StyleCop.Analyzers.SpacingRules.SA1003SymbolsMustBeSpacedCorrectly,
14+
StyleCop.Analyzers.SpacingRules.SA1003CodeFixProvider>;
715

816
public partial class SA1003CSharp9UnitTests : SA1003CSharp8UnitTests
917
{
18+
[Fact]
19+
[WorkItem(3968, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3968")]
20+
public async Task TestRelationalPatternsAreValidatedAsync()
21+
{
22+
const string testCode = @"
23+
class C
24+
{
25+
void M(int value)
26+
{
27+
_ = value is {|#0:>|}5;
28+
_ = value is{|#1:<|} 5;
29+
_ = value is ( < 5); // Validated by SA1008
30+
_ = value is (< 5);
31+
_ = value is {|#2:<=|}5;
32+
_ = value is {|#3:>=|}5;
33+
_ = value is {|#4:>|}
34+
5;
35+
}
36+
}";
37+
38+
const string fixedCode = @"
39+
class C
40+
{
41+
void M(int value)
42+
{
43+
_ = value is > 5;
44+
_ = value is < 5;
45+
_ = value is ( < 5); // Validated by SA1008
46+
_ = value is (< 5);
47+
_ = value is <= 5;
48+
_ = value is >= 5;
49+
_ = value is > 5;
50+
}
51+
}";
52+
53+
DiagnosticResult[] expected =
54+
{
55+
Diagnostic(DescriptorFollowedByWhitespace).WithLocation(0).WithArguments(">"),
56+
Diagnostic(DescriptorPrecededByWhitespace).WithLocation(1).WithArguments("<"),
57+
Diagnostic(DescriptorFollowedByWhitespace).WithLocation(2).WithArguments("<="),
58+
Diagnostic(DescriptorFollowedByWhitespace).WithLocation(3).WithArguments(">="),
59+
Diagnostic(DescriptorNotAtEndOfLine).WithLocation(4).WithArguments(">"),
60+
};
61+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
62+
}
1063
}
1164
}

StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1003SymbolsMustBeSpacedCorrectly.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ internal class SA1003SymbolsMustBeSpacedCorrectly : DiagnosticAnalyzer
140140
private static readonly Action<SyntaxNodeAnalysisContext> LambdaExpressionAction = HandleLambdaExpression;
141141
private static readonly Action<SyntaxNodeAnalysisContext> ArrowExpressionClauseAction = HandleArrowExpressionClause;
142142
private static readonly Action<SyntaxNodeAnalysisContext> RangeExpressionAction = HandleRangeExpression;
143+
private static readonly Action<SyntaxNodeAnalysisContext> RelationalPatternAction = HandleRelationalPattern;
143144
private static readonly Action<SyntaxNodeAnalysisContext> SwitchExpressionArmAction = HandleSwitchExpressionArm;
144145

145146
/// <summary>
@@ -218,6 +219,7 @@ public override void Initialize(AnalysisContext context)
218219
context.RegisterSyntaxNodeAction(LambdaExpressionAction, SyntaxKinds.LambdaExpression);
219220
context.RegisterSyntaxNodeAction(ArrowExpressionClauseAction, SyntaxKind.ArrowExpressionClause);
220221
context.RegisterSyntaxNodeAction(RangeExpressionAction, SyntaxKindEx.RangeExpression);
222+
context.RegisterSyntaxNodeAction(RelationalPatternAction, SyntaxKindEx.RelationalPattern);
221223
context.RegisterSyntaxNodeAction(SwitchExpressionArmAction, SyntaxKindEx.SwitchExpressionArm);
222224
}
223225

@@ -256,11 +258,6 @@ private static void HandleBinaryExpression(SyntaxNodeAnalysisContext context)
256258

257259
private static void HandleRangeExpression(SyntaxNodeAnalysisContext context)
258260
{
259-
if (!RangeExpressionSyntaxWrapper.IsInstance(context.Node))
260-
{
261-
return;
262-
}
263-
264261
var rangeExpression = (RangeExpressionSyntaxWrapper)context.Node;
265262
var hasLeftOperand = rangeExpression.LeftOperand != null;
266263
var hasRightOperand = rangeExpression.RightOperand != null;
@@ -346,6 +343,22 @@ private static void HandlePrefixUnaryExpression(SyntaxNodeAnalysisContext contex
346343
}
347344
}
348345

346+
private static void HandleRelationalPattern(SyntaxNodeAnalysisContext context)
347+
{
348+
var relationalPattern = (RelationalPatternSyntaxWrapper)context.Node;
349+
var operatorToken = relationalPattern.OperatorToken;
350+
var precedingToken = operatorToken.GetPreviousToken();
351+
352+
if (precedingToken.IsKind(SyntaxKind.OpenParenToken))
353+
{
354+
// Spacing next to the opening parenthesis is handled by SA1008; only enforce trailing whitespace here.
355+
CheckTokenTrailingWhitespace(context, operatorToken, allowAtEndOfLine: false, withTrailingWhitespace: true);
356+
return;
357+
}
358+
359+
CheckToken(context, operatorToken, withLeadingWhitespace: true, allowAtEndOfLine: false, withTrailingWhitespace: true);
360+
}
361+
349362
private static void HandlePostfixUnaryExpression(SyntaxNodeAnalysisContext context)
350363
{
351364
var unaryExpression = (PostfixUnaryExpressionSyntax)context.Node;

documentation/SA1003.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ rules apply: each arrow should have a single space on both sides.
3838
var description = value switch { 0 => "zero", _ => "nonzero" };
3939
```
4040

41+
Relational operators inside pattern matching expressions follow the same rules when they appear after keywords such as
42+
`is`. For example, in a relational pattern the `>` in `value is > 5` must be surrounded by spaces: `value is > 5`. When
43+
a relational pattern is wrapped in parentheses, it should still avoid spaces immediately after `(` or before `)`,
44+
consistent with the parenthesis rules described in SA1008.
45+
4146
In contrast, unary operators should be preceded by a single space, but should never be followed by any space. For example:
4247

4348
```csharp

0 commit comments

Comments
 (0)