Skip to content

Commit 152c412

Browse files
committed
Merge remote-tracking branch 'DotNetAnalyzers/master' into async-streams
2 parents 3ea6146 + 605c78d commit 152c412

File tree

54 files changed

+2045
-75
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2045
-75
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/OrderingRules/SA1206CodeFixProvider.cs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ namespace StyleCop.Analyzers.OrderingRules
1414
using Microsoft.CodeAnalysis;
1515
using Microsoft.CodeAnalysis.CodeActions;
1616
using Microsoft.CodeAnalysis.CodeFixes;
17+
using Microsoft.CodeAnalysis.CSharp;
1718
using Microsoft.CodeAnalysis.CSharp.Syntax;
1819
using StyleCop.Analyzers.Helpers;
20+
using StyleCop.Analyzers.Lightup;
1921
using static StyleCop.Analyzers.OrderingRules.ModifierOrderHelper;
2022

2123
/// <summary>
@@ -55,31 +57,45 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
5557
{
5658
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
5759

58-
var memberDeclaration = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf<MemberDeclarationSyntax>();
59-
if (memberDeclaration == null)
60+
var memberOrLocalFunction = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf<CSharpSyntaxNode>(static node => node is MemberDeclarationSyntax || LocalFunctionStatementSyntaxWrapper.IsInstance(node));
61+
if (memberOrLocalFunction == null)
6062
{
6163
return document;
6264
}
6365

64-
var modifierTokenToFix = memberDeclaration.FindToken(diagnostic.Location.SourceSpan.Start);
66+
var modifierTokenToFix = memberOrLocalFunction.FindToken(diagnostic.Location.SourceSpan.Start);
6567
if (GetModifierType(modifierTokenToFix) == ModifierType.None)
6668
{
6769
return document;
6870
}
6971

70-
var newModifierList = PartiallySortModifiers(memberDeclaration.GetModifiers(), modifierTokenToFix);
71-
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, newModifierList, syntaxRoot);
72+
if (memberOrLocalFunction is MemberDeclarationSyntax memberDeclaration)
73+
{
74+
var newModifierList = PartiallySortModifiers(memberDeclaration.GetModifiers(), modifierTokenToFix);
75+
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, newModifierList, syntaxRoot);
76+
}
77+
else
78+
{
79+
var localFunctionStatement = (LocalFunctionStatementSyntaxWrapper)memberOrLocalFunction;
80+
var newModifierList = PartiallySortModifiers(localFunctionStatement.Modifiers, modifierTokenToFix);
81+
syntaxRoot = UpdateSyntaxRoot(localFunctionStatement, newModifierList, syntaxRoot);
82+
}
7283

7384
return document.WithSyntaxRoot(syntaxRoot);
7485
}
7586

7687
private static SyntaxNode UpdateSyntaxRoot(MemberDeclarationSyntax memberDeclaration, SyntaxTokenList newModifiers, SyntaxNode syntaxRoot)
7788
{
78-
var newDeclaration = memberDeclaration.WithModifiers(newModifiers);
79-
89+
var newDeclaration = DeclarationModifiersHelper.WithModifiers(memberDeclaration, newModifiers);
8090
return syntaxRoot.ReplaceNode(memberDeclaration, newDeclaration);
8191
}
8292

93+
private static SyntaxNode UpdateSyntaxRoot(LocalFunctionStatementSyntaxWrapper localFunctionStatement, SyntaxTokenList newModifiers, SyntaxNode syntaxRoot)
94+
{
95+
var newDeclaration = localFunctionStatement.WithModifiers(newModifiers);
96+
return syntaxRoot.ReplaceNode(localFunctionStatement, newDeclaration);
97+
}
98+
8399
/// <summary>
84100
/// Sorts the complete modifier list to fix all issues.
85101
/// The trivia will be maintained positionally.
@@ -175,31 +191,40 @@ protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fi
175191

176192
// because all modifiers can be fixed in one run, we
177193
// only need to store each declaration once
178-
var trackedDiagnosticMembers = new HashSet<MemberDeclarationSyntax>();
194+
var trackedDiagnosticMembers = new HashSet<CSharpSyntaxNode>();
179195
foreach (var diagnostic in diagnostics)
180196
{
181-
var memberDeclaration = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf<MemberDeclarationSyntax>();
182-
if (memberDeclaration == null)
197+
var memberOrLocalFunction = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf<CSharpSyntaxNode>(static node => node is MemberDeclarationSyntax || LocalFunctionStatementSyntaxWrapper.IsInstance(node));
198+
if (memberOrLocalFunction == null)
183199
{
184200
continue;
185201
}
186202

187-
var modifierToken = memberDeclaration.FindToken(diagnostic.Location.SourceSpan.Start);
203+
var modifierToken = memberOrLocalFunction.FindToken(diagnostic.Location.SourceSpan.Start);
188204
if (GetModifierType(modifierToken) == ModifierType.None)
189205
{
190206
continue;
191207
}
192208

193-
trackedDiagnosticMembers.Add(memberDeclaration);
209+
trackedDiagnosticMembers.Add(memberOrLocalFunction);
194210
}
195211

