Skip to content

Commit a32ff54

Browse files
committed
Add ElementOrderingChecks
1 parent 2cd1db3 commit a32ff54

4 files changed

Lines changed: 119 additions & 64 deletions

File tree

StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/ElementOrderCodeFixProvider.cs

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,6 @@ public class ElementOrderCodeFixProvider : CodeFixProvider
2828
SA1214StaticReadonlyElementsMustAppearBeforeStaticNonReadonlyElements.DiagnosticId,
2929
SA1215InstanceReadonlyElementsMustAppearBeforeInstanceNonReadonlyElements.DiagnosticId);
3030

31-
private static bool checkElementType;
32-
private static bool checkAccessLevel;
33-
private static bool checkConst;
34-
private static bool checkStatic;
35-
private static bool checkReadonly;
36-
3731
/// <inheritdoc/>
3832
public override ImmutableArray<string> FixableDiagnosticIds => FixableDiagnostics;
3933

@@ -46,18 +40,6 @@ public override FixAllProvider GetFixAllProvider()
4640
/// <inheritdoc/>
4741
public override Task RegisterCodeFixesAsync(CodeFixContext context)
4842
{
49-
SemanticModel semanticModel;
50-
context.Document.TryGetSemanticModel(out semanticModel);
51-
if (semanticModel != null)
52-
{
53-
checkElementType = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1201ElementsMustAppearInTheCorrectOrder.DiagnosticId);
54-
checkAccessLevel = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1202ElementsMustBeOrderedByAccess.DiagnosticId);
55-
checkConst = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1203ConstantsMustAppearBeforeFields.DiagnosticId);
56-
checkStatic = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1204StaticElementsMustAppearBeforeInstanceElements.DiagnosticId);
57-
checkReadonly = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1214StaticReadonlyElementsMustAppearBeforeStaticNonReadonlyElements.DiagnosticId)
58-
|| !semanticModel.Compilation.IsAnalyzerSuppressed(SA1215InstanceReadonlyElementsMustAppearBeforeInstanceNonReadonlyElements.DiagnosticId);
59-
}
60-
6143
foreach (Diagnostic diagnostic in context.Diagnostics.Where(d => FixableDiagnostics.Contains(d.Id)))
6244
{
6345
context.RegisterCodeFix(CodeAction.Create(OrderingResources.ElementOrderCodeFix, token => GetTransformedDocumentAsync(context.Document, diagnostic, token), equivalenceKey: nameof(ElementOrderCodeFixProvider)), diagnostic);
@@ -68,6 +50,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
6850

6951
private static async Task<Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
7052
{
53+
var orderingChecks = await GetEnabledRulesForDocumentAsync(document, cancellationToken).ConfigureAwait(false);
7154
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
7255

7356
var memberDeclaration = syntaxRoot.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf<MemberDeclarationSyntax>();
@@ -76,54 +59,66 @@ private static async Task<Document> GetTransformedDocumentAsync(Document documen
7659
return document;
7760
}
7861

79-
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, syntaxRoot);
62+
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, orderingChecks, syntaxRoot);
8063

8164
return document.WithSyntaxRoot(syntaxRoot);
8265
}
8366

