Skip to content

Commit e6480ae

Browse files
authored
Merge pull request #4053 from sharwell/init-only-setters
Update for init-only setters
2 parents f467479 + 0ca45c4 commit e6480ae

File tree

24 files changed

+1093
-72
lines changed

24 files changed

+1093
-72
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1623CSharp9UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using Microsoft.CodeAnalysis.Testing;
9+
using StyleCop.Analyzers.DocumentationRules;
610
using StyleCop.Analyzers.Test.CSharp8.DocumentationRules;
11+
using Xunit;
12+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
13+
StyleCop.Analyzers.DocumentationRules.PropertySummaryDocumentationAnalyzer,
14+
StyleCop.Analyzers.DocumentationRules.PropertySummaryDocumentationCodeFixProvider>;
715

816
public partial class SA1623CSharp9UnitTests : SA1623CSharp8UnitTests
917
{
18+
/// <summary>
19+
/// Verifies that property documentation that does not start with the appropriate text will result in a diagnostic.
20+
/// </summary>
21+
/// <param name="accessibility">The accessibility of the property.</param>
22+
/// <param name="type">The type to use for the property.</param>
23+
/// <param name="accessors">The accessors for the property.</param>
24+
/// <param name="expectedArgument">The expected argument for the diagnostic message.</param>
25+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
26+
[Theory]
27+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
28+
[InlineData("public", "int", "{ get; init; }", "Gets or initializes")]
29+
[InlineData("public", "int", "{ get; private init; }", "Gets")]
30+
[InlineData("public", "int", "{ init { } }", "Initializes")]
31+
[InlineData("public", "int", "{ private get { return 0; } init { } }", "Initializes")]
32+
[InlineData("public", "bool", "{ get; init; }", "Gets or initializes a value indicating whether")]
33+
[InlineData("public", "bool", "{ get; private init; }", "Gets a value indicating whether")]
34+
[InlineData("public", "bool", "{ init { } }", "Initializes a value indicating whether")]
35+
[InlineData("public", "bool", "{ private get { return false; } init { } }", "Initializes a value indicating whether")]
36+
public async Task VerifyDocumentationWithWrongStartingTextWithInitAccessorWillProduceDiagnosticAsync(string accessibility, string type, string accessors, string expectedArgument)
37+
{
38+
var testCode = $@"
39+
public class TestClass
40+
{{
41+
/// <summary>
42+
/// The first test value.
43+
/// </summary>
44+
{accessibility} {type} {{|#0:TestProperty|}} {accessors}
45+
}}
46+
";
47+
48+
var fixedTestCode = $@"
49+
public class TestClass
50+
{{
51+
/// <summary>
52+
/// {expectedArgument} the first test value.
53+
/// </summary>
54+
{accessibility} {type} TestProperty {accessors}
55+
}}
56+
";
57+
58+
var expected = Diagnostic(PropertySummaryDocumentationAnalyzer.SA1623Descriptor).WithLocation(0).WithArguments(expectedArgument);
59+
await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false);
60+
61+
if (fixedTestCode.Contains("Gets or initializes"))
62+
{
63+
// These are allowed to be written as just 'Gets'
64+
await VerifyCSharpDiagnosticAsync(fixedTestCode.Replace("Gets or initializes", "Gets"), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
65+
}
66+
}
67+
68+
/// <summary>
69+
/// Verifies that property documentation that does not start with the appropriate text will result in a
70+
/// diagnostic. This is a regression test for DotNetAnalyzers/StyleCopAnalyzers#1844.
71+
/// </summary>
72+
/// <param name="accessibility">The accessibility of the property.</param>
73+
/// <param name="type">The type to use for the property.</param>
74+
/// <param name="accessors">The accessors for the property.</param>
75+
/// <param name="expectedArgument">The expected argument for the diagnostic message.</param>
76+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
77+
[Theory]
78+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
79+
[InlineData("public", "int", "{ get; init; }", "Gets or initializes")]
80+
[InlineData("public", "int", "{ get; private init; }", "Gets")]
81+
[InlineData("public", "int", "{ init { } }", "Initializes")]
82+
[InlineData("public", "int", "{ private get { return 0; } init { } }", "Initializes")]
83+
[InlineData("public", "bool", "{ get; init; }", "Gets or initializes a value indicating whether")]
84+
[InlineData("public", "bool", "{ get; private init; }", "Gets a value indicating whether")]
85+
[InlineData("public", "bool", "{ init { } }", "Initializes a value indicating whether")]
86+
[InlineData("public", "bool", "{ private get { return false; } init { } }", "Initializes a value indicating whether")]
87+
public async Task VerifyDocumentationOfPublicMethodInPrivateClassWithInitAccessorWillProduceDiagnosticAsync(string accessibility, string type, string accessors, string expectedArgument)
88+
{
89+
var testCode = $@"
90+
public class TestClass
91+
{{
92+
private class PrivateTestClass
93+
{{
94+
/// <summary>
95+
/// The first test value.
96+
/// </summary>
97+
{accessibility} {type} {{|#0:TestProperty|}} {accessors}
98+
}}
99+
}}
100+
";
101+
102+
var fixedTestCode = $@"
103+
public class TestClass
104+
{{
105+
private class PrivateTestClass
106+
{{
107+
/// <summary>
108+
/// {expectedArgument} the first test value.
109+
/// </summary>
110+
{accessibility} {type} TestProperty {accessors}
111+
}}
112+
}}
113+
";
114+
115+
var expected = Diagnostic(PropertySummaryDocumentationAnalyzer.SA1623Descriptor).WithLocation(0).WithArguments(expectedArgument);
116+
await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false);
117+
118+
if (fixedTestCode.Contains("Gets or initializes"))
119+
{
120+
// These are allowed to be written as just 'Gets'
121+
await VerifyCSharpDiagnosticAsync(fixedTestCode.Replace("Gets or initializes", "Gets"), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
122+
}
123+
}
124+
125+
/// <summary>
126+
/// Verifies that an incorrect summary tag with a known prefix will be fixed correctly.
127+
/// </summary>
128+
/// <param name="accessibility">The accessibility of the property.</param>
129+
/// <param name="type">The type to use for the property.</param>
130+
/// <param name="accessors">The accessors for the property.</param>
131+
/// <param name="summaryPrefix">The summary prefix used in the test code.</param>
132+
/// <param name="expectedArgument">The expected argument for the diagnostic message.</param>
133+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
134+
[Theory]
135+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
136+
[InlineData("public", "int", "{ get; init; }", "Sets", "Gets or initializes")]
137+
[InlineData("public", "int", "{ get; init; }", "Initializes", "Gets or initializes")]
138+
[InlineData("public", "int", "{ init {} }", "Gets", "Initializes")]
139+
[InlineData("public", "int", "{ init {} }", "Gets or sets", "Initializes")]
140+
[InlineData("public", "int", "{ init {} }", "Sets", "Initializes")]
141+
[InlineData("public", "int", "{ init {} }", "Gets or initializes", "Initializes")]
142+
[InlineData("public", "int", "{ get; private init; }", "Sets", "Gets")]
143+
[InlineData("public", "int", "{ get; private init; }", "Initializes", "Gets")]
144+
[InlineData("public", "int", "{ private get; init; }", "Gets", "Initializes")]
145+
[InlineData("public", "int", "{ private get; init; }", "Sets", "Initializes")]
146+
[InlineData("public", "int", "{ get; init; }", "Returns", "Gets or initializes")]
147+
[InlineData("public", "bool", "{ get; init; }", "Returns a value indicating whether", "Gets or initializes a value indicating whether")]
148+
public async Task IncorrectSummaryTagWithKnownPrefixAndInitAccessorShouldBeFixedCorrectlyAsync(string accessibility, string type, string accessors, string summaryPrefix, string expectedArgument)
149+
{
150+
var testCode = $@"
151+
public class TestClass
152+
{{
153+
/// <summary>
154+
/// {summaryPrefix} the value.
155+
/// </summary>
156+
{accessibility} {type} {{|#0:TestProperty|}} {accessors}
157+
}}
158+
";
159+
160+
var fixedTestCode = $@"
161+
public class TestClass
162+
{{
163+
/// <summary>
164+
/// {expectedArgument} the value.
165+
/// </summary>
166+
{accessibility} {type} TestProperty {accessors}
167+
}}
168+
";
169+
170+
DiagnosticResult[] expected =
171+
{
172+
Diagnostic(PropertySummaryDocumentationAnalyzer.SA1623Descriptor).WithLocation(0).WithArguments(expectedArgument),
173+
};
174+
175+
await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false);
176+
177+
if (fixedTestCode.Contains("Gets or initializes"))
178+
{
179+
// These are allowed to be written as just 'Gets'
180+
await VerifyCSharpDiagnosticAsync(fixedTestCode.Replace("Gets or initializes", "Gets"), DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
181+
}
182+
}
183+
184+
[Fact]
185+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
186+
public async Task TestGetInitPropertyRequiresGetsOrInitializesSummaryAsync()
187+
{
188+
var testCode = @"
189+
public class TestClass
190+
{
191+
/// <summary>
192+
/// Sets the value.
193+
/// </summary>
194+
public string {|#0:Name|} { get; init; }
195+
}
196+
";
197+
var fixedCode = @"
198+
public class TestClass
199+
{
200+
/// <summary>
201+
/// Gets or initializes the value.
202+
/// </summary>
203+
public string Name { get; init; }
204+
}
205+
";
206+
207+
var expected = Diagnostic(PropertySummaryDocumentationAnalyzer.SA1623Descriptor)
208+
.WithLocation(0)
209+
.WithArguments("Gets or initializes");
210+
211+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
212+
}
10213
}
11214
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/DocumentationRules/SA1624CSharp9UnitTests.cs

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

44
namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using StyleCop.Analyzers.DocumentationRules;
69
using StyleCop.Analyzers.Test.CSharp8.DocumentationRules;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
12+
StyleCop.Analyzers.DocumentationRules.PropertySummaryDocumentationAnalyzer,
13+
StyleCop.Analyzers.DocumentationRules.PropertySummaryDocumentationCodeFixProvider>;
714

815
public partial class SA1624CSharp9UnitTests : SA1624CSharp8UnitTests
916
{
17+
/// <summary>
18+
/// Verifies that documentation that starts with the proper text for multiple accessors will produce a diagnostic when one of the accessors has reduced visibility.
19+
/// </summary>
20+
/// <param name="accessibility">The accessibility of the property.</param>
21+
/// <param name="type">The type to use for the property.</param>
22+
/// <param name="accessors">The accessors for the property.</param>
23+
/// <param name="summaryPrefix">The prefix to use in the summary text.</param>
24+
/// <param name="expectedArgument1">The first expected argument for the diagnostic.</param>
25+
/// <param name="expectedArgument2">The second expected argument for the diagnostic.</param>
26+
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
27+
[Theory(DisplayName = "Init accessor findings")]
28+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
29+
[InlineData("public", "bool", "get; private init;", "Gets or sets a value indicating whether", "get", "Gets a value indicating whether")]
30+
[InlineData("public", "bool", "private get; init;", "Gets or sets a value indicating whether", "init", "Initializes a value indicating whether")]
31+
[InlineData("internal", "int", "get; private init;", "Gets or sets", "get", "Gets")]
32+
[InlineData("internal", "int", "private get; init;", "Gets or sets", "init", "Initializes")]
33+
[InlineData("public", "bool", "get; private init;", "Gets or initializes a value indicating whether", "get", "Gets a value indicating whether")]
34+
[InlineData("public", "bool", "private get; init;", "Gets or initializes a value indicating whether", "init", "Initializes a value indicating whether")]
35+
[InlineData("internal", "int", "get; private init;", "Gets or initializes", "get", "Gets")]
36+
[InlineData("internal", "int", "private get; init;", "Gets or initializes", "init", "Initializes")]
37+
public async Task VerifyThatInvalidDocumentationWithInitAccessorWillReportDiagnosticAsync(string accessibility, string type, string accessors, string summaryPrefix, string expectedArgument1, string expectedArgument2)
38+
{
39+
var testCode = $@"
40+
public class TestClass
41+
{{
42+
/// <summary>
43+
/// {summaryPrefix} the test property.
44+
/// </summary>
45+
{accessibility} {type} {{|#0:TestProperty|}}
46+
{{
47+
{accessors}
48+
}}
49+
}}
50+
";
51+
52+
var fixedTestCode = $@"
53+
public class TestClass
54+
{{
55+
/// <summary>
56+
/// {expectedArgument2} the test property.
57+
/// </summary>
58+
{accessibility} {type} TestProperty
59+
{{
60+
{accessors}
61+
}}
62+
}}
63+
";
64+
65+
var expected = Diagnostic(PropertySummaryDocumentationAnalyzer.SA1624Descriptor).WithLocation(0).WithArguments(expectedArgument1, expectedArgument2);
66+
await VerifyCSharpFixAsync(testCode, expected, fixedTestCode, CancellationToken.None).ConfigureAwait(false);
67+
}
68+
69+
[Theory]
70+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
71+
[InlineData("sets")]
72+
[InlineData("initializes")]
73+
public async Task TestGetInitWithRestrictedInitAsync(string setterDescription)
74+
{
75+
var testCode = $@"
76+
public class TestClass
77+
{{
78+
/// <summary>
79+
/// Gets or {setterDescription} the value.
80+
/// </summary>
81+
public string {{|#0:Name|}} {{ get; internal init; }}
82+
}}
83+
";
84+
85+
var fixedCode = @"
86+
public class TestClass
87+
{
88+
/// <summary>
89+
/// Gets the value.
90+
/// </summary>
91+
public string Name { get; internal init; }
92+
}
93+
";
94+
95+
var expected = Diagnostic(PropertySummaryDocumentationAnalyzer.SA1624Descriptor)
96+
.WithLocation(0)
97+
.WithArguments("get", "Gets");
98+
99+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
100+
}
101+
102+
[Theory]
103+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
104+
[InlineData("sets")]
105+
[InlineData("initializes")]
106+
public async Task TestGetBooleanInitWithRestrictedInitAsync(string setterDescription)
107+
{
108+
var testCode = $@"
109+
public class TestClass
110+
{{
111+
/// <summary>
112+
/// Gets or {setterDescription} a value indicating whether the value.
113+
/// </summary>
114+
public bool {{|#0:Name|}} {{ get; internal init; }}
115+
}}
116+
";
117+
118+
var fixedCode = @"
119+
public class TestClass
120+
{
121+
/// <summary>
122+
/// Gets a value indicating whether the value.
123+
/// </summary>
124+
public bool Name { get; internal init; }
125+
}
126+
";
127+
128+
var expected = Diagnostic(PropertySummaryDocumentationAnalyzer.SA1624Descriptor)
129+
.WithLocation(0)
130+
.WithArguments("get", "Gets a value indicating whether");
131+
132+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
133+
}
10134
}
11135
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/LayoutRules/SA1500CSharp9UnitTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,42 @@ int Property2
137137
FixedCode = fixedCode,
138138
}.RunAsync(CancellationToken.None).ConfigureAwait(false);
139139
}
140+
141+
[Fact]
142+
[WorkItem(3966, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3966")]
143+
public async Task TestGetBlockClosingBraceSharingLineWithInitAsync()
144+
{
145+
var testCode = @"
146+
class TestClass
147+
{
148+
int Property
149+
{
150+
get
151+
{
152+
return 0; [|}|] init
153+
{
154+
}
155+
}
156+
}
157+
";
158+
159+
var fixedCode = @"
160+
class TestClass
161+
{
162+
int Property
163+
{
164+
get
165+
{
166+
return 0;
167+
}
168+
init
169+
{
170+
}
171+
}
172+
}
173+
";
174+
175+
await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedCode, CancellationToken.None).ConfigureAwait(false);
176+
}
140177
}
141178
}

0 commit comments

Comments
 (0)