Skip to content

Commit 6cae4cf

Browse files
Update SA1212 to also trigger for an init accessor before a getter
#3652
1 parent b80f0c2 commit 6cae4cf

File tree

5 files changed

+88
-4
lines changed

5 files changed

+88
-4
lines changed

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

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

44
namespace StyleCop.Analyzers.Test.CSharp9.OrderingRules
55
{
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using StyleCop.Analyzers.Test.CSharp8.OrderingRules;
9+
using StyleCop.Analyzers.Test.Verifiers;
10+
using Xunit;
11+
using static StyleCop.Analyzers.Test.Verifiers.StyleCopCodeFixVerifier<
12+
StyleCop.Analyzers.OrderingRules.SA1212PropertyAccessorsMustFollowOrder,
13+
StyleCop.Analyzers.OrderingRules.SA1212SA1213CodeFixProvider>;
714

815
public class SA1212CSharp9UnitTests : SA1212CSharp8UnitTests
916
{
17+
[Fact]
18+
[WorkItem(3652, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3652")]
19+
public async Task TestAutoPropertyDeclarationInitBeforeGetterAsync()
20+
{
21+
var testCode = @"
22+
public class Foo
23+
{
24+
public int Prop { [|init;|] get; }
25+
}";
26+
27+
var fixedCode = @"
28+
public class Foo
29+
{
30+
public int Prop { get; init; }
31+
}";
32+
33+
var test = new CSharpTest
34+
{
35+
TestCode = testCode,
36+
FixedCode = fixedCode,
37+
ReferenceAssemblies = GenericAnalyzerTest.ReferenceAssembliesNet50,
38+
};
39+
await test.RunAsync(CancellationToken.None).ConfigureAwait(false);
40+
}
41+
42+
[Fact]
43+
[WorkItem(3652, "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3652")]
44+
public async Task TestPropertyWithBackingFieldDeclarationInitBeforeGetterAsync()
45+
{
46+
var testCode = @"
47+
public class Foo
48+
{
49+
private int i = 0;
50+
51+
public int Prop
52+
{
53+
[|init
54+
{
55+
i = value;
56+
}|]
57+
58+
get
59+
{
60+
return i;
61+
}
62+
}
63+
}";
64+
65+
var fixedCode = @"
66+
public class Foo
67+
{
68+
private int i = 0;
69+
70+
public int Prop
71+
{
72+
get
73+
{
74+
return i;
75+
}
76+
77+
init
78+
{
79+
i = value;
80+
}
81+
}
82+
}";
83+
84+
var test = new CSharpTest
85+
{
86+
TestCode = testCode,
87+
FixedCode = fixedCode,
88+
ReferenceAssemblies = GenericAnalyzerTest.ReferenceAssembliesNet50,
89+
};
90+
await test.RunAsync(CancellationToken.None).ConfigureAwait(false);
91+
}
1092
}
1193
}

StyleCop.Analyzers/StyleCop.Analyzers.Test/OrderingRules/SA1212UnitTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ public int Prop
339339
}
340340

341341
[Fact]
342-
public async Task TestAutoPropertydDeclarationSetterBeforeGetterAsync()
342+
public async Task TestAutoPropertyDeclarationSetterBeforeGetterAsync()
343343
{
344344
var testCode = @"
345345
public class Foo

StyleCop.Analyzers/StyleCop.Analyzers/Lightup/SyntaxKindEx.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ internal static class SyntaxKindEx
6262
public const SyntaxKind NullableDirectiveTrivia = (SyntaxKind)9055;
6363
public const SyntaxKind FunctionPointerType = (SyntaxKind)9056;
6464
public const SyntaxKind FunctionPointerParameter = (SyntaxKind)9057;
65+
public const SyntaxKind InitAccessorDeclaration = (SyntaxKind)9060;
6566
public const SyntaxKind WithExpression = (SyntaxKind)9061;
6667
public const SyntaxKind WithInitializerExpression = (SyntaxKind)9062;
6768
public const SyntaxKind RecordDeclaration = (SyntaxKind)9063;

StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/SA1212PropertyAccessorsMustFollowOrder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace StyleCop.Analyzers.OrderingRules
1111
using Microsoft.CodeAnalysis.CSharp;
1212
using Microsoft.CodeAnalysis.CSharp.Syntax;
1313
using Microsoft.CodeAnalysis.Diagnostics;
14+
using StyleCop.Analyzers.Lightup;
1415

1516
/// <summary>
1617
/// A get accessor appears after a set accessor within a property or indexer.
@@ -99,7 +100,7 @@ private static void AnalyzeProperty(SyntaxNodeAnalysisContext context, BasePrope
99100
return;
100101
}
101102

102-
if (accessors[0].Kind() == SyntaxKind.SetAccessorDeclaration &&
103+
if ((accessors[0].Kind() == SyntaxKind.SetAccessorDeclaration || accessors[0].Kind() == SyntaxKindEx.InitAccessorDeclaration) &&
103104
accessors[1].Kind() == SyntaxKind.GetAccessorDeclaration)
104105
{
105106
context.ReportDiagnostic(Diagnostic.Create(Descriptor, accessors[0].GetLocation()));

documentation/SA1212.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717

1818
## Cause
1919

20-
A get accessor appears after a set accessor within a property or indexer.
20+
A get accessor appears after a set or init accessor within a property or indexer.
2121

2222
## Rule description
2323

24-
A violation of this rule occurs when a get accessor is placed after a set accessor within a property or indexer. To comply with this rule, the get accessor should appear before the set accessor.
24+
A violation of this rule occurs when a get accessor is placed after a set or init accessor within a property or indexer. To comply with this rule, the get accessor should appear first.
2525

2626
For example, the following code would raise an instance of this violation:
2727

0 commit comments

Comments
 (0)