84-
private static SyntaxNode UpdateSyntaxRoot(MemberDeclarationSyntax memberDeclaration, SyntaxNode syntaxRoot)
67+
private static async Task<ElementOrderingChecks> GetEnabledRulesForDocumentAsync(Document document, CancellationToken cancellationToken)
68+
{
69+
SemanticModel semanticModel;
70+
document.TryGetSemanticModel(out semanticModel);
71+
if (semanticModel == null)
72+
{
73+
semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
74+
}
75+
76+
return ElementOrderingChecks.GetElementOrderingChecksForSemanticModel(semanticModel);
77+
}
78+
79+
private static SyntaxNode UpdateSyntaxRoot(MemberDeclarationSyntax memberDeclaration, ElementOrderingChecks checks, SyntaxNode syntaxRoot)
8580
{
8681
var parentDeclaration = memberDeclaration.Parent;
87-
var memberToMove = new MemberOrderHelper(memberDeclaration, checkElementType, checkAccessLevel, checkConst, checkStatic, checkReadonly);
82+
var memberToMove = new MemberOrderHelper(memberDeclaration, checks);
8883

8984
if (parentDeclaration is TypeDeclarationSyntax)
9085
{
91-
return HandleTypeDeclaration(memberToMove, (TypeDeclarationSyntax)parentDeclaration, syntaxRoot);
86+
return HandleTypeDeclaration(memberToMove, (TypeDeclarationSyntax)parentDeclaration, checks, syntaxRoot);
9287
}
9388

9489
if (parentDeclaration is NamespaceDeclarationSyntax)
9590
{
96-
return HandleNamespaceDeclaration(memberToMove, (NamespaceDeclarationSyntax)parentDeclaration, syntaxRoot);
91+
return HandleNamespaceDeclaration(memberToMove, (NamespaceDeclarationSyntax)parentDeclaration, checks, syntaxRoot);
9792
}
9893

9994
if (parentDeclaration is CompilationUnitSyntax)
10095
{
101-
return HandleCompilationUnitDeclaration(memberToMove, (CompilationUnitSyntax)parentDeclaration, syntaxRoot);
96+
return HandleCompilationUnitDeclaration(memberToMove, (CompilationUnitSyntax)parentDeclaration, checks, syntaxRoot);
10297
}
10398

10499
return syntaxRoot;
105100
}
106101

107-
private static SyntaxNode HandleTypeDeclaration(MemberOrderHelper memberOrder, TypeDeclarationSyntax typeDeclarationNode, SyntaxNode syntaxRoot)
102+
private static SyntaxNode HandleTypeDeclaration(MemberOrderHelper memberOrder, TypeDeclarationSyntax typeDeclarationNode, ElementOrderingChecks checks, SyntaxNode syntaxRoot)
108103
{
109-
return MoveMember(memberOrder, typeDeclarationNode.Members, syntaxRoot);
104+
return MoveMember(memberOrder, typeDeclarationNode.Members, checks, syntaxRoot);
110105
}
111106

112-
private static SyntaxNode HandleCompilationUnitDeclaration(MemberOrderHelper memberOrder, CompilationUnitSyntax compilationUnitDeclaration, SyntaxNode syntaxRoot)
107+
private static SyntaxNode HandleCompilationUnitDeclaration(MemberOrderHelper memberOrder, CompilationUnitSyntax compilationUnitDeclaration, ElementOrderingChecks checks, SyntaxNode syntaxRoot)
113108
{
114-
return MoveMember(memberOrder, compilationUnitDeclaration.Members, syntaxRoot);
109+
return MoveMember(memberOrder, compilationUnitDeclaration.Members, checks, syntaxRoot);
115110
}
116111

117-
private static SyntaxNode HandleNamespaceDeclaration(MemberOrderHelper memberOrder, NamespaceDeclarationSyntax namespaceDeclaration, SyntaxNode syntaxRoot)
112+
private static SyntaxNode HandleNamespaceDeclaration(MemberOrderHelper memberOrder, NamespaceDeclarationSyntax namespaceDeclaration, ElementOrderingChecks checks, SyntaxNode syntaxRoot)
118113
{
119-
return MoveMember(memberOrder, namespaceDeclaration.Members, syntaxRoot);
114+
return MoveMember(memberOrder, namespaceDeclaration.Members, checks, syntaxRoot);
120115
}
121116

