Skip to content

Commit 5689b95

Browse files
committed
Get enumeration statements from enumeration members instead of the listener in UnreachableCaseInspection
1 parent 5eda095 commit 5689b95

File tree

5 files changed

+82
-106
lines changed

5 files changed

+82
-106
lines changed

Rubberduck.CodeAnalysis/Inspections/Concrete/UnreachableCaseInspection/ParseTreeValueVisitor.cs

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,14 @@ public class ParseTreeValueVisitor : IParseTreeValueVisitor
3232
{
3333
private readonly IParseTreeValueFactory _valueFactory;
3434
private readonly Func<Declaration, (bool, string, string)> _valueDeclarationEvaluator;
35-
private readonly IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> _enumStmtContexts;
3635

3736
public ParseTreeValueVisitor(
3837
IParseTreeValueFactory valueFactory,
39-
IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> allEnums,
4038
Func<QualifiedModuleName, ParserRuleContext, (bool success, IdentifierReference idRef)> identifierReferenceRetriever,
4139
Func<Declaration, (bool, string, string)> valueDeclarationEvaluator = null)
4240
{
4341
_valueFactory = valueFactory;
4442
IdentifierReferenceRetriever = identifierReferenceRetriever;
45-
_enumStmtContexts = allEnums;
4643
_valueDeclarationEvaluator = valueDeclarationEvaluator ?? GetValuedDeclaration;
4744
}
4845

@@ -357,10 +354,15 @@ private bool TryGetLExprValue(QualifiedModuleName module, VBAParser.LExprContext
357354
return (Tokens.Long, constantExpressionValue, resultValues);
358355
}
359356

360-
var (enumMembers, valueResults) = EnumMembers(resultValues);
361-
var enumValue = enumMembers.SingleOrDefault(dt => dt.ConstantContext == declaration.Context);
362-
var enumExpressionValue = enumValue?.Value.ToString() ?? string.Empty;
363-
return (Tokens.Long, enumExpressionValue, valueResults);
357+
if (declaration.Context.Parent is VBAParser.EnumerationStmtContext enumStmt)
358+
{
359+
var (enumMembers, valueResults) = EnumMembers(module, enumStmt, resultValues);
360+
var enumValue = enumMembers.SingleOrDefault(enumMember => enumMember.ConstantContext == declaration.Context);
361+
var enumExpressionValue = enumValue?.Value.ToString() ?? string.Empty;
362+
return (Tokens.Long, enumExpressionValue, valueResults);
363+
}
364+
365+
return (Tokens.Long, string.Empty, resultValues);
364366
}
365367

366368
return (declaredTypeName, expressionValue, knownResults);
@@ -443,46 +445,46 @@ private static bool IsBinaryOpEvaluationContext<T>(T context)
443445
return false;
444446
}
445447

446-
private (IReadOnlyList<EnumMember> enumMembers, IMutableParseTreeVisitorResults resultValues) EnumMembers(IMutableParseTreeVisitorResults knownResults)
448+
private (IReadOnlyList<EnumMember> enumMembers, IMutableParseTreeVisitorResults resultValues) EnumMembers(QualifiedModuleName enumModule, VBAParser.EnumerationStmtContext enumerationStmtContext, IMutableParseTreeVisitorResults knownResults)
447449
{
448-
if (knownResults.EnumMembers.Count > 0)
450+
if (knownResults.TryGetEnumMembers(enumerationStmtContext, out var enumMembers))
451+
{
452+
return (enumMembers, knownResults);
453+
}
454+
455+
var resultValues = LoadEnumMemberValues(enumModule, enumerationStmtContext, knownResults);
456+
if (knownResults.TryGetEnumMembers(enumerationStmtContext, out var newEnumMembers))
449457
{
450-
return (knownResults.EnumMembers, knownResults);
458+
return (newEnumMembers, resultValues);
451459
}
452460

453-
var resultValues = LoadEnumMemberValues(_enumStmtContexts, knownResults);
454-
return (resultValues.EnumMembers, resultValues);
461+
return (new List<EnumMember>(), resultValues);
455462
}
456463

