Skip to content

Commit dbfbe6d

Browse files
committed
Some performance improvements for the ShadowedDeclarationsInspection
1 parent b69ddcb commit dbfbe6d

File tree

1 file changed

+56
-64
lines changed

1 file changed

+56
-64
lines changed

Rubberduck.Inspections/Concrete/ShadowedDeclarationInspection.cs

Lines changed: 56 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,24 @@ private enum DeclarationSite
2828
SameComponent = 3
2929
}
3030

31-
private class OptionPrivateModuleListener : VBAParserBaseListener
32-
{
33-
public List<VBAParser.ModuleContext> OptionPrivateModules { get; } = new List<VBAParser.ModuleContext>();
34-
35-
public override void EnterModule(VBAParser.ModuleContext context)
36-
{
37-
if (context.FindChildren<VBAParser.OptionPrivateModuleStmtContext>().Any())
38-
{
39-
OptionPrivateModules.Add(context);
40-
}
41-
}
42-
}
43-
4431
private class EnumerationRuleIndexListener : VBAParserBaseListener
4532
{
4633
public Dictionary<ParserRuleContext, int> DeclarationIndexes { get; } = new Dictionary<ParserRuleContext, int>();
4734

4835
public override void EnterEnumerationStmt(VBAParser.EnumerationStmtContext context)
4936
{
50-
DeclarationIndexes.Add(context, context.Start.TokenIndex);
37+
if (!DeclarationIndexes.ContainsKey(context))
38+
{
39+
DeclarationIndexes.Add(context, context.Start.TokenIndex);
40+
}
5141
}
5242

5343
public override void EnterEnumerationStmt_Constant(VBAParser.EnumerationStmt_ConstantContext context)
5444
{
55-
DeclarationIndexes.Add(context, context.Start.TokenIndex);
45+
if (!DeclarationIndexes.ContainsKey(context))
46+
{
47+
DeclarationIndexes.Add(context, context.Start.TokenIndex);
48+
}
5649
}
5750
}
5851

@@ -66,50 +59,37 @@ public ShadowedDeclarationInspection(RubberduckParserState state) : base(state,
6659

6760
public override IEnumerable<IInspectionResult> GetInspectionResults()
6861
{
69-
var optionPrivateModuleListener = new OptionPrivateModuleListener();
70-
var enumerationRuleIndexListener = new EnumerationRuleIndexListener();
71-
72-
foreach (var module in State.DeclarationFinder.AllModules.Where(m => m.ComponentType == ComponentType.StandardModule))
73-
{
74-
ParseTreeWalker.Default.Walk(optionPrivateModuleListener, State.GetParseTree(module));
75-
}
76-
77-
foreach (var module in State.AllUserDeclarations.Where(d => d.DeclarationType == DeclarationType.ProceduralModule || d.DeclarationType == DeclarationType.ClassModule))
78-
{
79-
ParseTreeWalker.Default.Walk(enumerationRuleIndexListener, State.GetParseTree(module.QualifiedName.QualifiedModuleName));
80-
}
81-
8262
var builtInEventHandlers = State.DeclarationFinder.FindEventHandlers().ToHashSet();
8363

8464
var issues = new List<IInspectionResult>();
8565

86-
var allUserProjects = UserDeclarations.OfType(DeclarationType.Project).Cast<ProjectDeclaration>();
66+
var allUserProjects = State.DeclarationFinder.UserDeclarations(DeclarationType.Project).Cast<ProjectDeclaration>();
8767

8868
foreach (var userProject in allUserProjects)
8969
{
9070
var referencedProjectIds = userProject.ProjectReferences.Select(reference => reference.ReferencedProjectId).ToHashSet();
9171

92-
var userDeclarations = UserDeclarations.Where(d =>
93-
d.ProjectId == userProject.ProjectId &&
72+
var userDeclarations = UserDeclarations.Where(declaration =>
73+
declaration.ProjectId == userProject.ProjectId &&
9474
// User has no control over build-in event handlers or their parameters, so we skip them
95-
!DeclarationIsPartOfBuiltInEventHandler(d, builtInEventHandlers));
75+
!DeclarationIsPartOfBuiltInEventHandler(declaration, builtInEventHandlers));
9676

97-
foreach (var declaration in userDeclarations)
77+
foreach (var userDeclaration in userDeclarations)
9878
{
99-
var shadowedDeclaration = State.AllDeclarations.FirstOrDefault(d =>
100-
!Equals(d, declaration) &&
101-
string.Equals(d.IdentifierName, declaration.IdentifierName, StringComparison.OrdinalIgnoreCase) &&
102-
DeclarationCanBeShadowed(d, declaration, GetDeclarationSite(d, declaration, referencedProjectIds), optionPrivateModuleListener, enumerationRuleIndexListener));
79+
var shadowedDeclaration = State.DeclarationFinder
80+
.MatchName(userDeclaration.IdentifierName).FirstOrDefault(declaration =>
81+
!declaration.Equals(userDeclaration) &&
82+
DeclarationCanBeShadowed(declaration, userDeclaration, GetDeclarationSite(declaration, userDeclaration, referencedProjectIds)));
10383

10484
if (shadowedDeclaration != null)
10585
{
10686
issues.Add(new DeclarationInspectionResult(this,
10787
string.Format(InspectionsUI.ShadowedDeclarationInspectionResultFormat,
108-
RubberduckUI.ResourceManager.GetString("DeclarationType_" + declaration.DeclarationType, CultureInfo.CurrentUICulture),
109-
declaration.IdentifierName,
88+
RubberduckUI.ResourceManager.GetString("DeclarationType_" + userDeclaration.DeclarationType, CultureInfo.CurrentUICulture),
89+
userDeclaration.IdentifierName,
11090
RubberduckUI.ResourceManager.GetString("DeclarationType_" + shadowedDeclaration.DeclarationType, CultureInfo.CurrentUICulture),
11191
shadowedDeclaration.IdentifierName),
112-
declaration));
92+
userDeclaration));
11393
}
11494
}
11595
}
@@ -124,7 +104,7 @@ private static DeclarationSite GetDeclarationSite(Declaration originalDeclaratio
124104
return referencedProjectIds.Contains(originalDeclaration.ProjectId) ? DeclarationSite.ReferencedProject : DeclarationSite.NotApplicable;
125105
}
126106

