Skip to content

Commit 35493de

Browse files
committed
Make analyzer stateless
1 parent 40e7dab commit 35493de

File tree

2 files changed

+27
-59
lines changed

2 files changed

+27
-59
lines changed

Diff for: src/WindowsForms.Analyzers/ControlTabOrderAnalyzer.cs

+26-23
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ public static readonly DiagnosticDescriptor InconsistentTabIndexRuleIdDescriptor
3535
isEnabledByDefault: true,
3636
"Remove TabIndex assignments and re-order controls in the parent's control collection.");
3737

38-
// Contains the list of fields and local controls that explicitly set TabIndex properties.
39-
private readonly Dictionary<string, int> _controlsTabIndex = new();
40-
// Contains the list of fields and local controls in order those are added to parent controls.
41-
private readonly Dictionary<string, List<string>> _controlsAddIndex = new();
42-
private readonly Dictionary<string, Location> _controlsAddIndexLocations = new();
43-
4438

4539
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
4640
=> ImmutableArray.Create(InconsistentTabIndexRuleIdDescriptor, NonNumericTabIndexValueRuleIdDescriptor);
@@ -68,6 +62,7 @@ private void CodeBlockAction(OperationBlockAnalysisContext context)
6862
continue;
6963
}
7064

65+
CalculatedAnalysisContext calculatedContext = new();
7166
foreach (IOperation operation in blockOperation.Operations)
7267
{
7368
switch (operation.Kind)
@@ -80,14 +75,14 @@ private void CodeBlockAction(OperationBlockAnalysisContext context)
8075
if (expressionStatementOperation.Operation is IOperation invocationOperation &&
8176
invocationOperation.Syntax is InvocationExpressionSyntax expressionSyntax)
8277
{
83-
ParseControlAddStatements(expressionSyntax);
78+
ParseControlAddStatements(expressionSyntax, calculatedContext);
8479
continue;
8580
}
8681

8782
// Look for ".TabIndex = <x>"
8883
if (expressionStatementOperation.Operation is IAssignmentOperation assignmentOperation)
8984
{
90-
ParseTabIndexAssignments((AssignmentExpressionSyntax)assignmentOperation.Syntax, context);
85+
ParseTabIndexAssignments((AssignmentExpressionSyntax)assignmentOperation.Syntax, context, calculatedContext);
9186
continue;
9287
}
9388

@@ -99,7 +94,7 @@ private void CodeBlockAction(OperationBlockAnalysisContext context)
9994
}
10095
}
10196

102-
if (_controlsTabIndex.Count < 1)
97+
if (calculatedContext.ControlsTabIndex.Count < 1)
10398
{
10499
// No controls explicitly set TabIndex - all good
105100
return;
@@ -116,25 +111,25 @@ private void CodeBlockAction(OperationBlockAnalysisContext context)
116111
// [this.button1:1]
117112
// [label2:0]
118113
Dictionary<string, int> flatControlsAddIndex = new();
119-
foreach (string key in _controlsAddIndex.Keys)
114+
foreach (string key in calculatedContext.ControlsAddIndex.Keys)
120115
{
121-
for (int i = 0; i < _controlsAddIndex[key].Count; i++)
116+
for (int i = 0; i < calculatedContext.ControlsAddIndex[key].Count; i++)
122117
{
123-
string controlName = _controlsAddIndex[key][i];
118+
string controlName = calculatedContext.ControlsAddIndex[key][i];
124119
flatControlsAddIndex[controlName] = i;
125120
}
126121
}
127122

128123
// Verify explicit TabIndex is the same as the "add order"
129-
foreach (string key in _controlsTabIndex.Keys)
124+
foreach (string key in calculatedContext.ControlsTabIndex.Keys)
130125
{
131126
if (!flatControlsAddIndex.ContainsKey(key))
132127
{
133128
// TODO: assert, diagnostics, etc.
134129
continue;
135130
}
136131

137-
int tabIndex = _controlsTabIndex[key];
132+
int tabIndex = calculatedContext.ControlsTabIndex[key];
138133
int addIndex = flatControlsAddIndex[key];
139134

140135
if (tabIndex == addIndex)
@@ -144,16 +139,15 @@ private void CodeBlockAction(OperationBlockAnalysisContext context)
144139

145140
var diagnostic = Diagnostic.Create(
146141
descriptor: InconsistentTabIndexRuleIdDescriptor,
147-
location: _controlsAddIndexLocations[key],
142+
location: calculatedContext.ControlsAddIndexLocations[key],
148143
properties: new Dictionary<string, string?> { { "ZOrder", addIndex.ToString() }, { "TabIndex", tabIndex.ToString() } }.ToImmutableDictionary(),
149144
key, addIndex, tabIndex);
150145
context.ReportDiagnostic(diagnostic);
151146
}
152-
153147
}
154148
}
155149

