Skip to content

Commit 9fc5569

Browse files
committed
Merge pull request #1864 from sharwell/fix-1856
Update SA1312 to check additional local variable declarations
2 parents 40131df + 16e2add commit 9fc5569

2 files changed

Lines changed: 327 additions & 11 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1312UnitTests.cs

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,268 @@ public void MethodName()
177177
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
178178
}
179179

180+
[Fact]
181+
public async Task TestVariableInCatchDeclarationAsync()
182+
{
183+
var testCode = @"
184+
using System;
185+
public class TypeName
186+
{
187+
public void MethodName()
188+
{
189+
try
190+
{
191+
}
192+
catch (Exception Ex)
193+
{
194+
}
195+
}
196+
}";
197+
var fixedCode = @"
198+
using System;
199+
public class TypeName
200+
{
201+
public void MethodName()
202+
{
203+
try
204+
{
205+
}
206+
catch (Exception ex)
207+
{
208+
}
209+
}
210+
}";
211+
212+
DiagnosticResult[] expected =
213+
{
214+
this.CSharpDiagnostic().WithArguments("Ex").WithLocation(10, 26),
215+
};
216+
217+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
218+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
219+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
220+
}
221+
222+
[Fact]
223+
public async Task TestVariableInForEachStatementAsync()
224+
{
225+
var testCode = @"public class TypeName
226+
{
227+
public void MethodName()
228+
{
229+
foreach (var X in new int[0])
230+
{
231+
}
232+
}
233+
}";
234+
var fixedCode = @"public class TypeName
235+
{
236+
public void MethodName()
237+
{
238+
foreach (var x in new int[0])
239+
{
240+
}
241+
}
242+
}";
243+
244+
DiagnosticResult[] expected =
245+
{
246+
this.CSharpDiagnostic().WithArguments("X").WithLocation(5, 22),
247+
};
248+
249+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
250+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
251+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
252+
}
253+
254+
[Fact]
255+
public async Task TestVariableInFromClauseAsync()
256+
{
257+
var testCode = @"
258+
using System.Linq;
259+
public class TypeName
260+
{
261+
public void MethodName()
262+
{
263+
var result =
264+
from X in new int[0]
265+
select X;
266+
}
267+
}";
268+
var fixedCode = @"
269+
using System.Linq;
270+
public class TypeName
271+
{
272+
public void MethodName()
273+
{
274+
var result =
275+
from x in new int[0]
276+
select x;
277+
}
278+
}";
279+
280+
DiagnosticResult[] expected =
281+
{
282+
this.CSharpDiagnostic().WithArguments("X").WithLocation(8, 18),
283+
};
284+
285+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
286+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
287+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
288+
}
289+
290+
[Fact]
291+
public async Task TestVariableInQueryContinuationAsync()
292+
{
293+
var testCode = @"
294+
using System.Linq;
295+
public class TypeName
296+
{
297+
public void MethodName()
298+
{
299+
var result =
300+
from x in new int[0]
301+
select x into Y
302+
select Y;
303+
}
304+
}";
305+
var fixedCode = @"
306+
using System.Linq;
307+
public class TypeName
308+
{
309+
public void MethodName()
310+
{
311+
var result =
312+
from x in new int[0]
313+
select x into y
314+
select y;
315+
}
316+
}";
317+
318+
DiagnosticResult[] expected =
319+
{
320+
this.CSharpDiagnostic().WithArguments("Y").WithLocation(9, 27),
321+
};
322+
323+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
324+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
325+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
326+
}
327+
328+
[Fact]
329+
public async Task TestVariableInLetClauseAsync()
330+
{
331+
var testCode = @"
332+
using System.Linq;
333+
public class TypeName
334+
{
335+
public void MethodName()
336+
{
337+
var result =
338+
from x in new int[0]
339+
let Y = x
340+
select Y;
341+
}
342+
}";
343+
var fixedCode = @"
344+
using System.Linq;
345+
public class TypeName
346+
{
347+
public void MethodName()
348+
{
349+
var result =
350+
from x in new int[0]
351+
let y = x
352+
select y;
353+
}
354+
}";
355+
356+
DiagnosticResult[] expected =
357+
{
358+
this.CSharpDiagnostic().WithArguments("Y").WithLocation(9, 17),
359+
};
360+
361+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
362+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
363+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
364+
}
365+
366+
[Fact]
367+
public async Task TestVariableInJoinClauseAsync()
368+
{
369+
var testCode = @"
370+
using System.Linq;
371+
public class TypeName
372+
{
373+
public void MethodName()
374+
{
375+
var result =
376+
from x in new int[0]
377+
join Y in new int[0] on x equals Y
378+
select x;
379+
}
380+
}";
381+
var fixedCode = @"
382+
using System.Linq;
383+
public class TypeName
384+
{
385+
public void MethodName()
386+
{
387+
var result =
388+
from x in new int[0]
389+
join y in new int[0] on x equals y
390+
select x;
391+
}
392+
}";
393+
394+
DiagnosticResult[] expected =
395+
{
396+
this.CSharpDiagnostic().WithArguments("Y").WithLocation(9, 18),
397+
};
398+
399+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
400+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
401+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
402+
}
403+
404+
[Fact]
405+
public async Task TestVariableInJoinIntoClauseAsync()
406+
{
407+
var testCode = @"
408+
using System.Linq;
409+
public class TypeName
410+
{
411+
public void MethodName()
412+
{
413+
var result =
414+
from x in new int[0]
415+
join y in new int[0] on x equals y into Z
416+
select Z;
417+
}
418+
}";
419+
var fixedCode = @"
420+
using System.Linq;
421+
public class TypeName
422+
{
423+
public void MethodName()
424+
{
425+
var result =
426+
from x in new int[0]
427+
join y in new int[0] on x equals y into z
428+
select z;
429+
}
430+
}";
431+
432+
DiagnosticResult[] expected =
433+
{
434+
this.CSharpDiagnostic().WithArguments("Z").WithLocation(9, 53),
435+
};
436+
437+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
438+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
439+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
440+
}
441+
180442
[Fact]
181443
public async Task TestVariablePlacedInsideNativeMethodsClassAsync()
182444
{

StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1312VariableNamesMustBeginWithLowerCaseLetter.cs

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ internal class SA1312VariableNamesMustBeginWithLowerCaseLetter : DiagnosticAnaly
4040

4141
private static readonly Action<CompilationStartAnalysisContext> CompilationStartAction = HandleCompilationStart;
4242
private static readonly Action<SyntaxNodeAnalysisContext> VariableDeclarationAction = HandleVariableDeclaration;
43+
private static readonly Action<SyntaxNodeAnalysisContext> CatchDeclarationAction = HandleCatchDeclaration;
44+
private static readonly Action<SyntaxNodeAnalysisContext> QueryContinuationAction = HandleQueryContinuation;
45+
private static readonly Action<SyntaxNodeAnalysisContext> FromClauseAction = HandleFromClause;
46+
private static readonly Action<SyntaxNodeAnalysisContext> LetClauseAction = HandleLetClause;
47+
private static readonly Action<SyntaxNodeAnalysisContext> JoinClauseAction = HandleJoinClause;
48+
private static readonly Action<SyntaxNodeAnalysisContext> JoinIntoClauseAction = HandleJoinIntoClause;
49+
private static readonly Action<SyntaxNodeAnalysisContext> ForEachStatementAction = HandleForEachStatement;
4350

4451
/// <inheritdoc/>
4552
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
@@ -54,6 +61,13 @@ public override void Initialize(AnalysisContext context)
5461
private static void HandleCompilationStart(CompilationStartAnalysisContext context)
5562
{
5663
context.RegisterSyntaxNodeActionHonorExclusions(VariableDeclarationAction, SyntaxKind.VariableDeclaration);
64+
context.RegisterSyntaxNodeActionHonorExclusions(CatchDeclarationAction, SyntaxKind.CatchDeclaration);
65+
context.RegisterSyntaxNodeActionHonorExclusions(QueryContinuationAction, SyntaxKind.QueryContinuation);
66+
context.RegisterSyntaxNodeActionHonorExclusions(FromClauseAction, SyntaxKind.FromClause);
67+
context.RegisterSyntaxNodeActionHonorExclusions(LetClauseAction, SyntaxKind.LetClause);
68+
context.RegisterSyntaxNodeActionHonorExclusions(JoinClauseAction, SyntaxKind.JoinClause);
69+
context.RegisterSyntaxNodeActionHonorExclusions(JoinIntoClauseAction, SyntaxKind.JoinIntoClause);
70+
context.RegisterSyntaxNodeActionHonorExclusions(ForEachStatementAction, SyntaxKind.ForEachStatement);
5771
}
5872

5973
private static void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
@@ -86,20 +100,60 @@ private static void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
86100
}
87101