457464
//The enum members incrementally to the parse tree visitor result are used within the call to Visit.
458-
private IMutableParseTreeVisitorResults LoadEnumMemberValues(IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> enumStmtContexts, IMutableParseTreeVisitorResults knownResults)
465+
private IMutableParseTreeVisitorResults LoadEnumMemberValues(QualifiedModuleName enumModule, VBAParser.EnumerationStmtContext enumStmt, IMutableParseTreeVisitorResults knownResults)
459466
{
460467
var valueResults = knownResults;
461-
foreach (var qualifiedEnumStmt in enumStmtContexts)
462-
{
463-
var module = qualifiedEnumStmt.ModuleName;
464-
var enumStmt = qualifiedEnumStmt.Context;
465-
long enumAssignedValue = -1;
466-
var enumConstContexts = enumStmt.children
467-
.OfType<VBAParser.EnumerationStmt_ConstantContext>();
468-
foreach (var enumConstContext in enumConstContexts)
468+
long enumAssignedValue = -1;
469+
var enumConstContexts = enumStmt.children
470+
.OfType<VBAParser.EnumerationStmt_ConstantContext>();
471+
foreach (var enumConstContext in enumConstContexts)
472+
{
473+
enumAssignedValue++;
474+
var enumMember = new EnumMember(enumConstContext, enumAssignedValue);
475+
if (enumMember.HasAssignment)
469476
{
470-
enumAssignedValue++;
471-
var enumMember = new EnumMember(enumConstContext, enumAssignedValue);
472-
if (enumMember.HasAssignment)
477+
valueResults = Visit(enumModule, enumMember.ConstantContext, valueResults);
478+
479+
var (valueText, resultValues) = GetConstantContextValueToken(enumModule, enumMember.ConstantContext, valueResults);
480+
valueResults = resultValues;
481+
if (!valueText.Equals(string.Empty))
473482
{
474-
valueResults = Visit(module, enumMember.ConstantContext, valueResults);
475-
476-
var (valueText, resultValues) = GetConstantContextValueToken(module, enumMember.ConstantContext, valueResults);
477-
valueResults = resultValues;
478-
if (!valueText.Equals(string.Empty))
479-
{
480-
enumMember.Value = long.Parse(valueText);
481-
enumAssignedValue = enumMember.Value;
482-
}
483+
enumMember.Value = long.Parse(valueText);
484+
enumAssignedValue = enumMember.Value;
483485
}
484-
valueResults.Add(enumMember);
485486
}
487+
valueResults.AddEnumMember(enumStmt, enumMember);
486488
}
487489

488490
return valueResults;
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
using System;
2-
using System.Collections.Generic;
32
using Antlr4.Runtime;
4-
using Rubberduck.Parsing;
5-
using Rubberduck.Parsing.Grammar;
63
using Rubberduck.Parsing.Symbols;
74
using Rubberduck.VBEditor;
85

96
namespace Rubberduck.Inspections.Concrete.UnreachableCaseInspection
107
{
118
public interface IParseTreeValueVisitorFactory
129
{
13-
IParseTreeValueVisitor Create(IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> allEnums, Func<QualifiedModuleName, ParserRuleContext, (bool success, IdentifierReference idRef)> idRefRetriever);
10+
IParseTreeValueVisitor Create(Func<QualifiedModuleName, ParserRuleContext, (bool success, IdentifierReference idRef)> idRefRetriever);
1411
}
1512

1613
public class ParseTreeValueVisitorFactory : IParseTreeValueVisitorFactory
@@ -22,9 +19,9 @@ public ParseTreeValueVisitorFactory(IParseTreeValueFactory valueFactory)
2219
_valueFactory = valueFactory;
2320
}
2421

25-
public IParseTreeValueVisitor Create(IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> allEnums, Func<QualifiedModuleName, ParserRuleContext, (bool success, IdentifierReference idRef)> identifierReferenceRetriever)
22+
public IParseTreeValueVisitor Create(Func<QualifiedModuleName, ParserRuleContext, (bool success, IdentifierReference idRef)> identifierReferenceRetriever)
2623
{
27-
return new ParseTreeValueVisitor(_valueFactory, allEnums, identifierReferenceRetriever);
24+
return new ParseTreeValueVisitor(_valueFactory, identifierReferenceRetriever);
2825
}
2926
}
3027
}