156-
private void ParseControlAddStatements(InvocationExpressionSyntax expressionSyntax)
150+
private void ParseControlAddStatements(InvocationExpressionSyntax expressionSyntax, CalculatedAnalysisContext calculatedContext)
157151
{
158152
if (!expressionSyntax.Expression.ToString().EndsWith(".Controls.Add"))
159153
{
@@ -188,16 +182,16 @@ private void ParseControlAddStatements(InvocationExpressionSyntax expressionSynt
188182
// [this.Controls.Add] : new List { button3, this.button1 }
189183
// [panel1.Controls.Add] : new List { label2 }
190184

191-
if (!_controlsAddIndex.ContainsKey(container))
185+
if (!calculatedContext.ControlsAddIndex.ContainsKey(container))
192186
{
193-
_controlsAddIndex[container] = new List<string>();
187+
calculatedContext.ControlsAddIndex[container] = new List<string>();
194188
}
195189

196-
_controlsAddIndex[container].Add(controlName);
197-
_controlsAddIndexLocations[controlName] = syntax.Parent!.Parent!.GetLocation();
190+
calculatedContext.ControlsAddIndex[container].Add(controlName);
191+
calculatedContext.ControlsAddIndexLocations[controlName] = syntax.Parent!.Parent!.GetLocation();
198192
}
199193

200-
private void ParseTabIndexAssignments(AssignmentExpressionSyntax expressionSyntax, OperationBlockAnalysisContext context)
194+
private void ParseTabIndexAssignments(AssignmentExpressionSyntax expressionSyntax, OperationBlockAnalysisContext context, CalculatedAnalysisContext calculatedContext)
201195
{
202196
var propertyNameExpressionSyntax = (MemberAccessExpressionSyntax)expressionSyntax.Left;
203197
SimpleNameSyntax propertyNameSyntax = propertyNameExpressionSyntax.Name;
@@ -230,7 +224,7 @@ private void ParseTabIndexAssignments(AssignmentExpressionSyntax expressionSynta
230224
#pragma warning restore CS8605 // Unboxing a possibly null value.
231225

232226
// "button3:0"
233-
_controlsTabIndex[controlName] = tabIndexValue;
227+
calculatedContext.ControlsTabIndex[controlName] = tabIndexValue;
234228
}
235229

236230
private static string? GetControlName(ExpressionSyntax expressionSyntax)
@@ -244,5 +238,14 @@ private void ParseTabIndexAssignments(AssignmentExpressionSyntax expressionSynta
244238

245239
_ => null,
246240
};
241+
242+
private sealed class CalculatedAnalysisContext
243+
{
244+
// Contains the list of fields and local controls that explicitly set TabIndex properties.
245+
public Dictionary<string, int> ControlsTabIndex { get; } = new();
246+
// Contains the list of fields and local controls in order those are added to parent controls.
247+
public Dictionary<string, List<string>> ControlsAddIndex { get; } = new();
248+
public Dictionary<string, Location> ControlsAddIndexLocations { get; } = new();
249+
}
247250
}
248251
}

Diff for: src/WindowsForms.CodeFixes/ControlTabOrderAnalyzerCodeFixProvider.cs

+1-36
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44
using System.Collections.Immutable;
55
using System.Composition;
66
using System.Linq;
7-
using System.Threading;
87
using System.Threading.Tasks;
98
using Microsoft.CodeAnalysis;
109
using Microsoft.CodeAnalysis.CodeActions;
1110
using Microsoft.CodeAnalysis.CodeFixes;
12-
using Microsoft.CodeAnalysis.CSharp;
1311
using Microsoft.CodeAnalysis.CSharp.Syntax;
14-
using Microsoft.CodeAnalysis.Options;
15-
using Microsoft.CodeAnalysis.Rename;
1612
using Microsoft.CodeAnalysis.Text;
1713
using WindowsForms.Analyzers;
1814

@@ -47,40 +43,9 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
4743
context.RegisterCodeFix(
4844
CodeAction.Create(
4945
title: CodeFixResources.CodeFixTitle,
50-
createChangedSolution: c => MakeUppercaseAsync(context.Document, declaration, c),
46+
createChangedSolution: c => null,
5147
equivalenceKey: nameof(CodeFixResources.CodeFixTitle)),
5248
diagnostic);
5349
}
54-
55-
private async Task<Solution> MakeUppercaseAsync(Document document, TypeDeclarationSyntax typeDecl, CancellationToken cancellationToken)
56-
{
57-
// Compute new uppercase name.
58-
SyntaxToken identifierToken = typeDecl.Identifier;
59-
var newName = identifierToken.Text.ToUpperInvariant();
60-
61-
// Get the symbol representing the type to be renamed.
62-
SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken);
63-
INamedTypeSymbol typeSymbol = semanticModel.GetDeclaredSymbol(typeDecl, cancellationToken);
64-
65-
// Produce a new solution that has all references to that type renamed, including the declaration.
66-
Solution originalSolution = document.Project.Solution;
67-
OptionSet optionSet = originalSolution.Workspace.Options;
68-
Solution newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, typeSymbol, newName, optionSet, cancellationToken).ConfigureAwait(false);
69-
70-
// Return the new solution with the now-uppercase type name.
71-
return newSolution;
72-
}
7350
}
74-
75-
//[ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = nameof(ControlTabOrderAnalyzerCodeRefactoringProvider)), Shared]
76-
77-
//public class ControlTabOrderAnalyzerCodeRefactoringProvider : CodeRefactoringProvider
78-
//{
79-
// public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
80-
// {
81-
// var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
82-
83-
// throw new System.NotImplementedException();
84-
// }
85-
//}
8651
}

0 commit comments

Comments
 (0)