127-
if (originalDeclaration.QualifiedName.QualifiedModuleName.Name != userDeclaration.QualifiedName.QualifiedModuleName.Name)
107+
if (originalDeclaration.QualifiedName.QualifiedModuleName.ComponentName != userDeclaration.QualifiedName.QualifiedModuleName.ComponentName)
128108
{
129109
return DeclarationSite.OtherComponent;
130110
}
@@ -144,8 +124,7 @@ private static bool DeclarationIsPartOfBuiltInEventHandler(Declaration declarati
144124
return parameterDeclaration != null && builtInEventHandlers.Contains(parameterDeclaration.ParentDeclaration);
145125
}
146126

147-
private static bool DeclarationCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration, DeclarationSite originalDeclarationSite,
148-
OptionPrivateModuleListener optionPrivateModuleListener, EnumerationRuleIndexListener enumerationRuleIndexListener)
127+
private bool DeclarationCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration, DeclarationSite originalDeclarationSite)
149128
{
150129
if (originalDeclarationSite == DeclarationSite.NotApplicable)
151130
{
@@ -154,20 +133,20 @@ private static bool DeclarationCanBeShadowed(Declaration originalDeclaration, De
154133

155134
if (originalDeclarationSite == DeclarationSite.ReferencedProject)
156135
{
157-
return DeclarationInReferencedProjectCanBeShadowed(originalDeclaration, userDeclaration, optionPrivateModuleListener);
136+
return DeclarationInReferencedProjectCanBeShadowed(originalDeclaration, userDeclaration);
158137
}
159138

160139
if (originalDeclarationSite == DeclarationSite.OtherComponent)
161140
{
162-
return DeclarationInAnotherComponentCanBeShadowed(originalDeclaration, userDeclaration, optionPrivateModuleListener);
141+
return DeclarationInAnotherComponentCanBeShadowed(originalDeclaration, userDeclaration);
163142
}
164143

165-
return DeclarationInTheSameComponentCanBeShadowed(originalDeclaration, userDeclaration, enumerationRuleIndexListener);
144+
return DeclarationInTheSameComponentCanBeShadowed(originalDeclaration, userDeclaration);
166145
}
167146

168-
private static bool DeclarationInReferencedProjectCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration, OptionPrivateModuleListener listener)
147+
private bool DeclarationInReferencedProjectCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration)
169148
{
170-
if (DeclarationIsInsideOptionPrivateModule(originalDeclaration, listener))
149+
if (DeclarationIsInsideOptionPrivateModule(originalDeclaration))
171150
{
172151
return false;
173152
}
@@ -231,9 +210,9 @@ private static bool DeclarationInReferencedProjectCanBeShadowed(Declaration orig
231210
return DeclarationAccessibilityCanBeShadowed(originalDeclaration);
232211
}
233212

234-
private static bool DeclarationInAnotherComponentCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration, OptionPrivateModuleListener listener)
213+
private static bool DeclarationInAnotherComponentCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration)
235214
{
236-
if (DeclarationIsInsideOptionPrivateModule(originalDeclaration, listener))
215+
if (DeclarationIsInsideOptionPrivateModule(originalDeclaration))
237216
{
238217
return false;
239218
}
@@ -292,7 +271,7 @@ private static bool DeclarationInAnotherComponentCanBeShadowed(Declaration origi
292271
return DeclarationAccessibilityCanBeShadowed(originalDeclaration);
293272
}
294273

295-
private static bool DeclarationInTheSameComponentCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration, EnumerationRuleIndexListener listener)
274+
private bool DeclarationInTheSameComponentCanBeShadowed(Declaration originalDeclaration, Declaration userDeclaration)
296275
{
297276
// Shadowing the component containing the declaration is not a problem, because it is possible to directly access declarations inside that component
298277
if (originalDeclaration.DeclarationType == DeclarationType.ProceduralModule || originalDeclaration.DeclarationType == DeclarationType.ClassModule ||
@@ -323,18 +302,31 @@ private static bool DeclarationInTheSameComponentCanBeShadowed(Declaration origi
323302
{
324303
return DeclarationIsLocal(userDeclaration);
325304
}
326-
327-
if (listener.DeclarationIndexes.ContainsKey(originalDeclaration.Context) && listener.DeclarationIndexes.ContainsKey(userDeclaration.Context))
305+
306+
// Shadowing between two enumerations or enumeration members is not possible inside one component.
307+
if (((originalDeclaration.DeclarationType == DeclarationType.Enumeration
308+
&& userDeclaration.DeclarationType == DeclarationType.EnumerationMember)
309+
|| (originalDeclaration.DeclarationType == DeclarationType.EnumerationMember
310+
&& userDeclaration.DeclarationType == DeclarationType.Enumeration)))
328311
{
329-
var originalDeclarationIndex = listener.DeclarationIndexes[originalDeclaration.Context];
330-
var userDeclarationIndex = listener.DeclarationIndexes[userDeclaration.Context];
312+
var listener = new EnumerationRuleIndexListener();
313+
if (!listener.DeclarationIndexes.ContainsKey(originalDeclaration.Context))
314+
{
315+
ParseTreeWalker.Default.Walk(listener,
316+
State.GetParseTree(originalDeclaration.QualifiedName.QualifiedModuleName));
317+
}
331318

332-
// The same declaration type means that both declarations are enumerations or enumeration members, and such shadowing is not possible inside one component
333-
return originalDeclaration.DeclarationType != userDeclaration.DeclarationType &&
334-
// First declaration wins
335-
originalDeclarationIndex > userDeclarationIndex &&
336-
// Enumeration member can have the same name as enclosing enumeration
337-
!Equals(originalDeclaration.ParentDeclaration, userDeclaration);
319+
if (listener.DeclarationIndexes.ContainsKey(originalDeclaration.Context) &&
320+
listener.DeclarationIndexes.ContainsKey(userDeclaration.Context))
321+
{
322+
var originalDeclarationIndex = listener.DeclarationIndexes[originalDeclaration.Context];
323+
var userDeclarationIndex = listener.DeclarationIndexes[userDeclaration.Context];
324+
325+
// First declaration wins
326+
return originalDeclarationIndex > userDeclarationIndex
327+
// Enumeration member can have the same name as enclosing enumeration
328+
&& !userDeclaration.Equals(originalDeclaration.ParentDeclaration);
329+
}
338330
}
339331

340332
// Events don't have a body, so their parameters can't be accessed
@@ -355,20 +347,20 @@ private static bool DeclarationAccessibilityCanBeShadowed(Declaration originalDe
355347
(originalDeclaration.DeclarationType == DeclarationType.EnumerationMember && originalDeclaration.ParentDeclaration.Accessibility == Accessibility.Public);
356348
}
357349

358-
private static bool DeclarationIsInsideOptionPrivateModule(Declaration declaration, OptionPrivateModuleListener listener)
350+
private static bool DeclarationIsInsideOptionPrivateModule(Declaration declaration)
359351
{
360352
if (declaration.QualifiedName.QualifiedModuleName.ComponentType != ComponentType.StandardModule)
361353
{
362354
return false;
363355
}
364356

365-
var moduleDeclaration = declaration as ProceduralModuleDeclaration;
357+
var moduleDeclaration = Declaration.GetModuleParent(declaration) as ProceduralModuleDeclaration;
366358
if (moduleDeclaration != null)
367359
{
368360
return moduleDeclaration.IsPrivateModule;
369361
}
370362

371-
return listener.OptionPrivateModules.Any(moduleContext => ParserRuleContextHelper.HasParent(declaration.Context, moduleContext));
363+
return false;
372364
}
373365

374366
private static bool DeclarationIsProjectOrComponent(Declaration declaration)

0 commit comments

Comments
 (0)