Rubberduck.CodeAnalysis/Inspections/Concrete/UnreachableCaseInspection/ParseTreeVisitorResults.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using Rubberduck.Parsing.Grammar;
56

67
namespace Rubberduck.Inspections.Concrete.UnreachableCaseInspection
78
{
@@ -13,19 +14,19 @@ public interface IParseTreeVisitorResults
1314
string GetToken(ParserRuleContext context);
1415
bool Contains(ParserRuleContext context);
1516
bool TryGetValue(ParserRuleContext context, out IParseTreeValue value);
16-
IReadOnlyList<EnumMember> EnumMembers { get; }
17+
bool TryGetEnumMembers(VBAParser.EnumerationStmtContext enumerationStmtContext, out IReadOnlyList<EnumMember> enumMembers);
1718
}
1819

1920
public interface IMutableParseTreeVisitorResults : IParseTreeVisitorResults
2021
{
2122
void AddIfNotPresent(ParserRuleContext context, IParseTreeValue value);
22-
void Add(EnumMember enumMember);
23+
void AddEnumMember(VBAParser.EnumerationStmtContext enumerationStmtContext, EnumMember enumMember);
2324
}
2425

2526
public class ParseTreeVisitorResults : IMutableParseTreeVisitorResults
2627
{
2728
private readonly Dictionary<ParserRuleContext, IParseTreeValue> _parseTreeValues = new Dictionary<ParserRuleContext, IParseTreeValue>();
28-
private readonly List<EnumMember> _enumMembers = new List<EnumMember>();
29+
private readonly Dictionary<VBAParser.EnumerationStmtContext, List<EnumMember>> _enumMembers = new Dictionary<VBAParser.EnumerationStmtContext, List<EnumMember>>();
2930

3031
public IParseTreeValue GetValue(ParserRuleContext context)
3132
{
@@ -77,10 +78,29 @@ public void AddIfNotPresent(ParserRuleContext context, IParseTreeValue value)
7778
}
7879
}
7980

80-
public IReadOnlyList<EnumMember> EnumMembers => _enumMembers;
81-
public void Add(EnumMember enumMember)
81+
public bool TryGetEnumMembers(VBAParser.EnumerationStmtContext enumerationStmtContext, out IReadOnlyList<EnumMember> enumMembers)
8282
{
83-
_enumMembers.Add(enumMember);
83+
if (!_enumMembers.TryGetValue(enumerationStmtContext, out var enumMemberList))
84+
{
85+
enumMembers = null;
86+
return false;
87+
}
88+
89+
enumMembers = enumMemberList;
90+
return true;
91+
}
92+
93+
public void AddEnumMember(VBAParser.EnumerationStmtContext enumerationStmtContext, EnumMember enumMember)
94+
{
95+
if (_enumMembers.TryGetValue(enumerationStmtContext, out var enumMemberList))
96+
{
97+
enumMemberList.Add(enumMember);
98+
}
99+
else
100+
{
101+
enumMemberList = new List<EnumMember>{enumMember};
102+
_enumMembers.Add(enumerationStmtContext, enumMemberList);
103+
}
84104
}
85105
}
86106
}

Rubberduck.CodeAnalysis/Inspections/Concrete/UnreachableCaseInspection/UnreachableCaseInspection.cs

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -144,28 +144,27 @@ public UnreachableCaseInspection(IDeclarationFinderProvider declarationFinderPro
144144
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
145145
{
146146
var finder = DeclarationFinderProvider.DeclarationFinder;
147+
var parseTreeValueVisitor = CreateParseTreeValueVisitor(GetIdentifierReferenceForContextFunction(finder));
147148

148149
return finder.UserDeclarations(DeclarationType.Module)
149150
.Where(module => module != null)
150-
.SelectMany(module => DoGetInspectionResults(module.QualifiedModuleName, finder))
151+
.SelectMany(module => DoGetInspectionResults(module.QualifiedModuleName, finder, parseTreeValueVisitor))
151152
.ToList();
152153
}
153154

154155
protected override IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module)
155156
{
156157
var finder = DeclarationFinderProvider.DeclarationFinder;
157-
return DoGetInspectionResults(module, finder);
158+
var parseTreeValueVisitor = CreateParseTreeValueVisitor(GetIdentifierReferenceForContextFunction(finder));
159+
return DoGetInspectionResults(module, finder, parseTreeValueVisitor);
158160
}
159161

