Skip to content

Commit e5efb48

Browse files
committed
Pass declaration finder along in UnreacableCaseInspection
1 parent 04aa262 commit e5efb48

File tree

3 files changed

+67
-44
lines changed

3 files changed

+67
-44
lines changed

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

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -144,38 +144,38 @@ public UnreachableCaseInspection(IDeclarationFinderProvider declarationFinderPro
144144
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
145145
{
146146
var finder = DeclarationFinderProvider.DeclarationFinder;
147-
var enumStmts = _listener.EnumerationStmtContexts();
148-
var parseTreeValueVisitor = CreateParseTreeValueVisitor(enumStmts, GetIdentifierReferenceForContext);
149147

150148
return finder.UserDeclarations(DeclarationType.Module)
151149
.Where(module => module != null)
152-
.SelectMany(module => DoGetInspectionResults(module.QualifiedModuleName, finder, parseTreeValueVisitor))
150+
.SelectMany(module => DoGetInspectionResults(module.QualifiedModuleName, finder))
153151
.ToList();
154152
}
155153

156154
protected override IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module)
157155
{
158156
var finder = DeclarationFinderProvider.DeclarationFinder;
159-
var enumStmts = _listener.EnumerationStmtContexts();
160-
var parseTreeValueVisitor = CreateParseTreeValueVisitor(enumStmts, GetIdentifierReferenceForContext);
161-
return DoGetInspectionResults(module, finder, parseTreeValueVisitor);
157+
return DoGetInspectionResults(module, finder);
162158
}
163159

164-
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module, DeclarationFinder finder, IParseTreeValueVisitor parseTreeValueVisitor)
160+
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module, DeclarationFinder finder)
165161
{
166162
var qualifiedSelectCaseStmts = Listener.Contexts(module)
167163
// ignore filtering here to make the search space smaller
168164
.Where(result => !result.IsIgnoringInspectionResultFor(finder, AnnotationName));
169165

166+
var enumStmts = _listener.EnumerationStmtContexts();
167+
var parseTreeValueVisitor = CreateParseTreeValueVisitor(enumStmts, context => GetIdentifierReferenceForContextFunction(finder)(module, context));
168+
170169
return qualifiedSelectCaseStmts
171170
.SelectMany(context => ResultsForContext(context, finder, parseTreeValueVisitor))
172171
.ToList();
173172
}
174173

175174
private IEnumerable<IInspectionResult> ResultsForContext(QualifiedContext<ParserRuleContext> qualifiedSelectCaseStmt, DeclarationFinder finder, IParseTreeValueVisitor parseTreeValueVisitor)
176175
{
177-
var contextValues = qualifiedSelectCaseStmt.Context.Accept(parseTreeValueVisitor);
178-
var selectCaseInspector = _unreachableCaseInspectorFactory.Create((VBAParser.SelectCaseStmtContext)qualifiedSelectCaseStmt.Context, contextValues, GetVariableTypeName);
176+
var module = qualifiedSelectCaseStmt.ModuleName;
177+
var contextValues = parseTreeValueVisitor.VisitChildren(qualifiedSelectCaseStmt.Context);
178+
var selectCaseInspector = _unreachableCaseInspectorFactory.Create((VBAParser.SelectCaseStmtContext)qualifiedSelectCaseStmt.Context, contextValues, GetVariableTypeNameFunction(module, finder));
179179

180180
var results = selectCaseInspector.InspectForUnreachableCases();
181181

@@ -216,28 +216,33 @@ private IInspectionResult CreateInspectionResult(QualifiedContext<ParserRuleCont
216216
new QualifiedContext<ParserRuleContext>(selectStmt.ModuleName, unreachableBlock));
217217
}
218218

219-
public IParseTreeValueVisitor CreateParseTreeValueVisitor(IReadOnlyList<VBAParser.EnumerationStmtContext> allEnums, Func<ParserRuleContext, (bool success, IdentifierReference idRef)> func)
220-
=> _parseTreeValueVisitorFactory.Create(allEnums, func);
219+
public IParseTreeValueVisitor CreateParseTreeValueVisitor(
220+
IReadOnlyList<QualifiedContext<VBAParser.EnumerationStmtContext>> allEnums,
221+
Func<ParserRuleContext, (bool success, IdentifierReference idRef)> func)
222+
{
223+
var enums = allEnums.Select(item => item.Context).ToList();
224+
return _parseTreeValueVisitorFactory.Create(enums, func);
225+
}
221226