122-
private static SyntaxNode MoveMember(MemberOrderHelper memberOrder, SyntaxList<MemberDeclarationSyntax> members, SyntaxNode syntaxRoot)
117+
private static SyntaxNode MoveMember(MemberOrderHelper memberOrder, SyntaxList<MemberDeclarationSyntax> members, ElementOrderingChecks checks, SyntaxNode syntaxRoot)
123118
{
124119
foreach (var member in members)
125120
{
126-
var orderHelper = new MemberOrderHelper(member, checkElementType, checkAccessLevel, checkConst, checkStatic, checkReadonly);
121+
var orderHelper = new MemberOrderHelper(member, checks);
127122

128123
if (orderHelper.Priority < memberOrder.Priority)
129124
{
@@ -164,17 +159,7 @@ protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fi
164159
return null;
165160
}
166161

167-
SemanticModel semanticModel;
168-
document.TryGetSemanticModel(out semanticModel);
169-
if (semanticModel != null)
170-
{
171-
checkElementType = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1201ElementsMustAppearInTheCorrectOrder.DiagnosticId);
172-
checkAccessLevel = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1202ElementsMustBeOrderedByAccess.DiagnosticId);
173-
checkConst = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1203ConstantsMustAppearBeforeFields.DiagnosticId);
174-
checkStatic = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1204StaticElementsMustAppearBeforeInstanceElements.DiagnosticId);
175-
checkReadonly = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1214StaticReadonlyElementsMustAppearBeforeStaticNonReadonlyElements.DiagnosticId)
176-
|| !semanticModel.Compilation.IsAnalyzerSuppressed(SA1215InstanceReadonlyElementsMustAppearBeforeInstanceNonReadonlyElements.DiagnosticId);
177-
}
162+
var orderingChecks = await GetEnabledRulesForDocumentAsync(document, fixAllContext.CancellationToken).ConfigureAwait(false);
178163

179164
var syntaxRoot = await document.GetSyntaxRootAsync().ConfigureAwait(false);
180165

@@ -186,7 +171,7 @@ protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fi
186171
continue;
187172
}
188173

189-
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, syntaxRoot);
174+
syntaxRoot = UpdateSyntaxRoot(memberDeclaration, orderingChecks, syntaxRoot);
190175
}
191176

