Skip to content

Commit fa46a54

Browse files
committed
Update SA1300 to handle local functions
1 parent e300f9e commit fa46a54

3 files changed

Lines changed: 113 additions & 0 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Helpers/RenameHelper.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace StyleCop.Analyzers.Helpers
1212
using Microsoft.CodeAnalysis.CSharp;
1313
using Microsoft.CodeAnalysis.CSharp.Syntax;
1414
using Microsoft.CodeAnalysis.Rename;
15+
using StyleCop.Analyzers.Lightup;
1516

1617
internal static class RenameHelper
1718
{
@@ -158,6 +159,8 @@ public static SyntaxNode GetParentDeclaration(SyntaxToken token)
158159
case SyntaxKind.UsingDirective:
159160
case SyntaxKind.LabeledStatement:
160161
case SyntaxKind.AnonymousObjectMemberDeclarator:
162+
case SyntaxKindEx.LocalFunctionStatement:
163+
case SyntaxKindEx.SingleVariableDesignation:
161164
return parent;
162165

163166
default:
@@ -191,6 +194,25 @@ public bool Found
191194
private set;
192195
}
193196

197+
public override void Visit(SyntaxNode node)
198+
{
199+
switch (node.Kind())
200+
{
201+
case SyntaxKindEx.LocalFunctionStatement:
202+
this.Found |= ((LocalFunctionStatementSyntaxWrapper)node).Identifier.ValueText == this.name;
203+
break;
204+
205+
case SyntaxKindEx.SingleVariableDesignation:
206+
this.Found |= ((SingleVariableDesignationSyntaxWrapper)node).Identifier.ValueText == this.name;
207+
break;
208+
209+
default:
210+
break;
211+
}
212+
213+
base.Visit(node);
214+
}
215+
194216
public override void VisitVariableDeclarator(VariableDeclaratorSyntax node)
195217
{
196218
this.Found |= node.Identifier.ValueText == this.name;

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/NamingRules/SA1300CSharp7UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp7.NamingRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using StyleCop.Analyzers.Test.NamingRules;
9+
using TestHelper;
10+
using Xunit;
711

812
public class SA1300CSharp7UnitTests : SA1300UnitTests
913
{
14+
[Fact]
15+
public async Task TestUpperCaseLocalFunctionAsync()
16+
{
17+
var testCode = @"public class TestClass
18+
{
19+
public void Method()
20+
{
21+
void LocalFunction()
22+
{
23+
}
24+
}
25+
}";
26+
27+
await this.VerifyCSharpDiagnosticAsync(testCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
28+
}
29+
30+
[Fact]
31+
public async Task TestLowerCaseLocalFunctionAsync()
32+
{
33+
var testCode = @"public class TestClass
34+
{
35+
public void Method()
36+
{
37+
void localFunction()
38+
{
39+
}
40+
}
41+
}";
42+
var fixedCode = @"public class TestClass
43+
{
44+
public void Method()
45+
{
46+
void LocalFunction()
47+
{
48+
}
49+
}
50+
}";
51+
52+
DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("localFunction").WithLocation(5, 14);
53+
54+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
55+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
56+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
57+
}
58+
59+
[Fact]
60+
public async Task TestLowerCaseLocalFunctionWithConflictAsync()
61+
{
62+
// Conflict resolution does not attempt to examine overloaded methods.
63+
var testCode = @"public class TestClass
64+
{
65+
public void Method()
66+
{
67+
void localFunction()
68+
{
69+
}
70+
71+
int LocalFunction(int value) => value;
72+
}
73+
}";
74+
var fixedCode = @"public class TestClass
75+
{
76+
public void Method()
77+
{
78+
void LocalFunction1()
79+
{
80+
}
81+
82+
int LocalFunction(int value) => value;
83+
}
84+
}";
85+
86+
DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("localFunction").WithLocation(5, 14);
87+
88+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
89+
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
90+
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
91+
}
1092
}
1193
}

StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1300ElementMustBeginWithUpperCaseLetter.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace StyleCop.Analyzers.NamingRules
1111
using Microsoft.CodeAnalysis.CSharp.Syntax;
1212
using Microsoft.CodeAnalysis.Diagnostics;
1313
using StyleCop.Analyzers.Helpers;
14+
using StyleCop.Analyzers.Lightup;
1415

1516
/// <summary>
1617
/// The name of a C# element does not begin with an upper-case letter.
@@ -53,6 +54,7 @@ internal class SA1300ElementMustBeginWithUpperCaseLetter : DiagnosticAnalyzer
5354
private static readonly Action<SyntaxNodeAnalysisContext> EventDeclarationAction = HandleEventDeclaration;
5455
private static readonly Action<SyntaxNodeAnalysisContext> EventFieldDeclarationAction = HandleEventFieldDeclaration;
5556
private static readonly Action<SyntaxNodeAnalysisContext> MethodDeclarationAction = HandleMethodDeclaration;
57+
private static readonly Action<SyntaxNodeAnalysisContext> LocalFunctionStatementAction = HandleLocalFunctionStatement;
5658
private static readonly Action<SyntaxNodeAnalysisContext> PropertyDeclarationAction = HandlePropertyDeclaration;
5759

5860
/// <inheritdoc/>
@@ -76,6 +78,7 @@ public override void Initialize(AnalysisContext context)
7678
context.RegisterSyntaxNodeAction(EventDeclarationAction, SyntaxKind.EventDeclaration);
7779
context.RegisterSyntaxNodeAction(EventFieldDeclarationAction, SyntaxKind.EventFieldDeclaration);
7880
context.RegisterSyntaxNodeAction(MethodDeclarationAction, SyntaxKind.MethodDeclaration);
81+
context.RegisterSyntaxNodeAction(LocalFunctionStatementAction, SyntaxKindEx.LocalFunctionStatement);
7982
context.RegisterSyntaxNodeAction(PropertyDeclarationAction, SyntaxKind.PropertyDeclaration);
8083
}
8184

@@ -179,6 +182,12 @@ private static void HandleMethodDeclaration(SyntaxNodeAnalysisContext context)
179182
CheckElementNameToken(context, methodDeclaration.Identifier);
180183
}
181184

185+
private static void HandleLocalFunctionStatement(SyntaxNodeAnalysisContext context)
186+
{
187+
var localFunctionStatement = (LocalFunctionStatementSyntaxWrapper)context.Node;
188+
CheckElementNameToken(context, localFunctionStatement.Identifier);
189+
}
190+
182191
private static void HandlePropertyDeclaration(SyntaxNodeAnalysisContext context)
183192
{
184193
var propertyDeclaration = (PropertyDeclarationSyntax)context.Node;

0 commit comments

Comments
 (0)