222-
//Method is used as a delegate to avoid propagating RubberduckParserState beyond this class
223-
private (bool success, IdentifierReference idRef) GetIdentifierReferenceForContext(ParserRuleContext context)
227+
private Func<QualifiedModuleName, ParserRuleContext,(bool success, IdentifierReference idRef)> GetIdentifierReferenceForContextFunction(DeclarationFinder finder)
224228
{
225-
return GetIdentifierReferenceForContext(context, DeclarationFinderProvider);
229+
return (module, context) => GetIdentifierReferenceForContext(module, context, finder);
226230
}
227231

228232
//public static to support tests
229233
//FIXME There should not be additional public methods just for tests. This class seems to want to be split or at least reorganized.
230-
public static (bool success, IdentifierReference idRef) GetIdentifierReferenceForContext(ParserRuleContext context, IDeclarationFinderProvider declarationFinderProvider)
234+
public static (bool success, IdentifierReference idRef) GetIdentifierReferenceForContext(QualifiedModuleName module, ParserRuleContext context, DeclarationFinder finder)
231235
{
232236
if (context == null)
233237
{
234238
return (false, null);
235239
}
236240

237-
//FIXME Get the declaration finder only once inside the inspection to avoid the possibility of inconsistent state due to a reparse while inspections run.
238-
var finder = declarationFinderProvider.DeclarationFinder;
239-
var identifierReferences = finder.MatchName(context.GetText())
240-
.SelectMany(declaration => declaration.References)
241+
var qualifiedSelection = new QualifiedSelection(module, context.GetSelection());
242+
243+
var identifierReferences =
244+
finder
245+
.IdentifierReferences(qualifiedSelection)
241246
.Where(reference => reference.Context == context)
242247
.ToList();
243248

@@ -246,19 +251,31 @@ public static (bool success, IdentifierReference idRef) GetIdentifierReferenceFo
246251
: (false, null);
247252
}
248253

249-
//Method is used as a delegate to avoid propogating RubberduckParserState beyond this class
250-
private string GetVariableTypeName(string variableName, ParserRuleContext ancestor)
254+
private Func<string, ParserRuleContext, string> GetVariableTypeNameFunction(QualifiedModuleName module, DeclarationFinder finder)
251255
{
252-
var descendents = ancestor.GetDescendents<VBAParser.SimpleNameExprContext>().Where(desc => desc.GetText().Equals(variableName)).ToList();
253-
if (descendents.Any())
256+
return (variableName, ancestor) => GetVariableTypeName(module, variableName, ancestor, finder);
257+
}
258+
259+
private string GetVariableTypeName(QualifiedModuleName module, string variableName, ParserRuleContext ancestor, DeclarationFinder finder)
260+
{
261+
if (ancestor == null)
254262
{
255-
(bool success, IdentifierReference idRef) = GetIdentifierReferenceForContext(descendents.First(), DeclarationFinderProvider);
256-
if (success)
257-
{
258-
return GetBaseTypeForDeclaration(idRef.Declaration);
259-
}
263+
return string.Empty;
264+
}
265+
266+
var descendents = ancestor.GetDescendents<VBAParser.SimpleNameExprContext>()
267+
.Where(desc => desc.GetText().Equals(variableName))
268+
.ToList();
269+
if (!descendents.Any())
270+
{
271+
return string.Empty;
260272
}
261-
return string.Empty;
273+
274+
var firstDescendent = descendents.First();
275+
var (success, reference) = GetIdentifierReferenceForContext(module, firstDescendent, finder);
276+
return success ?
277+
GetBaseTypeForDeclaration(reference.Declaration)
278+
: string.Empty;
262279
}
263280

