Skip to content

Commit 313b1ea

Browse files
authored
Merge pull request #4063 from sharwell/partial-methods
Update for partial methods in C# 9
2 parents 7c6c77e + 56de55e commit 313b1ea

File tree

10 files changed

+253
-5
lines changed

10 files changed

+253
-5
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,33 @@ namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules
99
using StyleCop.Analyzers.Test.CSharp8.DocumentationRules;
1010
using StyleCop.Analyzers.Test.Helpers;
1111
using Xunit;
12+
using static StyleCop.Analyzers.Test.Verifiers.CustomDiagnosticVerifier<StyleCop.Analyzers.DocumentationRules.SA1611ElementParametersMustBeDocumented>;
1213

1314
public partial class SA1611CSharp9UnitTests : SA1611CSharp8UnitTests
1415
{
16+
[Fact]
17+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
18+
public async Task TestPartialMethodDeclarationMissingParameterDocumentationAsync()
19+
{
20+
var testCode = @"
21+
/// <summary>
22+
/// Tests a partial method.
23+
/// </summary>
24+
public partial class TestClass
25+
{
26+
/// <summary>Declaration.</summary>
27+
public partial void TestMethod(int {|#0:value|});
28+
29+
public partial void TestMethod(int value)
30+
{
31+
}
32+
}";
33+
34+
var expected = Diagnostic().WithLocation(0).WithArguments("value");
35+
36+
await VerifyCSharpDiagnosticAsync(testCode, new[] { expected }, CancellationToken.None).ConfigureAwait(false);
37+
}
38+
1539
[Theory]
1640
[MemberData(nameof(CommonMemberData.RecordTypeDeclarationKeywords), MemberType = typeof(CommonMemberData))]
1741
[WorkItem(3770, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3770")]

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules
88
using Microsoft.CodeAnalysis.Testing;
99
using StyleCop.Analyzers.Test.CSharp8.DocumentationRules;
1010
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.CustomDiagnosticVerifier<StyleCop.Analyzers.DocumentationRules.SA1612ElementParameterDocumentationMustMatchElementParameters>;
1112

1213
public partial class SA1612CSharp9UnitTests : SA1612CSharp8UnitTests
1314
{
@@ -29,5 +30,29 @@ public void TestMethod()
2930

3031
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
3132
}
33+
34+
[Fact]
35+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
36+
public async Task TestPartialMethodDeclarationWithMismatchedParameterDocumentationAsync()
37+
{
38+
var testCode = @"
39+
/// <summary>
40+
/// Tests a partial method.
41+
/// </summary>
42+
public partial class TestClass
43+
{
44+
/// <summary>Declaration.</summary>
45+
/// <param name=""{|#0:value|}"">Value.</param>
46+
public partial void TestMethod(int other);
47+
48+
public partial void TestMethod(int other)
49+
{
50+
}
51+
}";
52+
53+
var expected = Diagnostic().WithLocation(0).WithArguments("value");
54+
55+
await VerifyCSharpDiagnosticAsync(testCode, new[] { expected }, CancellationToken.None).ConfigureAwait(false);
56+
}
3257
}
3358
}

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules
88
using Microsoft.CodeAnalysis.Testing;
99
using StyleCop.Analyzers.Test.CSharp8.DocumentationRules;
1010
using Xunit;
11-
using static StyleCop.Analyzers.Test.Verifiers.StyleCopDiagnosticVerifier<StyleCop.Analyzers.DocumentationRules.SA1615ElementReturnValueMustBeDocumented>;
11+
using static StyleCop.Analyzers.Test.Verifiers.CustomDiagnosticVerifier<StyleCop.Analyzers.DocumentationRules.SA1615ElementReturnValueMustBeDocumented>;
1212

1313
public partial class SA1615CSharp9UnitTests : SA1615CSharp8UnitTests
1414
{
@@ -71,5 +71,26 @@ public class DerivedClass : BaseClass
7171

7272
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
7373
}
74+
75+
[Fact]
76+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
77+
public async Task TestPartialMethodDeclarationMissingReturnsDocumentationAsync()
78+
{
79+
var testCode = @"
80+
/// <summary>
81+
/// Tests a partial method.
82+
/// </summary>
83+
public partial class TestClass
84+
{
85+
/// <summary>Declaration.</summary>
86+
public partial {|#0:int|} TestMethod(int value);
87+
88+
public partial int TestMethod(int value) => value;
89+
}";
90+
91+
var expected = Diagnostic().WithLocation(0);
92+
93+
await VerifyCSharpDiagnosticAsync(testCode, new[] { expected }, CancellationToken.None).ConfigureAwait(false);
94+
}
7495
}
7596
}

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

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

44
namespace StyleCop.Analyzers.Test.CSharp9.DocumentationRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using StyleCop.Analyzers.Test.CSharp8.DocumentationRules;
9+
using Xunit;
10+
using static StyleCop.Analyzers.Test.Verifiers.CustomDiagnosticVerifier<StyleCop.Analyzers.DocumentationRules.SA1618GenericTypeParametersMustBeDocumented>;
711

812
public partial class SA1618CSharp9UnitTests : SA1618CSharp8UnitTests
913
{
14+
[Fact]
15+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
16+
public async Task TestPartialMethodDeclarationMissingTypeParameterDocumentationAsync()
17+
{
18+
var testCode = @"
19+
/// <summary>
20+
/// Tests a partial method.
21+
/// </summary>
22+
public partial class TestClass
23+
{
24+
/// <summary>Declaration.</summary>
25+
public partial void TestMethod<{|#0:T|}>();
26+
27+
public partial void TestMethod<T>()
28+
{
29+
}
30+
}";
31+
32+
var expected = Diagnostic().WithLocation(0).WithArguments("T");
33+
34+
await VerifyCSharpDiagnosticAsync(testCode, new[] { expected }, CancellationToken.None).ConfigureAwait(false);
35+
}
1036
}
1137
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/OrderingRules/SA1202CSharp9UnitTests.cs

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

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

815
public partial class SA1202CSharp9UnitTests : SA1202CSharp8UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
19+
public async Task TestPartialMethodExplicitAccessibilityDeclarationOrderingAsync()
20+
{
21+
var testCode = @"
22+
public partial class TestClass
23+
{
24+
private void Helper() { }
25+
26+
public partial void {|#0:TestMethod|}();
27+
}
28+
29+
public partial class TestClass
30+
{
31+
public partial void TestMethod()
32+
{
33+
}
34+
}
35+
";
36+
37+
var expected = Diagnostic().WithLocation(0).WithArguments("public", "private");
38+
39+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
40+
}
41+
42+
[Fact]
43+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
44+
public async Task TestPartialMethodExplicitAccessibilityImplementationOrderingAsync()
45+
{
46+
var testCode = @"
47+
public partial class TestClass
48+
{
49+
public partial void TestMethod();
50+
}
51+
52+
public partial class TestClass
53+
{
54+
private void Helper() { }
55+
56+
public partial void {|#0:TestMethod|}()
57+
{
58+
}
59+
}
60+
";
61+
62+
var expected = Diagnostic().WithLocation(0).WithArguments("public", "private");
63+
64+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
65+
}
1066
}
1167
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp9/OrderingRules/SA1205CSharp9UnitTests.cs

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

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

815
public partial class SA1205CSharp9UnitTests : SA1205CSharp8UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
19+
public async Task TestPartialMethodWithPublicAccessModifierAsync()
20+
{
21+
var testCode = @"
22+
public partial class TestClass
23+
{
24+
public partial int TestMethod();
25+
}
26+
27+
public partial class TestClass
28+
{
29+
public partial int TestMethod()
30+
{
31+
return 0;
32+
}
33+
}
34+
";
35+
36+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
37+
}
38+
39+
[Fact]
40+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
41+
public async Task TestPartialMethodWithoutAccessModifierAsync()
42+
{
43+
var testCode = @"
44+
public partial class TestClass
45+
{
46+
partial void {|#0:TestMethod|}();
47+
}
48+
49+
public partial class TestClass
50+
{
51+
public partial void {|CS8799:TestMethod|}()
52+
{
53+
}
54+
}
55+
";
56+
57+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
58+
}
59+
60+
[Fact]
61+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
62+
public async Task TestPartialMethodWithoutAccessModifierNonVoidAsync()
63+
{
64+
var testCode = @"
65+
public partial class TestClass
66+
{
67+
partial int {|CS8796:TestMethod|}();
68+
}
69+
70+
public partial class TestClass
71+
{
72+
public partial int {|CS8799:TestMethod|}()
73+
{
74+
return 0;
75+
}
76+
}
77+
";
78+
79+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
80+
}
1081
}
1182
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1615UnitTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,10 @@ internal class ClassName
340340
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
341341
}
342342

343-
private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult expected, CancellationToken cancellationToken)
343+
protected static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult expected, CancellationToken cancellationToken)
344344
=> VerifyCSharpFixAsync(source, new[] { expected }, fixedSource: null, cancellationToken);
345345

346-
private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken)
346+
protected static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken)
347347
=> VerifyCSharpFixAsync(source, expected, fixedSource: null, cancellationToken);
348348