192177
return syntaxRoot;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
namespace StyleCop.Analyzers.OrderingRules
2+
{
3+
using Microsoft.CodeAnalysis;
4+
using StyleCop.Analyzers.Helpers;
5+
6+
/// <summary>
7+
/// Contains information about enabled element order rules.
8+
/// </summary>
9+
internal struct ElementOrderingChecks
10+
{
11+
/// <summary>
12+
/// Initializes a new instance of the <see cref="ElementOrderingChecks"/> struct.
13+
/// </summary>
14+
/// <param name="checkElementType">Indicates whether element type should be checked.</param>
15+
/// <param name="checkAccessLevel">Indicates whether access level should be checked.</param>
16+
/// <param name="checkConst">Indicates whether const modifiers should be checked.</param>
17+
/// <param name="checkStatic">Indicates whether static modifiers should be checked.</param>
18+
/// <param name="checkReadonly">Indicates whether readonly modifiers should be checked.</param>
19+
internal ElementOrderingChecks(bool checkElementType, bool checkAccessLevel, bool checkConst, bool checkStatic, bool checkReadonly)
20+
{
21+
this.ElementType = checkElementType;
22+
this.AccessLevel = checkAccessLevel;
23+
this.Const = checkConst;
24+
this.Static = checkStatic;
25+
this.Readonly = checkReadonly;
26+
}
27+
28+
/// <summary>
29+
/// Gets a value indicating whether the element type should be checked.
30+
/// </summary>
31+
/// <value>Indicates whether element type should be checked.</value>
32+
internal bool ElementType { get; }
33+
34+
/// <summary>
35+
/// Gets a value indicating whether the access level should be checked.
36+
/// </summary>
37+
/// <value>Indicates whether access level should be checked.</value>
38+
internal bool AccessLevel { get; }
39+
40+
/// <summary>
41+
/// Gets a value indicating whether the const modifier should be checked.
42+
/// </summary>
43+
/// <value>Indicates whether const modifier should be checked.</value>
44+
internal bool Const { get; }
45+
46+
/// <summary>
47+
/// Gets a value indicating whether the static modifier should be checked.
48+
/// </summary>
49+
/// <value>Indicates whether static modifier should be checked.</value>
50+
internal bool Static { get; }
51+
52+
/// <summary>
53+
/// Gets a value indicating whether the readonly modifier should be checked.
54+
/// </summary>
55+
/// <value>Indicates whether readonly modifier should be checked.</value>
56+
internal bool Readonly { get; }
57+
58+
/// <summary>
59+
/// Creates a configured instance of the <see cref="ElementOrderingChecks"/> struct for the given semantic model.
60+
/// </summary>
61+
/// <param name="semanticModel">The semantic model.</param>
62+
/// <returns>The created <see cref="ElementOrderingChecks"/>.</returns>
63+
internal static ElementOrderingChecks GetElementOrderingChecksForSemanticModel(SemanticModel semanticModel)
64+
{
65+
var checkReadonly = !semanticModel.Compilation.IsAnalyzerSuppressed(SA1214StaticReadonlyElementsMustAppearBeforeStaticNonReadonlyElements.DiagnosticId)
66+
|| !semanticModel.Compilation.IsAnalyzerSuppressed(SA1215InstanceReadonlyElementsMustAppearBeforeInstanceNonReadonlyElements.DiagnosticId);
67+
return new ElementOrderingChecks(
68+
!semanticModel.Compilation.IsAnalyzerSuppressed(SA1201ElementsMustAppearInTheCorrectOrder.DiagnosticId),
69+
!semanticModel.Compilation.IsAnalyzerSuppressed(SA1202ElementsMustBeOrderedByAccess.DiagnosticId),
70+
!semanticModel.Compilation.IsAnalyzerSuppressed(SA1203ConstantsMustAppearBeforeFields.DiagnosticId),
71+
!semanticModel.Compilation.IsAnalyzerSuppressed(SA1204StaticElementsMustAppearBeforeInstanceElements.DiagnosticId),
72+
checkReadonly);
73+
}
74+
}
75+
}

StyleCop.Analyzers/StyleCop.Analyzers/OrderingRules/MemberOrderHelper.cs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,30 +33,24 @@ internal struct MemberOrderHelper
3333
SyntaxKind.NamespaceDeclaration);
3434

3535
private readonly ModifierFlags modifierFlags;
36-
private readonly AccessLevel accessibilty;
3736
private readonly int elementPriority;
38-
private readonly bool prioritizeAccess;
37+
private readonly AccessLevel accessibilty;
3938

