Skip to content

Commit 6e957c7

Browse files
authored
Merge pull request #2480 from sharwell/postfix-operators
Support postfix operator followed by member access
2 parents aff686a + b6a1179 commit 6e957c7

4 files changed

Lines changed: 244 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: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,114 @@ 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+
y-- -> ToString();
214+
y-- ->ToString();
215+
y---> ToString();
216+
217+
y++ -> ToString();
218+
y++ ->ToString();
219+
y++-> ToString();
220+
}
221+
}
222+
";
223+
var fixedTestCode = @"public class ClassName
224+
{
225+
public unsafe void MethodName()
226+
{
227+
int? x = 0;
228+
int* y = null;
229+
230+
x--.ToString();
231+
x--.ToString();
232+
x--.ToString();
233+
234+
x++.ToString();
235+
x++.ToString();
236+
x++.ToString();
237+
238+
x--?.ToString();
239+
x--?.ToString();
240+
x--?.ToString();
241+
242+
x++?.ToString();
243+
x++?.ToString();
244+
x++?.ToString();
245+
246+
y--->ToString();
247+
y--->ToString();
248+
y--->ToString();
249+
250+
y++->ToString();
251+
y++->ToString();
252+
y++->ToString();
253+
}
254+
}
255+
";
256+
DiagnosticResult[] expected =
257+
{
258+
this.CSharpDiagnostic().WithLocation(8, 13).WithArguments(".", "preceded"),
259+
this.CSharpDiagnostic().WithLocation(8, 13).WithArguments(".", "followed"),
260+
this.CSharpDiagnostic().WithLocation(9, 13).WithArguments(".", "preceded"),
261+
this.CSharpDiagnostic().WithLocation(10, 12).WithArguments(".", "followed"),
262+
263+
this.CSharpDiagnostic().WithLocation(12, 13).WithArguments(".", "preceded"),
264+
this.CSharpDiagnostic().WithLocation(12, 13).WithArguments(".", "followed"),
265+
this.CSharpDiagnostic().WithLocation(13, 13).WithArguments(".", "preceded"),
266+
this.CSharpDiagnostic().WithLocation(14, 12).WithArguments(".", "followed"),
267+
268+
this.CSharpDiagnostic().WithLocation(16, 13).WithArguments("?", "preceded"),
269+
this.CSharpDiagnostic().WithLocation(16, 14).WithArguments(".", "followed"),
270+
this.CSharpDiagnostic().WithLocation(17, 13).WithArguments("?", "preceded"),
271+
this.CSharpDiagnostic().WithLocation(18, 13).WithArguments(".", "followed"),
272+
273+
this.CSharpDiagnostic().WithLocation(20, 13).WithArguments("?", "preceded"),
274+
this.CSharpDiagnostic().WithLocation(20, 14).WithArguments(".", "followed"),
275+
this.CSharpDiagnostic().WithLocation(21, 13).WithArguments("?", "preceded"),
276+
this.CSharpDiagnostic().WithLocation(22, 13).WithArguments(".", "followed"),
277+
278+
this.CSharpDiagnostic().WithLocation(24, 13).WithArguments("->", "preceded"),
279+
this.CSharpDiagnostic().WithLocation(24, 13).WithArguments("->", "followed"),
280+
this.CSharpDiagnostic().WithLocation(25, 13).WithArguments("->", "preceded"),
281+
this.CSharpDiagnostic().WithLocation(26, 12).WithArguments("->", "followed"),
282+
283+
this.CSharpDiagnostic().WithLocation(28, 13).WithArguments("->", "preceded"),
284+
this.CSharpDiagnostic().WithLocation(28, 13).WithArguments("->", "followed"),
285+
this.CSharpDiagnostic().WithLocation(29, 13).WithArguments("->", "preceded"),
286+
this.CSharpDiagnostic().WithLocation(30, 12).WithArguments("->", "followed"),
287+
};
288+
289+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
290+
await this.VerifyCSharpDiagnosticAsync(fixedTestCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
291+
await this.VerifyCSharpFixAsync(testCode, fixedTestCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
292+
}
293+
186294
/// <summary>
187295
/// Gets the C# analyzers being tested
188296
/// </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

StyleCop.Analyzers/StyleCop.Analyzers/SpacingRules/SA1019MemberAccessSymbolsMustBeSpacedCorrectly.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
5959
HandleDotToken(context, token);
6060
break;
6161

62+
case SyntaxKind.MinusGreaterThanToken:
63+
HandleMemberAccessSymbol(context, token);
64+
break;
65+
6266
// This case handles the new ?. and ?[ operators
6367
case SyntaxKind.QuestionToken:
6468
HandleQuestionToken(context, token);

0 commit comments

Comments
 (0)