88102
var identifier = variableDeclarator.Identifier;
89-
if (identifier.IsMissing)
90-
{
91-
continue;
92-
}
103+
CheckIdentifier(context, identifier);
104+
}
105+
}
93106

94-
string name = identifier.ValueText;
95-
if (string.IsNullOrEmpty(name) || char.IsLower(name[0]))
96-
{
97-
continue;
98-
}
107+
private static void HandleCatchDeclaration(SyntaxNodeAnalysisContext context)
108+
{
109+
CheckIdentifier(context, ((CatchDeclarationSyntax)context.Node).Identifier);
110+
}
111+
112+
private static void HandleQueryContinuation(SyntaxNodeAnalysisContext context)
113+
{
114+
CheckIdentifier(context, ((QueryContinuationSyntax)context.Node).Identifier);
115+
}
116+
117+
private static void HandleFromClause(SyntaxNodeAnalysisContext context)
118+
{
119+
CheckIdentifier(context, ((FromClauseSyntax)context.Node).Identifier);
120+
}
121+
122+
private static void HandleLetClause(SyntaxNodeAnalysisContext context)
123+
{
124+
CheckIdentifier(context, ((LetClauseSyntax)context.Node).Identifier);
125+
}
126+
127+
private static void HandleJoinClause(SyntaxNodeAnalysisContext context)
128+
{
129+
CheckIdentifier(context, ((JoinClauseSyntax)context.Node).Identifier);
130+
}
131+
132+
private static void HandleJoinIntoClause(SyntaxNodeAnalysisContext context)
133+
{
134+
CheckIdentifier(context, ((JoinIntoClauseSyntax)context.Node).Identifier);
135+
}
136+
137+
private static void HandleForEachStatement(SyntaxNodeAnalysisContext context)
138+
{
139+
CheckIdentifier(context, ((ForEachStatementSyntax)context.Node).Identifier);
140+
}
99141

100-
// Variable names must begin with lower-case letter
101-
context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), name));
142+
private static void CheckIdentifier(SyntaxNodeAnalysisContext context, SyntaxToken identifier)
143+
{
144+
if (identifier.IsMissing)
145+
{
146+
return;
102147
}
148+
149+
string name = identifier.ValueText;
150+
if (string.IsNullOrEmpty(name) || char.IsLower(name[0]))
151+
{
152+
return;
153+
}
154+
155+
// Variable names must begin with lower-case letter
156+
context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), name));
103157
}
104158
}
105159
}

0 commit comments

Comments
 (0)