349349
private static Task VerifyCSharpFixAsync(string source, DiagnosticResult expected, string fixedSource, CancellationToken cancellationToken)

StyleCop.Analyzers/StyleCop.Analyzers.Test/DocumentationRules/SA1618UnitTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,10 +427,10 @@ private void Test2<T>(int arg) { }
427427
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
428428
}
429429

430-
private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult expected, CancellationToken cancellationToken)
430+
protected static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult expected, CancellationToken cancellationToken)
431431
=> VerifyCSharpDiagnosticAsync(source, new[] { expected }, cancellationToken);
432432

433-
private static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken)
433+
protected static Task VerifyCSharpDiagnosticAsync(string source, DiagnosticResult[] expected, CancellationToken cancellationToken)
434434
{
435435
string contentClassWithTypeparamDoc = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
436436
<TestClass>

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1202UnitTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,5 +989,23 @@ public string
989989

990990
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
991991
}
992+
993+
[Fact]
994+
[WorkItem(3971, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3971")]
995+
public async Task TestPartialMethodImplicitPrivateOrderingAsync()
996+
{
997+
var testCode = @"
998+
public partial class TestClass
999+
{
1000+
partial void TestMethod();
1001+
1002+
public void {|#0:PublicMethod|}() { }
1003+
}
1004+
";
1005+
1006+
var expected = Diagnostic().WithLocation(0).WithArguments("public", "private");
1007+
1008+
await VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
1009+
}
9921010
}
9931011
}

documentation/SA1205.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ The partial element does not have an access modifier defined.
2323

2424
A violation of this rule occurs when the partial elements does not have an access modifier defined.
2525

26+
### Partial methods in C# 9
27+
28+
C# 9 allows partial methods to have access modifiers and non-`void` return types. For compatibility across versions,
29+
SA1205 does not require these access modifiers to be included. In addition, the compiler enforces the presence of access
30+
modifiers when using the new features, so SA1205 will not apply duplicate diagnostics in cases where required modifiers
31+
are omitted.
32+
2633
## How to fix violations
2734

2835
To fix an instance of this violation, specify an access modifier for the partial element.

0 commit comments

Comments
 (0)