264281
private string GetBaseTypeForDeclaration(Declaration declaration)
@@ -277,8 +294,8 @@ private string GetBaseTypeForDeclaration(Declaration declaration)
277294
#region UnreachableCaseInspectionListeners
278295
public class UnreachableCaseInspectionListener : InspectionListenerBase
279296
{
280-
private readonly IDictionary<QualifiedModuleName, List<VBAParser.EnumerationStmtContext>> _enumStmts = new Dictionary<QualifiedModuleName, List<VBAParser.EnumerationStmtContext>>();
281-
public IReadOnlyList<VBAParser.EnumerationStmtContext> EnumerationStmtContexts() => _enumStmts.AllValues().ToList();
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();
282299

283300
public override void ClearContexts()
284301
{
@@ -305,13 +322,14 @@ public override void EnterEnumerationStmt([NotNull] VBAParser.EnumerationStmtCon
305322
private void SaveEnumStmt(VBAParser.EnumerationStmtContext context)
306323
{
307324
var module = CurrentModuleName;
325+
var qualifiedContext = new QualifiedContext<VBAParser.EnumerationStmtContext>(module, context);
308326
if (_enumStmts.TryGetValue(module, out var stmts))
309327
{
310-
stmts.Add(context);
328+
stmts.Add(qualifiedContext);
311329
}
312330
else
313331
{
314-
_enumStmts.Add(module, new List<VBAParser.EnumerationStmtContext> { context });
332+
_enumStmts.Add(module, new List<QualifiedContext<VBAParser.EnumerationStmtContext>> { qualifiedContext });
315333
}
316334
}
317335
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public class UnreachableCaseInspector : IUnreachableCaseInspector
2121
private readonly Func<string, ParserRuleContext, string> _getVariableDeclarationTypeName;
2222
private IParseTreeValue _selectExpressionValue;
2323

24-
public UnreachableCaseInspector(VBAParser.SelectCaseStmtContext selectCaseContext,
24+
public UnreachableCaseInspector(
25+
VBAParser.SelectCaseStmtContext selectCaseContext,
2526
IParseTreeVisitorResults inspValues,
2627
IParseTreeValueFactory valueFactory,
2728
Func<string,ParserRuleContext,string> getVariableTypeName = null)

RubberduckTests/Inspections/UnreachableCase/UnreachableCaseInspectionTests.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
using System.Collections.Generic;
1414
using System.Linq;
1515
using System.Threading;
16+
using Antlr4.Runtime.Tree;
1617
using Moq;
18+
using Rubberduck.Parsing.VBA.Parsing;
19+
using Rubberduck.VBEditor;
20+
using Rubberduck.VBEditor.Extensions;
1721

1822
namespace RubberduckTests.Inspections.UnreachableCase
1923
{
@@ -2461,8 +2465,8 @@ End Sub
24612465
var factoryProvider = SpecialValueDeclarationEvaluatorFactoryProvider(TestGetValuedDeclaration);
24622466
var inspection = new UnreachableCaseInspection(state, factoryProvider);
24632467

2464-
var inspector = InspectionsHelper.GetInspector(inspection);
2465-
actualResults = inspector.FindIssuesAsync(state, CancellationToken.None).Result;
2468+
WalkTrees(inspection, state);
2469+
actualResults = inspection.GetInspectionResults(CancellationToken.None);
24662470
}
24672471

24682472
var actualUnreachable = actualResults.Where(ar => ar.Description.Equals(Rubberduck.Resources.Inspections.InspectionResults.UnreachableCaseInspection_Unreachable));
@@ -2513,8 +2517,8 @@ End Sub
25132517
var factoryProvider = SpecialValueDeclarationEvaluatorFactoryProvider(TestGetValuedDeclaration);
25142518
var inspection = new UnreachableCaseInspection(state, factoryProvider);
25152519

2516-
var inspector = InspectionsHelper.GetInspector(inspection);
2517-
actualResults = inspector.FindIssuesAsync(state, CancellationToken.None).Result;
2520+
WalkTrees(inspection, state);
2521+
actualResults = inspection.GetInspectionResults(CancellationToken.None);
25182522
}
25192523

25202524
var actualUnreachable = actualResults.Where(ar => ar.Description.Equals(Rubberduck.Resources.Inspections.InspectionResults.UnreachableCaseInspection_Unreachable));
@@ -2631,14 +2635,14 @@ private IParseTreeVisitorResults GetParseTreeValueResults(string inputCode, out
26312635
var vbe = MockVbeBuilder.BuildFromSingleStandardModule(inputCode, out var _);
26322636
using (var state = MockParser.CreateAndParse(vbe.Object))
26332637
{
2634-
var firstParserRuleContext = (ParserRuleContext)state.ParseTrees
2635-
.First(pt => pt.Value is ParserRuleContext)
2636-
.Value;
2637-
selectStmt = firstParserRuleContext.GetDescendent<VBAParser.SelectCaseStmtContext>();
2638+
var finder = state.DeclarationFinder;
2639+
var (parseTreeModule, moduleParseTree) = state.ParseTrees
2640+
.First(pt => pt.Value is ParserRuleContext);
2641+
selectStmt = ((ParserRuleContext)moduleParseTree).GetDescendent<VBAParser.SelectCaseStmtContext>();
26382642
var visitor = ParseTreeValueVisitorFactory.Create(
26392643
new List<VBAParser.EnumerationStmtContext>(),
2640-
context => UnreachableCaseInspection.GetIdentifierReferenceForContext(context, state));
2641-
valueResults = selectStmt.Accept(visitor);
2644+
(context) => UnreachableCaseInspection.GetIdentifierReferenceForContext(parseTreeModule, context, finder));
2645+
valueResults = visitor.VisitChildren(selectStmt);
26422646
}
26432647
return valueResults;
26442648
}

0 commit comments

Comments
 (0)