Skip to content

Commit b3e8f5c

Browse files
authored
Switch analyzer cleanup (#11)
* Code optimization for switch analyzer * Fix duplicates case (check enums by value, not name)
1 parent 19cc02a commit b3e8f5c

File tree

1 file changed

+17
-46
lines changed

1 file changed

+17
-46
lines changed

SwitchAnalyzer/SwitchAnalyzer/SwitchAnalyzer.cs

+17-46
Original file line numberDiff line numberDiff line change
@@ -36,49 +36,20 @@ public override void Initialize(AnalysisContext context)
3636
return;
3737
}
3838

39-
context.RegisterCodeBlockAction(AnalyzeBlock);
39+
context.RegisterOperationAction(AnalyzeSwitch, OperationKind.Switch);
4040

41-
void AnalyzeBlock(CodeBlockAnalysisContext con) => SwitchAnalyzer.AnalyzeBlock(
42-
context: con,
43-
shouldProcessEnum: shouldProcessEnum,
44-
shouldProcessInterface: shouldProcessInterface,
41+
void AnalyzeSwitch(OperationAnalysisContext con) => CheckSwitch(
42+
switchStatement: con.Operation.Syntax as SwitchStatementSyntax,
43+
context: con,
44+
shouldProcessEnum: shouldProcessEnum,
45+
shouldProcessInterface: shouldProcessInterface,
4546
shouldProcessClass: shouldProcessClass);
4647
}
4748

48-
private static void AnalyzeBlock(CodeBlockAnalysisContext context, bool shouldProcessEnum, bool shouldProcessInterface, bool shouldProcessClass)
49-
{
50-
var blockSyntaxes = context.CodeBlock.ChildNodes().OfType<BlockSyntax>();
51-
52-
var switchStatements = blockSyntaxes.SelectMany(x => x.Statements.OfType<SwitchStatementSyntax>());
53-
54-
foreach (var switchStatement in switchStatements)
55-
{
56-
try
57-
{
58-
59-
CheckSwitch(
60-
switchStatement: switchStatement,
61-
context: context,
62-
shouldProcessEnum: shouldProcessEnum,
63-
shouldProcessInterface: shouldProcessInterface,
64-
shouldProcessClass: shouldProcessClass);
65-
}
66-
catch (Exception e)
67-
{
68-
var diagnostic = Diagnostic.Create(
69-
descriptor: AnalyzerErrorDescriptor,
70-
location: switchStatement.GetLocation(),
71-
messageArgs: e.ToString());
72-
73-
context.ReportDiagnostic(diagnostic);
74-
}
75-
}
76-
}
77-
78-
private static void CheckSwitch(SwitchStatementSyntax switchStatement, CodeBlockAnalysisContext context, bool shouldProcessEnum, bool shouldProcessInterface, bool shouldProcessClass)
49+
private static void CheckSwitch(SwitchStatementSyntax switchStatement, OperationAnalysisContext context, bool shouldProcessEnum, bool shouldProcessInterface, bool shouldProcessClass)
7950
{
8051
var expression = switchStatement.Expression;
81-
var typeInfo = context.SemanticModel.GetTypeInfo(expression);
52+
var typeInfo = context.Operation.SemanticModel.GetTypeInfo(expression);
8253
var expressionType = typeInfo.ConvertedType;
8354
var switchCases = switchStatement.Sections;
8455
var switchLocationStart = switchStatement.GetLocation().SourceSpan.Start;
@@ -145,7 +116,7 @@ private static void CheckSwitch(SwitchStatementSyntax switchStatement, CodeBlock
145116
if (expressionType.TypeKind == TypeKind.Interface && shouldProcessInterface)
146117
{
147118
bool ShouldProceed() => InterfaceAnalyzer.ShouldProceedWithChecks(switchCases);
148-
IEnumerable<SwitchArgumentTypeItem<string>> AllImplementations() => InterfaceAnalyzer.GetAllImplementationNames(switchLocationStart, expressionType, context.SemanticModel);
119+
IEnumerable<SwitchArgumentTypeItem<string>> AllImplementations() => InterfaceAnalyzer.GetAllImplementationNames(switchLocationStart, expressionType, context.Operation.SemanticModel);
149120
IEnumerable<string> CaseImplementations() => PatternMatchingHelper.GetCaseValues(switchCases);
150121

151122
ProcessSwitch(ShouldProceed, AllImplementations, CaseImplementations, InterfaceAnalyzer.Rule);
@@ -154,7 +125,7 @@ private static void CheckSwitch(SwitchStatementSyntax switchStatement, CodeBlock
154125
if (expressionType.TypeKind == TypeKind.Class && shouldProcessClass)
155126
{
156127
bool ShouldProceed() => ClassAnalyzer.ShouldProceedWithChecks(switchCases, expressionType.Name);
157-
IEnumerable<SwitchArgumentTypeItem<string>> AllImplementations() => ClassAnalyzer.GetAllImplementationNames(switchLocationStart, expressionType, context.SemanticModel);
128+
IEnumerable<SwitchArgumentTypeItem<string>> AllImplementations() => ClassAnalyzer.GetAllImplementationNames(switchLocationStart, expressionType, context.Operation.SemanticModel);
158129
IEnumerable<string> CaseImplementations() => PatternMatchingHelper.GetCaseValues(switchCases);
159130

160131
ProcessSwitch(ShouldProceed, AllImplementations, CaseImplementations, ClassAnalyzer.Rule);
@@ -179,7 +150,7 @@ private static void ProcessSwitchCases<T>(
179150
Func<IEnumerable<string>> caseImplementationFunc,
180151
DiagnosticDescriptor rule,
181152
Location location,
182-
CodeBlockAnalysisContext context,
153+
OperationAnalysisContext context,
183154
int switchStatementLocation) where T: IComparable
184155
{
185156
if (shouldProceedFunc == null
@@ -193,23 +164,23 @@ private static void ProcessSwitchCases<T>(
193164

194165
var allImplementations = allImplementationsFunc().ToList();
195166

196-
var obj = new object();
197-
var caseImplementations = caseImplementationFunc().ToDictionary(x => x, _ => obj);
167+
var caseImplementations = caseImplementationFunc().ToImmutableHashSet();
198168

199169
var checkedValues = allImplementations
200-
.Where(expectedValue => caseImplementations.ContainsKey(expectedValue.FullName))
201-
.ToDictionary(x => x.Value, x => obj);
170+
.Where(expectedValue => caseImplementations.Contains(expectedValue.FullName))
171+
.Select(x => x.Value)
172+
.ToImmutableHashSet();
202173

203174
var notCheckedValues = allImplementations.Where(x =>
204-
!checkedValues.ContainsKey(x.Value))
175+
!checkedValues.Contains(x.Value))
205176
.OrderBy(x => x.FullName)
206177
.ToList();
207178

208179
if (notCheckedValues.Any())
209180
{
210181
var firstUncheckedValue = notCheckedValues.First();
211182
var typeName = firstUncheckedValue.Member;
212-
var symbols = context.SemanticModel.LookupSymbols(switchStatementLocation);
183+
var symbols = context.Operation.SemanticModel.LookupSymbols(switchStatementLocation);
213184
var shouldAddNamespace = !symbols.Any(x => x.Name == typeName && x.ContainingNamespace.Name == firstUncheckedValue.Prefix);
214185

215186
var notCoveredValues = notCheckedValues.Select(caseName =>

0 commit comments

Comments
 (0)