Skip to content

Commit 74eded3

Browse files
committed
Update SA1130 for static anonymous functions
1 parent ff14d11 commit 74eded3

4 files changed

Lines changed: 108 additions & 3 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1130CodeFixProvider.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace StyleCop.Analyzers.ReadabilityRules
1818
using Microsoft.CodeAnalysis.CSharp.Syntax;
1919
using Microsoft.CodeAnalysis.Formatting;
2020
using StyleCop.Analyzers.Helpers;
21+
using StyleCop.Analyzers.Lightup;
2122

2223
/// <summary>
2324
/// Implements a code fix for <see cref="SA1130UseLambdaSyntax"/>.
@@ -72,7 +73,7 @@ private static async Task<bool> CanFixAsync(CodeFixContext context, Diagnostic d
7273
private static SyntaxNode ReplaceWithLambda(SemanticModel semanticModel, AnonymousMethodExpressionSyntax anonymousMethod)
7374
{
7475
var parameterList = anonymousMethod.ParameterList;
75-
ExpressionSyntax lambdaExpression;
76+
AnonymousFunctionExpressionSyntax lambdaExpression;
7677
SyntaxToken arrowToken;
7778

7879
if (parameterList == null)
@@ -178,14 +179,21 @@ private static SyntaxNode ReplaceWithLambda(SemanticModel semanticModel, Anonymo
178179
lambdaExpression = SyntaxFactory.ParenthesizedLambdaExpression(anonymousMethod.AsyncKeyword, parameterListSyntax, arrowToken, anonymousMethod.Body);
179180
}
180181

182+
var modifiers = anonymousMethod.Modifiers();
183+
if (modifiers.Count > 0)
184+
{
185+
lambdaExpression = lambdaExpression.WithModifiers(modifiers);
186+
}
187+
188+
ExpressionSyntax resultExpression = lambdaExpression;
181189
if (anonymousMethod.Parent.IsKind(SyntaxKind.CastExpression))
182190
{
183191
// In this case, the lambda needs enclosing parenthesis to be syntactically correct
184-
lambdaExpression = SyntaxFactory.ParenthesizedExpression(lambdaExpression);
192+
resultExpression = SyntaxFactory.ParenthesizedExpression(resultExpression);
185193
}
186194

187195
// TODO: No tests require this annotation. Can it be removed?
188-
return lambdaExpression
196+
return resultExpression
189197
.WithAdditionalAnnotations(Formatter.Annotation);
190198
}
191199

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/ReadabilityRules/SA1130CSharp9UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp9.ReadabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp8.ReadabilityRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
12+
StyleCop.Analyzers.ReadabilityRules.SA1130UseLambdaSyntax,
13+
StyleCop.Analyzers.ReadabilityRules.SA1130CodeFixProvider>;
714

815
public partial class SA1130CSharp9UnitTests : SA1130CSharp8UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
19+
public async Task TestStaticAnonymousMethodAsync()
20+
{
21+
var testCode = @"using System;
22+
23+
public class TestClass
24+
{
25+
public void TestMethod()
26+
{
27+
Action a = static {|#0:delegate|} { };
28+
}
29+
}
30+
";
31+
32+
var fixedCode = @"using System;
33+
34+
public class TestClass
35+
{
36+
public void TestMethod()
37+
{
38+
Action a = static () => { };
39+
}
40+
}
41+
";
42+
43+
await VerifyCSharpFixAsync(testCode, Diagnostic().WithLocation(0), fixedCode, CancellationToken.None).ConfigureAwait(false);
44+
}
45+
46+
[Fact]
47+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
48+
public async Task TestStaticAnonymousMethodWithParametersAsync()
49+
{
50+
var testCode = @"using System;
51+
52+
public class TestClass
53+
{
54+
public void TestMethod()
55+
{
56+
Func<int, int, int> sum = static {|#0:delegate|}(int x, int y) { return x + y; };
57+
}
58+
}
59+
";
60+
61+
var fixedCode = @"using System;
62+
63+
public class TestClass
64+
{
65+
public void TestMethod()
66+
{
67+
Func<int, int, int> sum = static (x, y) => { return x + y; };
68+
}
69+
}
70+
";
71+
72+
await VerifyCSharpFixAsync(testCode, Diagnostic().WithLocation(0), fixedCode, CancellationToken.None).ConfigureAwait(false);
73+
}
1074
}
1175
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.Lightup
5+
{
6+
using System;
7+
using Microsoft.CodeAnalysis;
8+
using Microsoft.CodeAnalysis.CSharp.Syntax;
9+
10+
internal static class AnonymousFunctionExpressionSyntaxExtensions
11+
{
12+
private static readonly Func<AnonymousFunctionExpressionSyntax, SyntaxTokenList> ModifiersAccessor;
13+
private static readonly Func<AnonymousFunctionExpressionSyntax, SyntaxTokenList, AnonymousFunctionExpressionSyntax> WithModifiersAccessor;
14+
15+
static AnonymousFunctionExpressionSyntaxExtensions()
16+
{
17+
ModifiersAccessor = LightupHelpers.CreateSyntaxPropertyAccessor<AnonymousFunctionExpressionSyntax, SyntaxTokenList>(typeof(AnonymousFunctionExpressionSyntax), nameof(Modifiers));
18+
WithModifiersAccessor = LightupHelpers.CreateSyntaxWithPropertyAccessor<AnonymousFunctionExpressionSyntax, SyntaxTokenList>(typeof(AnonymousFunctionExpressionSyntax), nameof(Modifiers));
19+
}
20+
21+
public static SyntaxTokenList Modifiers(this AnonymousFunctionExpressionSyntax syntax)
22+
{
23+
return ModifiersAccessor(syntax);
24+
}
25+
26+
public static AnonymousFunctionExpressionSyntax WithModifiers(this AnonymousFunctionExpressionSyntax syntax, SyntaxTokenList modifiers)
27+
{
28+
return WithModifiersAccessor(syntax, modifiers);
29+
}
30+
}
31+
}

documentation/SA1130.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ For example, each of the following would produce a violation of this rule:
3333
Action a = delegate { x = 0; };
3434
Action b = delegate() { y = 0; };
3535
Func<int, int, int> c = delegate(int m, int n) { return m + n; };
36+
Action d = static delegate() { z = 0; };
3637
```
3738

3839
The following code shows the equivalent variable declarations using the more familiar lambda syntax.
@@ -41,6 +42,7 @@ The following code shows the equivalent variable declarations using the more fam
4142
Action a = () => { x = 0; };
4243
Action b = () => { y = 0; };
4344
Func<int, int, int> c = (m, n) => m + n;
45+
Action d = static () => { z = 0; };
4446
```
4547

4648
:memo: It is not always possible to replace an anonymous method with an equivalent lambda expression. For example, the

0 commit comments

Comments
 (0)