Skip to content

Commit 7c6c77e

Browse files
authored
Merge pull request #4064 from sharwell/static-anonymous
Update for static anonymous functions in C# 9
2 parents caaf3e7 + 9856cd5 commit 7c6c77e

File tree

17 files changed

+449
-3
lines changed

17 files changed

+449
-3
lines changed

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/MaintainabilityRules/SA1410CSharp9UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp9.MaintainabilityRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using StyleCop.Analyzers.Test.CSharp8.MaintainabilityRules;
9+
using Xunit;
10+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
11+
StyleCop.Analyzers.MaintainabilityRules.SA1410RemoveDelegateParenthesisWhenPossible,
12+
StyleCop.Analyzers.MaintainabilityRules.SA1410SA1411CodeFixProvider>;
713

814
public partial class SA1410CSharp9UnitTests : SA1410CSharp8UnitTests
915
{
16+
[Fact]
17+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
18+
public async Task TestStaticAnonymousMethodAsync()
19+
{
20+
var testCode = @"using System;
21+
22+
public class TestClass
23+
{
24+
public void TestMethod()
25+
{
26+
Func<int> getValue = static delegate{|#0:()|} { return 3; };
27+
}
28+
}
29+
";
30+
31+
var fixedCode = @"using System;
32+
33+
public class TestClass
34+
{
35+
public void TestMethod()
36+
{
37+
Func<int> getValue = static delegate { return 3; };
38+
}
39+
}
40+
";
41+
42+
await VerifyCSharpFixAsync(testCode, Diagnostic().WithLocation(0), fixedCode, CancellationToken.None).ConfigureAwait(false);
43+
}
1044
}
1145
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,26 @@ public static class ExtensionEnumerableExtensions
104104

105105
await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedCode, CancellationToken.None).ConfigureAwait(false);
106106
}
107+
108+
[Fact]
109+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
110+
public async Task TestStaticLambdaAccessingStaticMemberAsync()
111+
{
112+
var testCode = @"public class TestClass
113+
{
114+
private static int value;
115+
116+
public void TestMethod()
117+
{
118+
System.Action action = static () =>
119+
{
120+
value++;
121+
};
122+
}
123+
}
124+
";
125+
126+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
127+
}
107128
}
108129
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,41 @@ void M()
172172
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
173173
}
174174

