Skip to content

Commit 1555129

Browse files
committed
Update SA1003 and SA1019 to handle member access after unary postfix operator
Fixes #2471
1 parent 000b45d commit 1555129

3 files changed

Lines changed: 214 additions & 5 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1003UnitTests.cs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,114 @@ public void Bar()
194194
await this.VerifyCSharpFixAsync(testCode, fixedTestCode, numberOfFixAllIterations: 2, cancellationToken: CancellationToken.None).ConfigureAwait(false);
195195
}
196196

197+
[Fact]
198+
[WorkItem(2471, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2471")]
199+
public async Task TestUnaryMemberAccessAsync()
200+
{
201+
var testCode = @"public class ClassName
202+
{
203+
public unsafe void MethodName()
204+
{
205+
int? x = 0;
206+
int* y = null;
207+
208+
x -- .ToString();
209+
x --.ToString();
210+
x-- .ToString();
211+
212+
x ++ .ToString();
213+
x ++.ToString();
214+
x++ .ToString();
215+
216+
x -- ?.ToString();
217+
x --?.ToString();
218+
x-- ?.ToString();
219+
220+
x ++ ?.ToString();
221+
x ++?.ToString();
222+
x++ ?.ToString();
223+
224+
y -- ->ToString();
225+
y --->ToString();
226+
y-- ->ToString();
227+
228+
y ++ ->ToString();
229+
y ++->ToString();
230+
y++ ->ToString();
231+
}
232+
}
233+
";
234+
var fixedTestCode = @"public class ClassName
235+
{
236+
public unsafe void MethodName()
237+
{
238+
int? x = 0;
239+
int* y = null;
240+
241+
x--.ToString();
242+
x--.ToString();
243+
x--.ToString();
244+
245+
x++.ToString();
246+
x++.ToString();
247+
x++.ToString();
248+
249+
x--?.ToString();
250+
x--?.ToString();
251+
x--?.ToString();
252+
253+
x++?.ToString();
254+
x++?.ToString();
255+
x++?.ToString();
256+
257+
y--->ToString();
258+
y--->ToString();
259+
y--->ToString();
260+
261+
y++->ToString();
262+
y++->ToString();
263+
y++->ToString();
264+
}
265+
}
266+
";
267+
DiagnosticResult[] expected =
268+
{
269+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(8, 11).WithArguments("--"),
270+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(8, 11).WithArguments("--"),
271+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(9, 11).WithArguments("--"),
272+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(10, 10).WithArguments("--"),
273+
274+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(12, 11).WithArguments("++"),
275+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(12, 11).WithArguments("++"),
276+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(13, 11).WithArguments("++"),
277+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(14, 10).WithArguments("++"),
278+
279+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(16, 11).WithArguments("--"),
280+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(16, 11).WithArguments("--"),
281+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(17, 11).WithArguments("--"),
282+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(18, 10).WithArguments("--"),
283+
284+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(20, 11).WithArguments("++"),
285+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(20, 11).WithArguments("++"),
286+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(21, 11).WithArguments("++"),
287+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(22, 10).WithArguments("++"),
288+
289+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(24, 11).WithArguments("--"),
290+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(24, 11).WithArguments("--"),
291+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(25, 11).WithArguments("--"),
292+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(26, 10).WithArguments("--"),
293+
294+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(28, 11).WithArguments("++"),
295+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(28, 11).WithArguments("++"),
296+
this.CSharpDiagnostic(DescriptorNotPrecededByWhitespace).WithLocation(29, 11).WithArguments("++"),
297+
this.CSharpDiagnostic(DescriptorNotFollowedByWhitespace).WithLocation(30, 10).WithArguments("++"),
298+
};
299+
300+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
301+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
302+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
303+
}
304+
197305
/// <summary>
198306
/// Verifies that valid binary expressions do not produce diagnostics.
199307
/// </summary>

StyleCop.Analyzers/StyleCop.Analyzers.Test/SpacingRules/SA1019UnitTests.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,88 @@ public void TestMethod()
183183
await this.VerifyCSharpDiagnosticAsync(template, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
184184
}
185185

186+
[Fact]
187+
[WorkItem(2471, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2471")]
188+
public async Task TestUnaryMemberAccessAsync()
189+
{
190+
var testCode = @"public class ClassName
191+
{
192+
public unsafe void MethodName()
193+
{
194+
int? x = 0;
195+
int* y = null;
196+
197+
x-- . ToString();
198+
x-- .ToString();
199+
x--. ToString();
200+
201+
x++ . ToString();
202+
x++ .ToString();
203+
x++. ToString();
204+
205+
x-- ?. ToString();
206+
x-- ?.ToString();
207+
x--?. ToString();
208+
209+
x++ ?. ToString();
210+
x++ ?.ToString();
211+
x++?. ToString();
212+
}
213+
}
214+
";
215+
var fixedTestCode = @"public class ClassName
216+
{
217+
public unsafe void MethodName()
218+
{
219+
int? x = 0;
220+
int* y = null;
221+
222+
x--.ToString();
223+
x--.ToString();
224+
x--.ToString();
225+
226+
x++.ToString();
227+
x++.ToString();
228+
x++.ToString();
229+
230+
x--?.ToString();
231+
x--?.ToString();
232+
x--?.ToString();
233+
234+
x++?.ToString();
235+
x++?.ToString();
236+
x++?.ToString();
237+
}
238+
}
239+
";
240+
DiagnosticResult[] expected =
241+
{
242+
this.CSharpDiagnostic().WithLocation(8, 13).WithArguments(".", "preceded"),
243+
this.CSharpDiagnostic().WithLocation(8, 13).WithArguments(".", "followed"),
244+
this.CSharpDiagnostic().WithLocation(9, 13).WithArguments(".", "preceded"),
245+
this.CSharpDiagnostic().WithLocation(10, 12).WithArguments(".", "followed"),
246+
247+
this.CSharpDiagnostic().WithLocation(12, 13).WithArguments(".", "preceded"),
248+
this.CSharpDiagnostic().WithLocation(12, 13).WithArguments(".", "followed"),
249+
this.CSharpDiagnostic().WithLocation(13, 13).WithArguments(".", "preceded"),
250+
this.CSharpDiagnostic().WithLocation(14, 12).WithArguments(".", "followed"),
251+
252+
this.CSharpDiagnostic().WithLocation(16, 13).WithArguments("?", "preceded"),
253+
this.CSharpDiagnostic().WithLocation(16, 14).WithArguments(".", "followed"),
254+
this.CSharpDiagnostic().WithLocation(17, 13).WithArguments("?", "preceded"),
255+
this.CSharpDiagnostic().WithLocation(18, 13).WithArguments(".", "followed"),
256+
257+
this.CSharpDiagnostic().WithLocation(20, 13).WithArguments("?", "preceded"),
258+
this.CSharpDiagnostic().WithLocation(20, 14).WithArguments(".", "followed"),
259+
this.CSharpDiagnostic().WithLocation(21, 13).WithArguments("?", "preceded"),
260+
this.CSharpDiagnostic().WithLocation(22, 13).WithArguments(".", "followed"),
261+
};
262+
263+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
264+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
265+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
266+
}
267+
186268
/// <summary>
187269
/// Gets the C# analyzers being tested
188270
/// </summary>

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,30 @@ private static void HandlePostfixUnaryExpression(SyntaxNodeAnalysisContext conte
292292
var unaryExpression = (PostfixUnaryExpressionSyntax)context.Node;
293293
var followingToken = unaryExpression.OperatorToken.GetNextToken();
294294

295-
var mustHaveTrailingWhitespace = !followingToken.IsKind(SyntaxKind.CloseParenToken)
296-
&& !followingToken.IsKind(SyntaxKind.CloseBracketToken)
297-
&& !followingToken.IsKind(SyntaxKind.SemicolonToken)
298-
&& !followingToken.IsKind(SyntaxKind.CommaToken)
299-
&& !(followingToken.IsKind(SyntaxKind.CloseBraceToken) && (followingToken.Parent is InterpolationSyntax));
295+
bool mustHaveTrailingWhitespace;
296+
switch (followingToken.Kind())
297+
{
298+
case SyntaxKind.CloseParenToken:
299+
case SyntaxKind.CloseBracketToken:
300+
case SyntaxKind.SemicolonToken:
301+
case SyntaxKind.CommaToken:
302+
case SyntaxKind.DotToken:
303+
case SyntaxKind.MinusGreaterThanToken:
304+
mustHaveTrailingWhitespace = false;
305+
break;
306+
307+
case SyntaxKind.QuestionToken:
308+
mustHaveTrailingWhitespace = !(followingToken.Parent is ConditionalAccessExpressionSyntax);
309+
break;
310+
311+
case SyntaxKind.CloseBraceToken:
312+
mustHaveTrailingWhitespace = !(followingToken.Parent is InterpolationSyntax);
313+
break;
314+
315+
default:
316+
mustHaveTrailingWhitespace = true;
317+
break;
318+
}
300319

301320
// If the next token is a close brace token we are in an anonymous object creation or an initialization.
302321
// Then we allow a new line

0 commit comments

Comments
 (0)