Skip to content

Commit be7e0d9

Browse files
committed
Merge remote-tracking branch 'DotNetAnalyzers/master' into pattern-matching
2 parents 94671b7 + f4e1e0c commit be7e0d9

File tree

67 files changed

+2459
-89
lines changed

Some content is hidden

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

67 files changed

+2459
-89
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/SA1600CSharp8UnitTests.cs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,121 @@
33

44
namespace StyleCop.Analyzers.Test.CSharp8.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using Microsoft.CodeAnalysis.CSharp;
9+
using Microsoft.CodeAnalysis.Testing;
710
using StyleCop.Analyzers.Test.CSharp7.DocumentationRules;
11+
using Xunit;
12+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
13+
StyleCop.Analyzers.DocumentationRules.SA1600ElementsMustBeDocumented,
14+
StyleCop.Analyzers.DocumentationRules.SA1600CodeFixProvider>;
815

916
public partial class SA1600CSharp8UnitTests : SA1600CSharp7UnitTests
1017
{
1118
// Using 'Default' here makes sure that later test projects also run these tests with their own language version, without having to override this property
1219
protected override LanguageVersion LanguageVersion => LanguageVersion.Default;
20+
21+
[Fact]
22+
[WorkItem(3002, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3002")]
23+
public async Task TestDefaultInterfaceMemberRequiresDocumentationAsync()
24+
{
25+
var testCode = @"using System;
26+
/// <summary>Summary.</summary>
27+
public interface ITest
28+
{
29+
public static int [|field1|];
30+
static int [|field2|];
31+
32+
public int [|Prop1|] { get => 0; }
33+
int [|Prop2|] { get => 0; }
34+
35+
int [|this|][int index] { get => 0; }
36+
37+
public event EventHandler [|Event1|];
38+
event EventHandler [|Event2|];
39+
40+
public event EventHandler [|Event3|] { add { } remove { } }
41+
event EventHandler [|Event4|] { add { } remove { } }
42+
43+
public void [|Method1|]() { }
44+
void [|Method2|]() { }
45+
46+
public delegate void [|Del1|]();
47+
delegate void [|Del2|]();
48+
49+
public class [|Class1|] { }
50+
class [|Class2|] { }
51+
52+
public struct [|Struct1|] { }
53+
struct [|Struct2|] { }
54+
55+
public interface [|Interface1|] { }
56+
interface [|Interface2|] { }
57+
}
58+
";
59+
60+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
61+
}
62+
63+
[Fact]
64+
[WorkItem(3002, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3002")]
65+
public async Task TestDefaultInterfaceFieldRequiresDocumentationAsync()
66+
{
67+
var testCode = @"
68+
/// <summary>Summary.</summary>
69+
public interface ITest
70+
{
71+
public static int [|field1|];
72+
static int [|field2|];
73+
}
74+
";
75+
76+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
77+
}
78+
79+
[Fact]
80+
[WorkItem(3002, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3002")]
81+
public async Task TestPrivateDefaultInterfaceMethodDoesNotRequireDocumentationByDefaultAsync()
82+
{
83+
var testCode = @"
84+
/// <summary>Summary.</summary>
85+
public interface ITest
86+
{
87+
private void M()
88+
{
89+
}
90+
}
91+
";
92+
93+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
94+
}
95+
96+
[Fact]
97+
[WorkItem(3002, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3002")]
98+
public async Task TestPrivateDefaultInterfaceMethodHonorsDocumentPrivateElementsAsync()
99+
{
100+
var testCode = @"
101+
/// <summary>Summary.</summary>
102+
public interface ITest
103+
{
104+
private void [|M|]()
105+
{
106+
}
107+
}
108+
";
109+
110+
var settings = @"
111+
{
112+
""settings"": {
113+
""documentationRules"": {
114+
""documentPrivateElements"": true
115+
}
116+
}
117+
}
118+
";
119+
120+
await VerifyCSharpDiagnosticAsync(testCode, settings, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
121+
}
13122
}
14123
}

0 commit comments

Comments
 (0)