175+
[Fact]
176+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
177+
public async Task TestStaticAnonymousMethodOpeningParenthesisOnNextLineAsync()
178+
{
179+
var testCode = @"using System;
180+
181+
public class TestClass
182+
{
183+
public void TestMethod()
184+
{
185+
Action<int> action = static delegate
186+
{|#0:(|}int value)
187+
{
188+
};
189+
}
190+
}
191+
";
192+
193+
var fixedCode = @"using System;
194+
195+
public class TestClass
196+
{
197+
public void TestMethod()
198+
{
199+
Action<int> action = static delegate(
200+
int value)
201+
{
202+
};
203+
}
204+
}
205+
";
206+
207+
await VerifyCSharpFixAsync(testCode, Diagnostic().WithLocation(0), fixedCode, CancellationToken.None).ConfigureAwait(false);
208+
}
209+
175210
protected virtual DiagnosticResult[] GetExpectedResultTestPrimaryConstructor()
176211
{
177212
return new[]

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,40 @@ void M()
136136
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
137137
}
138138

139+
[Fact]
140+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
141+
public async Task TestStaticAnonymousMethodClosingParenthesisOnOwnLineAsync()
142+
{
143+
var testCode = @"using System;
144+
145+
public class TestClass
146+
{
147+
public void TestMethod()
148+
{
149+
Action<int> action = static delegate(int value
150+
{|#0:)|}
151+
{
152+
};
153+
}
154+
}
155+
";
156+
157+
var fixedCode = @"using System;
158+
159+
public class TestClass
160+
{
161+
public void TestMethod()
162+
{
163+
Action<int> action = static delegate(int value)
164+
{
165+
};
166+
}
167+
}
168+
";
169+
170+
await VerifyCSharpFixAsync(testCode, Diagnostic().WithLocation(0), fixedCode, CancellationToken.None).ConfigureAwait(false);
171+
}
172+
139173
protected virtual DiagnosticResult[] GetExpectedResultTestPrimaryConstructorWithParameter()
140174
{
141175
return new[]

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,26 @@ void M()
4949
var expected = Diagnostic().WithLocation(0);
5050
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
5151
}
52+
53+
[Fact]
54+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
55+
public async Task TestStaticAnonymousMethodClosingParenthesisOnNextLineAsync()
56+
{
57+
var testCode = @"using System;
58+
59+
public class TestClass
60+
{
61+
public void TestMethod()
62+
{
63+
Action action = static delegate(
64+
{|#0:)|}
65+
{
66+
};
67+
}
68+
}
69+
";
70+
71+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
72+
}
5273
}
5374
}

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,37 @@ void M()
5656
var expected = Diagnostic().WithLocation(0);
5757
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
5858
}
59+
60+
[Fact]
61+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
62+
public async Task TestStaticAnonymousFunctionCommaOnNextLineAsync()
63+
{
64+
var testCode = @"using System;
65+
66+
public class TestClass
67+
{
68+
public void TestMethod()
69+
{
70+
Func<int, int, int> func = static (int first
71+
{|#0:,|} int second) => first + second;
72+
}
73+
}
74+
";
75+
76+
var fixedCode = @"using System;
77+
78+
public class TestClass
79+
{
80+
public void TestMethod()
81+
{
82+
Func<int, int, int> func = static (int first,
83+
int second) => first + second;
84+
}
85+
}
86+
";
87+
88+
DiagnosticResult expected = Diagnostic().WithLocation(0);
89+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
90+
}
5991
}
6092
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,34 @@
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.StyleCopDiagnosticVerifier<StyleCop.Analyzers.ReadabilityRules.SA1114ParameterListMustFollowDeclaration>;
712

813
public partial class SA1114CSharp9UnitTests : SA1114CSharp8UnitTests
914
{
15+
[Fact]
16+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
17+
public async Task TestStaticAnonymousFunctionParameterListAfterBlankLineAsync()
18+
{
19+
var testCode = @"using System;
20+
21+
public class TestClass
22+
{
23+
public void TestMethod()
24+
{
25+
Action<int> action = static (
26+
27+
{|#0:int value|}) => value++;
28+
}
29+
}
30+
";
31+
32+
var expected = Diagnostic().WithLocation(0);
33+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
34+
}
1035
}
1136
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,34 @@
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.StyleCopDiagnosticVerifier<StyleCop.Analyzers.ReadabilityRules.SA1115ParameterMustFollowComma>;
712

813
public partial class SA1115CSharp9UnitTests : SA1115CSharp8UnitTests
914
{
15+
[Fact]
16+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
17+
public async Task TestStaticAnonymousFunctionParameterAfterBlankLineAsync()
18+
{
19+
var testCode = @"using System;
20+
21+
public class TestClass
22+
{
23+
public void TestMethod()
24+
{
25+
Func<int, int, int> func = static (int first,
26+
27+
{|#0:int second|}) => first + second;
28+
}
29+
}
30+
";
31+
32+
var expected = Diagnostic().WithLocation(0);
33+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
34+
}
1035
}
1136
}

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,39 @@ public void Method()
5151
DiagnosticResult expected = Diagnostic().WithLocation(10, 21);
5252
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
5353
}
54+
55+
[Fact]
56+
[WorkItem(3973, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3973")]
57+
public async Task TestStaticAnonymousFunctionFirstParameterOnSameLineAsync()
58+
{
59+
var testCode = @"
60+
using System;
61+
62+
public class TestClass
63+
{
64+
public void TestMethod()
65+
{
66+
Func<int, int, int> func = static ({|#0:int first|},
67+
int second) => first + second;
68+
}
69+
}
70+
";
71+
72+
var fixedCode = @"
73+
using System;
74+
75+
public class TestClass
76+
{
77+
public void TestMethod()
78+
{
79+
Func<int, int, int> func = static (
80+
int first,
81+
int second) => first + second;
82+
}
83+
}
84+
";
85+
86+
await VerifyCSharpFixAsync(testCode, Diagnostic().WithLocation(0), fixedCode, CancellationToken.None).ConfigureAwait(false);
87+
}
5488
}
5589
}

0 commit comments

Comments
 (0)