196212
syntaxRoot = syntaxRoot.TrackNodes(trackedDiagnosticMembers);
197213

198214
foreach (var member in trackedDiagnosticMembers)
199215
{
200-
var memberDeclaration = syntaxRoot.GetCurrentNode(member);
201-
var newModifierList = FullySortModifiers(memberDeclaration.GetModifiers());
202-
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, newModifierList, syntaxRoot);
216+
var currentMember = syntaxRoot.GetCurrentNode(member);
217+
if (currentMember is MemberDeclarationSyntax memberDeclaration)
218+
{
219+
var newModifierList = FullySortModifiers(memberDeclaration.GetModifiers());
220+
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, newModifierList, syntaxRoot);
221+
}
222+
else
223+
{
224+
var localFunctionStatement = (LocalFunctionStatementSyntaxWrapper)currentMember;
225+
var newModifierList = FullySortModifiers(localFunctionStatement.Modifiers);
226+
syntaxRoot = UpdateSyntaxRoot(localFunctionStatement, newModifierList, syntaxRoot);
227+
}
203228
}
204229

205230
return syntaxRoot;

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

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4-
#nullable disable
5-
64
namespace StyleCop.Analyzers.Test.CSharp7.NamingRules
75
{
86
using System.Threading;
@@ -16,30 +14,14 @@ namespace StyleCop.Analyzers.Test.CSharp7.NamingRules
1614

1715
public partial class SA1300CSharp7UnitTests : SA1300UnitTests
1816
{
19-
[Fact]
20-
public async Task TestUpperCaseLocalFunctionAsync()
21-
{
22-
var testCode = @"public class TestClass
23-
{
24-
public void Method()
25-
{
26-
void LocalFunction()
27-
{
28-
}
29-
}
30-
}";
31-
32-
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
33-
}
34-
3517
[Fact]
3618
public async Task TestLowerCaseLocalFunctionAsync()
3719
{
3820
var testCode = @"public class TestClass
3921
{
4022
public void Method()
4123
{
42-
void localFunction()
24+
void {|#0:localFunction|}()
4325
{
4426
}
4527
}
@@ -54,7 +36,7 @@ void LocalFunction()
5436
}
5537
}";
5638

57-
DiagnosticResult expected = Diagnostic().WithArguments("localFunction").WithLocation(5, 14);
39+
DiagnosticResult expected = Diagnostic().WithArguments("localFunction").WithLocation(0);
5840
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
5941
}
6042

@@ -66,7 +48,7 @@ public async Task TestLowerCaseLocalFunctionWithConflictAsync()
6648
{
6749
public void Method()
6850
{
69-
void localFunction()
51+
void {|#0:localFunction|}()
7052
{
7153
}
7254
@@ -85,7 +67,7 @@ void LocalFunction1()
8567
}
8668
}";
8769

88-
DiagnosticResult expected = Diagnostic().WithArguments("localFunction").WithLocation(5, 14);
70+
DiagnosticResult expected = Diagnostic().WithArguments("localFunction").WithLocation(0);
8971
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
9072
}
9173
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp7/ReadabilityRules/SA1101CSharp7UnitTests.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ public class TestClass
121121
{
122122
private int foobar = 1;
123123
124+
public int Foo()
125+
{
126+
int Quux<T>() => {|#0:foobar|};
127+
return Quux<int>();
128+
}
129+
}
130+
";
131+
var fixedCode = @"
132+
public class TestClass
133+
{
134+
private int foobar = 1;
135+
124136
public int Foo()
125137
{
126138
int Quux<T>() => this.foobar;
@@ -129,7 +141,46 @@ public int Foo()
129141
}
130142
";
131143

132-
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
144+
DiagnosticResult[] expected =
145+
{
146+
Diagnostic().WithLocation(0),
147+
};
148+
149+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
150+
}
151+
152+
[Fact]
153+
[WorkItem(3005, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3005")]
154+
public async Task TestLocalFunctionRequiresThisAsync()
155+
{
156+
var testCode = @"public class TestClass
157+
{
158+
private int field;
159+
160+
public int Method()
161+
{
162+
int Local() => {|#0:field|};
163+
return Local();
164+
}
165+
}";
166+
167+
var fixedCode = @"public class TestClass
168+
{
169+
private int field;
170+
171+
public int Method()
172+
{
173+
int Local() => this.field;
174+
return Local();
175+
}
176+
}";
177+
178+
DiagnosticResult[] expected =
179+
{
180+
Diagnostic().WithLocation(0),
181+
};
182+
183+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
133184
}
134185
}
135186
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/DocumentationRules/SA1633CSharp8UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp8.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using StyleCop.Analyzers.DocumentationRules;
69
using StyleCop.Analyzers.Test.CSharp7.DocumentationRules;
10+
using Xunit;
711

812
public partial class SA1633CSharp8UnitTests : SA1633CSharp7UnitTests
913
{
14+
[Fact]
15+
[WorkItem(3006, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3006")]
16+
public async Task TestNullableDirectiveBeforeFileHeaderAsync()
17+
{
18+
var testCode = @"#nullable enable
19+
// <copyright file=""Test0.cs"" company=""FooCorp"">
20+
// Copyright (c) FooCorp. All rights reserved.
21+
// </copyright>
22+
23+
namespace TestNamespace
24+
{
25+
}
26+
";
27+
28+
var expected = Diagnostic(FileHeaderAnalyzers.SA1633DescriptorMissing).WithLocation(1, 1);
29+
await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
30+
}
1031
}
1132
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/DocumentationRules/SA1649CSharp8UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp8.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
69
using StyleCop.Analyzers.Test.CSharp7.DocumentationRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.CustomDiagnosticVerifier<StyleCop.Analyzers.DocumentationRules.SA1649FileNameMustMatchTypeName>;
712

813
public partial class SA1649CSharp8UnitTests : SA1649CSharp7UnitTests
914
{
15+
[Fact]
16+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
17+
public async Task VerifyReadonlyMembersDoNotAffectCorrectFileNameAsync()
18+
{
19+
var testCode = @"
20+
namespace TestNamespace
21+
{
22+
public readonly struct TestType
23+
{
24+
private readonly int value;
25+
26+
public TestType(int value)
27+
{
28+
this.value = value;
29+
}
30+
31+
public readonly int GetValue() => this.value;
32+
33+
public int Property
34+
{
35+
readonly get => this.value;
36+
set => _ = value;
37+
}
38+
39+
public int this[int index]
40+
{
41+
readonly get => this.value + index;
42+
set => _ = value - index;
43+
}
44+
}
45+
}
46+
";
47+
48+
await VerifyCSharpDiagnosticAsync(fileName: "TestType.cs", testCode, testSettings: null, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
49+
}
50+
51+
[Fact]
52+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
53+
public async Task VerifyWrongFileNameWithReadonlyMembersAsync()
54+
{
55+
var testCode = @"
56+
namespace TestNamespace
57+
{
58+
public readonly struct {|#0:TestType|}
59+
{
60+
private readonly int value;
61+
62+
public TestType(int value)
63+
{
64+
this.value = value;
65+
}
66+
67+
public readonly int GetValue() => this.value;
68+
69+
public int Property
70+
{
71+
readonly get => this.value;
72+
set => _ = value;
73+
}
74+
75+
public int this[int index]
76+
{
77+
readonly get => this.value + index;
78+
set => _ = value - index;
79+
}
80+
}
81+
}
82+
";
83+
var fixedCode = @"
84+
namespace TestNamespace
85+
{
86+
public readonly struct TestType
87+
{
88+
private readonly int value;
89+
90+
public TestType(int value)
91+
{
92+
this.value = value;
93+
}
94+
95+
public readonly int GetValue() => this.value;
96+
97+
public int Property
98+
{
99+
readonly get => this.value;
100+
set => _ = value;
101+
}
102+
103+
public int this[int index]
104+
{
105+
readonly get => this.value + index;
106+
set => _ = value - index;
107+
}
108+
}
109+
}
110+
";
111+
112+
var expectedDiagnostic = Diagnostic().WithLocation(0);
113+
await VerifyCSharpFixAsync(oldFileName: "WrongFileName.cs", testCode, StyleCopSettings, expectedDiagnostic, newFileName: "TestType.cs", fixedCode, CancellationToken.None).ConfigureAwait(false);
114+
}
10115
}
11116
}

0 commit comments

Comments
 (0)