160-
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module, DeclarationFinder finder)
162+
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module, DeclarationFinder finder, IParseTreeValueVisitor parseTreeValueVisitor)
161163
{
162164
var qualifiedSelectCaseStmts = Listener.Contexts(module)
163165
// ignore filtering here to make the search space smaller
164166
.Where(result => !result.IsIgnoringInspectionResultFor(finder, AnnotationName));
165167

166-
var enumStmts = _listener.EnumerationStmtContexts();
167-
var parseTreeValueVisitor = CreateParseTreeValueVisitor(enumStmts, GetIdentifierReferenceForContextFunction(finder));
168-
169168
return qualifiedSelectCaseStmts
170169
.SelectMany(context => ResultsForContext(context, finder, parseTreeValueVisitor))
171170
.ToList();
@@ -216,11 +215,9 @@ private IInspectionResult CreateInspectionResult(QualifiedContext<ParserRuleCont
216215
new QualifiedContext<ParserRuleContext>(selectStmt.ModuleName, unreachableBlock));
217216
}
218217

219-
public IParseTreeValueVisitor CreateParseTreeValueVisitor(
220-
IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> allEnums,
221-
Func<QualifiedModuleName, ParserRuleContext, (bool success, IdentifierReference idRef)> func)
218+
public IParseTreeValueVisitor CreateParseTreeValueVisitor(Func<QualifiedModuleName, ParserRuleContext, (bool success, IdentifierReference idRef)> func)
222219
{
223-
return _parseTreeValueVisitorFactory.Create(allEnums, func);
220+
return _parseTreeValueVisitorFactory.Create(func);
224221
}
225222

226223
private Func<QualifiedModuleName, ParserRuleContext,(bool success, IdentifierReference reference)> GetIdentifierReferenceForContextFunction(DeclarationFinder finder)
@@ -291,48 +288,12 @@ private string GetBaseTypeForDeclaration(Declaration declaration)
291288
return localDeclaration is null ? declaration.AsTypeName : localDeclaration.AsTypeName;
292289
}
293290

294-
#region UnreachableCaseInspectionListeners
295291
public class UnreachableCaseInspectionListener : InspectionListenerBase
296292
{
297-
private readonly IDictionary<QualifiedModuleName, List<QualifiedContext<VBAParser.EnumerationStmtContext>>> _enumStmts = new Dictionary<QualifiedModuleName, List<QualifiedContext<VBAParser.EnumerationStmtContext>>>();
298-
public IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> EnumerationStmtContexts() => _enumStmts.AllValues().ToList();
299-
300-
public override void ClearContexts()
301-
{
302-
_enumStmts.Clear();
303-
base.ClearContexts();
304-
}
305-
306-
public override void ClearContexts(QualifiedModuleName module)
307-
{
308-
_enumStmts.Remove(module);
309-
base.ClearContexts(module);
310-
}
311-
312293
public override void EnterSelectCaseStmt([NotNull] VBAParser.SelectCaseStmtContext context)
313294
{
314295
SaveContext(context);
315296
}
316-
317-
public override void EnterEnumerationStmt([NotNull] VBAParser.EnumerationStmtContext context)
318-
{
319-
SaveEnumStmt(context);
320-
}
321-
322-
private void SaveEnumStmt(VBAParser.EnumerationStmtContext context)
323-
{
324-
var module = CurrentModuleName;
325-
var qualifiedContext = new QualifiedContext<VBAParser.EnumerationStmtContext>(module, context);
326-
if (_enumStmts.TryGetValue(module, out var stmts))
327-
{
328-
stmts.Add(qualifiedContext);
329-
}
330-
else
331-
{
332-
_enumStmts.Add(module, new List<QualifiedContext<VBAParser.EnumerationStmtContext>> { qualifiedContext });
333-
}
334-
}
335297
}
336-
#endregion
337298
}
338299
}

0 commit comments

Comments
 (0)