Skip to content

Commit 962472b

Browse files
committed
Update SA1304/SA1307/SA1311 for readonly members
1 parent 2ba3c91 commit 962472b

File tree

6 files changed

+150
-0
lines changed

6 files changed

+150
-0
lines changed

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/NamingRules/SA1304CSharp8UnitTests.cs

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

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

815
public partial class SA1304CSharp8UnitTests : SA1304CSharp7UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
19+
public async Task TestReadonlyMembersDoNotTriggerAsync()
20+
{
21+
var testCode = @"public struct TestStruct
22+
{
23+
public readonly void Method() { }
24+
public int Property { readonly get; set; }
25+
}";
26+
27+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
28+
}
29+
30+
[Fact]
31+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
32+
public async Task TestPublicReadonlyFieldHandledBySA1307Async()
33+
{
34+
var testCode = @"public struct TestStruct
35+
{
36+
public readonly int bar;
37+
public readonly void Method() { }
38+
}";
39+
40+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
41+
}
42+
43+
[Fact]
44+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
45+
public async Task TestPublicStaticReadonlyFieldHandledBySA1311Async()
46+
{
47+
var testCode = @"public struct TestStruct
48+
{
49+
public static readonly int bar;
50+
public readonly void Method() { }
51+
}";
52+
53+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
54+
}
1055
}
1156
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/NamingRules/SA1307CSharp8UnitTests.cs

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

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

815
public partial class SA1307CSharp8UnitTests : SA1307CSharp7UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
19+
public async Task TestReadonlyFieldInStructAsync()
20+
{
21+
var testCode = @"public struct TestStruct
22+
{
23+
public readonly int {|#0:bar|};
24+
public readonly void Method() { }
25+
}";
26+
27+
var fixedCode = @"public struct TestStruct
28+
{
29+
public readonly int Bar;
30+
public readonly void Method() { }
31+
}";
32+
33+
DiagnosticResult expected = Diagnostic().WithLocation(0).WithArguments("bar");
34+
35+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
36+
}
37+
38+
[Fact]
39+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
40+
public async Task TestStaticReadonlyFieldInStructAsync()
41+
{
42+
var testCode = @"public struct TestStruct
43+
{
44+
public static readonly int {|#0:bar|};
45+
public readonly void Method() { }
46+
}";
47+
48+
var fixedCode = @"public struct TestStruct
49+
{
50+
public static readonly int Bar;
51+
public readonly void Method() { }
52+
}";
53+
54+
DiagnosticResult expected = Diagnostic().WithLocation(0).WithArguments("bar");
55+
56+
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
57+
}
58+
59+
[Fact]
60+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
61+
public async Task TestReadonlyMembersWithoutFieldsAsync()
62+
{
63+
var testCode = @"public struct TestStruct
64+
{
65+
public readonly void Method() { }
66+
public int Property { readonly get; set; }
67+
}";
68+
69+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
70+
}
1071
}
1172
}

StyleCop.Analyzers/StyleCop.Analyzers.Test.CSharp8/NamingRules/SA1311CSharp8UnitTests.cs

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

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

815
public partial class SA1311CSharp8UnitTests : SA1311CSharp7UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
19+
public async Task TestStaticReadonlyFieldInStructWithReadonlyMembersAsync()
20+
{
21+
var testCode = @"public struct TestStruct
22+
{
23+
public static readonly string [|bar|] = string.Empty;
24+
public readonly void Method() { }
25+
}";
26+
27+
var fixedCode = @"public struct TestStruct
28+
{
29+
public static readonly string Bar = string.Empty;
30+
public readonly void Method() { }
31+
}";
32+
33+
await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedCode, CancellationToken.None).ConfigureAwait(false);
34+
}
35+
36+
[Fact]
37+
[WorkItem(3001, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3001")]
38+
public async Task TestReadonlyMembersWithoutStaticReadonlyFieldsAsync()
39+
{
40+
var testCode = @"public struct TestStruct
41+
{
42+
public readonly void Method() { }
43+
public int Property { readonly get; set; }
44+
}";
45+
46+
await VerifyCSharpDiagnosticAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
47+
}
1048
}
1149
}

documentation/SA1304.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ A violation of this rule occurs when the name of a readonly field which is not p
2525

2626
If the field or variable name is intended to match the name of an item associated with Win32 or COM, and thus needs to begin with a lower-case letter, place the field or variable within a special *NativeMethods* class. A NativeMethods class is any class which contains a name ending in NativeMethods, and is intended as a placeholder for Win32 or COM wrappers. StyleCop will ignore this violation if the item is placed within a NativeMethods class.
2727

28+
C# 8 allows readonly members on structs. This rule still only analyzes readonly fields; readonly methods, properties, indexers, or events are ignored. When a readonly field is public or protected, SA1307 reports the naming violation instead of SA1304. Static readonly fields are covered by SA1311. SA1304 normally reports on internal readonly fields (or on public/protected readonly fields only when SA1307 is disabled), which avoids multiple diagnostics for the same field.
29+
2830
## How to fix violations
2931

3032
To fix a violation of this rule, change the name of the readonly field so that it begins with an upper-case letter, make the field private, or place the item within a NativeMethods class if appropriate.

documentation/SA1307.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ A violation of this rule occurs when the name of a public or internal field begi
2525

2626
If the field or variable name is intended to match the name of an item associated with Win32 or COM, and thus needs to start with a lower-case letter, place the field or variable within a special *NativeMethods* class. A NativeMethods class is any class which contains a name ending in NativeMethods, and is intended as a placeholder for Win32 or COM wrappers. StyleCop will ignore this violation if the item is placed within a NativeMethods class.
2727

28+
C# 8 readonly members do not change the scope of this rule. It still applies only to field declarations (including readonly fields in structs) and ignores readonly methods, properties, indexers, or events. Public and internal readonly fields continue to be analyzed here, while static readonly fields can also trigger SA1311. SA1304 suppresses itself for public and protected readonly fields so only one naming diagnostic is produced.
29+
2830
## How to fix violations
2931

3032
To fix a violation of this rule, change the name of the field so that it begins with an upper-case letter, or place the item within a NativeMethods class if appropriate.

documentation/SA1311.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ The name of a static readonly field does not begin with an upper-case letter.
2323

2424
A violation of this rule occurs when the name of a static readonly field begins with a lower-case letter.
2525

26+
C# 8 added readonly members for structs; this rule still only targets static readonly fields and ignores readonly methods, properties, indexers, or events. Accessible static readonly fields can also trigger SA1307, while SA1304 does not report static readonly fields. This prevents all three naming rules from firing on the same field while keeping static readonly fields covered.
27+
2628
## How to fix violations
2729

2830
To fix a violation of this rule, change the name of the field so that it begins with an upper-case letter.

0 commit comments

Comments
 (0)