4039
/// <summary>
4140
/// Initializes a new instance of the <see cref="MemberOrderHelper"/> struct.
4241
/// </summary>
4342
/// <param name="member">The member to wrap.</param>
44-
/// <param name="prioritizeType">Indicates whether to prioritize element type.</param>
45-
/// <param name="prioritizeAccess">Indicates whether to prioritize access level.</param>
46-
/// <param name="prioritizeConst">Indicates whether to prioritize constants.</param>
47-
/// <param name="prioritizeStatic">Indicates whether to prioritize static elements.</param>
48-
/// <param name="prioritizeReadonly">Indicates whether to prioritize readonly elements.</param>
49-
public MemberOrderHelper(MemberDeclarationSyntax member, bool prioritizeType = true, bool prioritizeAccess = true, bool prioritizeConst = true, bool prioritizeStatic = true, bool prioritizeReadonly = true)
43+
/// <param name="checks">The element ordering checks.</param>
44+
internal MemberOrderHelper(MemberDeclarationSyntax member, ElementOrderingChecks checks)
5045
{
5146
this.Member = member;
52-
this.prioritizeAccess = prioritizeAccess;
5347
var modifiers = member.GetModifiers();
5448
var type = member.Kind();
5549
type = type == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : type;
5650

57-
this.elementPriority = prioritizeType ? TypeMemberOrder.IndexOf(type) : 0;
58-
this.modifierFlags = GetModifierFlags(modifiers, prioritizeConst, prioritizeStatic, prioritizeReadonly);
59-
if (prioritizeAccess)
51+
this.elementPriority = checks.ElementType ? TypeMemberOrder.IndexOf(type) : 0;
52+
this.modifierFlags = GetModifierFlags(modifiers, checks);
53+
if (checks.AccessLevel)
6054
{
6155
if ((type == SyntaxKind.ConstructorDeclaration && this.modifierFlags.HasFlag(ModifierFlags.Static))
6256
|| (type == SyntaxKind.MethodDeclaration && (member as MethodDeclarationSyntax)?.ExplicitInterfaceSpecifier != null)
@@ -117,15 +111,15 @@ private enum ModifierFlags
117111
/// <value>
118112
/// The wrapped member.
119113
/// </value>
120-
public MemberDeclarationSyntax Member { get; }
114+
internal MemberDeclarationSyntax Member { get; }
121115

122116
/// <summary>
123117
/// The priority for this member.
124118
/// </summary>
125119
/// <value>
126120
/// The priority for this member.
127121
/// </value>
128-
public int Priority
122+
internal int Priority
129123
{
130124
get
131125
{
@@ -146,31 +140,31 @@ public int Priority
146140
/// <value>
147141
/// The priority for this member.
148142
/// </value>
149-
public int AccessibilityPriority => (int)this.accessibilty;
143+
internal int AccessibilityPriority => (int)this.accessibilty;
150144

151145
/// <summary>
152146
/// The priority for this member only from modifiers.
153147
/// </summary>
154148
/// <value>
155149
/// The priority for this member.
156150
/// </value>
157-
public int ModifierPriority => (int)this.modifierFlags;
151+
internal int ModifierPriority => (int)this.modifierFlags;
158152

159-
private static ModifierFlags GetModifierFlags(SyntaxTokenList syntax, bool prioritizeConst, bool prioritizeStatic, bool prioritizeReadonly)
153+
private static ModifierFlags GetModifierFlags(SyntaxTokenList syntax, ElementOrderingChecks checks)
160154
{
161155
var flags = ModifierFlags.None;
162-
if (prioritizeConst && syntax.Any(SyntaxKind.ConstKeyword))
156+
if (checks.Const && syntax.Any(SyntaxKind.ConstKeyword))
163157
{
164158
flags |= ModifierFlags.Const;
165159
}
166160
else
167161
{
168-
if (prioritizeStatic && syntax.Any(SyntaxKind.StaticKeyword))
162+
if (checks.Static && syntax.Any(SyntaxKind.StaticKeyword))
169163
{
170164
flags |= ModifierFlags.Static;
171165
}
172166

173-
if (prioritizeReadonly && syntax.Any(SyntaxKind.ReadOnlyKeyword))
167+
if (checks.Readonly && syntax.Any(SyntaxKind.ReadOnlyKeyword))
174168
{
175169
flags |= ModifierFlags.Readonly;
176170
}

StyleCop.Analyzers/StyleCop.Analyzers/StyleCop.Analyzers.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@
245245
<Compile Include="NamingRules\SX1309SStaticFieldNamesMustBeginWithUnderscore.cs" />
246246
<Compile Include="NoCodeFixAttribute.cs" />
247247
<Compile Include="NoDiagnosticAttribute.cs" />
248+
<Compile Include="OrderingRules\ElementOrderingChecks.cs" />
248249
<Compile Include="OrderingRules\MemberOrderHelper.cs" />
249250
<Compile Include="OrderingRules\OrderingResources.Designer.cs">
250251
<AutoGen>True</AutoGen>

0 commit comments

Comments
 (0)