Skip to content

Commit 280f29f

Browse files
authored
Merge pull request #2810 from MDoerner/TestsFor2737
Tests for 2737
2 parents cd8202f + 7161698 commit 280f29f

File tree

4 files changed

+108
-47
lines changed

4 files changed

+108
-47
lines changed

Rubberduck.Parsing/Symbols/DeclarationFinder.cs

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ public class DeclarationFinder
5252
private readonly Lazy<ConcurrentDictionary<Declaration, Declaration[]>> _handlersByWithEventsField;
5353
private readonly Lazy<ConcurrentDictionary<VBAParser.ImplementsStmtContext, Declaration[]>> _membersByImplementsContext;
5454
private readonly Lazy<ConcurrentDictionary<Declaration, Declaration[]>> _interfaceMembers;
55+
private Lazy<List<Declaration>> _nonBaseAsType;
56+
private readonly Lazy<ConcurrentBag<Declaration>> _eventHandlers;
57+
private readonly Lazy<ConcurrentBag<Declaration>> _classes;
5558

56-
private static readonly object ThreadLock = new object();
59+
private readonly object threadLock = new object();
5760

5861
public DeclarationFinder(IReadOnlyList<Declaration> declarations, IEnumerable<IAnnotation> annotations, IReadOnlyList<UnboundMemberDeclaration> unresolvedMemberDeclarations, IHostApplication hostApp = null)
5962
{
@@ -133,8 +136,16 @@ public DeclarationFinder(IReadOnlyList<Declaration> declarations, IEnumerable<IA
133136
});
134137

135138
_membersByImplementsContext = new Lazy<ConcurrentDictionary<VBAParser.ImplementsStmtContext, Declaration[]>>(() =>
136-
new ConcurrentDictionary<VBAParser.ImplementsStmtContext, Declaration[]>(
137-
implementableMembers.ToDictionary(item => item.Context, item => item.Members)), true);
139+
new ConcurrentDictionary<VBAParser.ImplementsStmtContext, Declaration[]>(
140+
implementableMembers.ToDictionary(item => item.Context, item => item.Members)), true);
141+
142+
_nonBaseAsType = new Lazy<List<Declaration>>(() =>
143+
_declarations.AllValues().Where(d =>
144+
!string.IsNullOrWhiteSpace(d.AsTypeName)
145+
&& !d.AsTypeIsBaseType
146+
&& d.DeclarationType != DeclarationType.Project
147+
&& d.DeclarationType != DeclarationType.ProceduralModule).ToList()
148+
,true);
138149
}
139150

140151
public IEnumerable<Declaration> FreshUndeclared
@@ -152,38 +163,22 @@ public IEnumerable<Declaration> Members(QualifiedModuleName module)
152163
return _declarations[module];
153164
}
154165

155-
private IEnumerable<Declaration> _nonBaseAsType;
156166
public IEnumerable<Declaration> FindDeclarationsWithNonBaseAsType()
157167
{
158-
lock (ThreadLock)
159-
{
160-
return _nonBaseAsType ?? (_nonBaseAsType = _declarations.AllValues().Where(d =>
161-
!string.IsNullOrWhiteSpace(d.AsTypeName)
162-
&& !d.AsTypeIsBaseType
163-
&& d.DeclarationType != DeclarationType.Project
164-
&& d.DeclarationType != DeclarationType.ProceduralModule).ToList());
165-
}
166-
}
168+
return _nonBaseAsType.Value;
167169

168-
private readonly Lazy<ConcurrentBag<Declaration>> _eventHandlers;
170+
}
171+
169172
public IEnumerable<Declaration> FindEventHandlers()
170173
{
171-
lock (ThreadLock)
172-
{
173-
return _eventHandlers.Value;
174-
}
174+
return _eventHandlers.Value;
175175
}
176176

177-
private readonly Lazy<ConcurrentBag<Declaration>> _classes;
178-
179177
public IEnumerable<Declaration> Classes
180178
{
181179
get
182180
{
183-
lock (ThreadLock)
184-
{
185-
return _classes.Value;
186-
}
181+
return _classes.Value;
187182
}
188183
}
189184

@@ -193,10 +188,7 @@ public IEnumerable<Declaration> Projects
193188
{
194189
get
195190
{
196-
lock (ThreadLock)
197-
{
198-
return _projects.Value;
199-
}
191+
return _projects.Value;
200192
}
201193
}
202194

@@ -214,10 +206,7 @@ public IEnumerable<Declaration> UserDeclarations(DeclarationType type)
214206

215207
public IEnumerable<UnboundMemberDeclaration> FreshUnresolvedMemberDeclarations()
216208
{
217-
lock (ThreadLock)
218-
{
219-
return _newUnresolved.ToArray();
220-
}
209+
return _newUnresolved.ToArray(); //This does not need a lock because enumerators over a ConcurrentBag uses a snapshot.
221210
}
222211

223212
public IEnumerable<UnboundMemberDeclaration> UnresolvedMemberDeclarations()
@@ -259,19 +248,18 @@ public Declaration FindParameter(Declaration procedure, string parameterName)
259248
public IEnumerable<Declaration> FindMemberMatches(Declaration parent, string memberName)
260249
{
261250
ConcurrentBag<Declaration> children;
262-
if (_declarations.TryGetValue(parent.QualifiedName.QualifiedModuleName, out children))
263-
{
264-
return children.Where(item => item.DeclarationType.HasFlag(DeclarationType.Member)
265-
&& item.IdentifierName == memberName).ToList();
266-
}
267-
268-
return Enumerable.Empty<Declaration>();
251+
return _declarations.TryGetValue(parent.QualifiedName.QualifiedModuleName, out children)
252+
? children.Where(item => item.DeclarationType.HasFlag(DeclarationType.Member)
253+
&& item.IdentifierName == memberName).ToList()
254+
: Enumerable.Empty<Declaration>();
269255
}
270256

271257
public IEnumerable<IAnnotation> FindAnnotations(QualifiedModuleName module)
272258
{
273259
ConcurrentBag<IAnnotation> result;
274-
return _annotations.TryGetValue(module, out result) ? result : Enumerable.Empty<IAnnotation>();
260+
return _annotations.TryGetValue(module, out result)
261+
? result
262+
: Enumerable.Empty<IAnnotation>();
275263
}
276264

277265
public bool IsMatch(string declarationName, string potentialMatchName)
@@ -326,7 +314,8 @@ public Declaration FindProject(string name, Declaration currentScope = null)
326314
Declaration result = null;
327315
try
328316
{
329-
result = MatchName(name).SingleOrDefault(project => project.DeclarationType.HasFlag(DeclarationType.Project)
317+
result = MatchName(name).SingleOrDefault(project =>
318+
project.DeclarationType.HasFlag(DeclarationType.Project)
330319
&& (currentScope == null || project.ProjectId == currentScope.ProjectId));
331320
}
332321
catch (InvalidOperationException exception)
@@ -337,7 +326,7 @@ public Declaration FindProject(string name, Declaration currentScope = null)
337326
return result;
338327
}
339328

340-
public Declaration FindStdModule(string name, Declaration parent = null, bool includeBuiltIn = false)
329+
public Declaration FindStdModule(string name, Declaration parent, bool includeBuiltIn = false)
341330
{
342331
Debug.Assert(parent != null);
343332
Declaration result = null;
@@ -356,7 +345,7 @@ public Declaration FindStdModule(string name, Declaration parent = null, bool in
356345
return result;
357346
}
358347

359-
public Declaration FindClassModule(string name, Declaration parent = null, bool includeBuiltIn = false)
348+
public Declaration FindClassModule(string name, Declaration parent, bool includeBuiltIn = false)
360349
{
361350
Debug.Assert(parent != null);
362351
Declaration result = null;

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,12 +1183,12 @@ public HashSet<QualifiedModuleName> ModulesReferencedBy(QualifiedModuleName refe
11831183

11841184
public HashSet<QualifiedModuleName> ModulesReferencedBy(IEnumerable<QualifiedModuleName> referencingModules)
11851185
{
1186-
var referencedModules = new HashSet<QualifiedModuleName>();
1187-
foreach (var referencingModule in referencedModules)
1186+
var toModules = new HashSet<QualifiedModuleName>();
1187+
foreach (var referencingModule in referencingModules)
11881188
{
1189-
referencedModules.UnionWith(ModulesReferencedBy(referencingModule));
1189+
toModules.UnionWith(ModulesReferencedBy(referencingModule));
11901190
}
1191-
return referencedModules;
1191+
return toModules;
11921192
}
11931193

11941194
public HashSet<QualifiedModuleName> ModulesReferencing(QualifiedModuleName referencedModule)

RubberduckTests/RubberduckTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@
203203
<Compile Include="SourceControl\UnsyncedCommitsViewModelTests.cs" />
204204
<Compile Include="StringExtensionsTests.cs" />
205205
<Compile Include="Properties\AssemblyInfo.cs" />
206+
<Compile Include="Symbols\DeclarationFinderTests.cs" />
206207
<Compile Include="TodoExplorer\TodoExplorerTests.cs" />
207208
<Compile Include="UnitTesting\AssertTests.cs" />
208209
<Compile Include="UnitTesting\EngineTests.cs" />
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using Rubberduck.Parsing.Symbols;
4+
using Rubberduck.Parsing.VBA;
5+
using Rubberduck.Parsing.Grammar;
6+
using Rubberduck.VBEditor;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using Antlr4.Runtime;
10+
11+
namespace RubberduckTests.Symbols
12+
{
13+
[TestClass]
14+
public class DeclarationFinderTests
15+
{
16+
[TestCategory("Resolver")]
17+
[TestMethod]
18+
public void DeclarationFinderCanCopeWithMultipleModulesImplementingTheSameInterface()
19+
{
20+
var project = GetTestProject("testProject");
21+
var interf = GetTestClassModule(project, "interface");
22+
var member = GetTestFunction(interf, "testMember", Accessibility.Public);
23+
var implementingClass1 = GetTestClassModule(project, "implementingClass1");
24+
var implementingClass2 = GetTestClassModule(project, "implementingClass2");
25+
var implementsContext1 = new VBAParser.ImplementsStmtContext(null, 0);
26+
var implementsContext2 = new VBAParser.ImplementsStmtContext(null, 0);
27+
AddReference(interf, implementingClass1, implementsContext1);
28+
AddReference(interf, implementingClass1, implementsContext2);
29+
var declarations = new List<Declaration> {interf, member, implementingClass1, implementingClass2};
30+
31+
DeclarationFinder finder = new DeclarationFinder(declarations, new List<Rubberduck.Parsing.Annotations.IAnnotation>(), new List<UnboundMemberDeclaration>());
32+
var interfaceDeclarations = finder.FindAllInterfaceMembers().ToList();
33+
34+
Assert.AreEqual(1, interfaceDeclarations.Count());
35+
}
36+
37+
private static ClassModuleDeclaration GetTestClassModule(Declaration projectDeclatation, string name, bool isExposed = false)
38+
{
39+
var qualifiedClassModuleMemberName = new QualifiedMemberName(StubQualifiedModuleName(name), name);
40+
var classModuleAttributes = new Rubberduck.Parsing.VBA.Attributes();
41+
if (isExposed)
42+
{
43+
classModuleAttributes.AddExposedClassAttribute();
44+
}
45+
return new ClassModuleDeclaration(qualifiedClassModuleMemberName, projectDeclatation, name, false, null, classModuleAttributes);
46+
}
47+
48+
private static ProjectDeclaration GetTestProject(string name)
49+
{
50+
var qualifiedProjectName = new QualifiedMemberName(StubQualifiedModuleName("proj"), name);
51+
return new ProjectDeclaration(qualifiedProjectName, name, false, null);
52+
}
53+
54+
private static QualifiedModuleName StubQualifiedModuleName(string name)
55+
{
56+
return new QualifiedModuleName("dummy", "dummy", name);
57+
}
58+
59+
private static FunctionDeclaration GetTestFunction(Declaration moduleDeclatation, string name, Accessibility functionAccessibility)
60+
{
61+
var qualifiedFunctionMemberName = new QualifiedMemberName(moduleDeclatation.QualifiedName.QualifiedModuleName, name);
62+
return new FunctionDeclaration(qualifiedFunctionMemberName, moduleDeclatation, moduleDeclatation, "test", null, "test", functionAccessibility, null, Selection.Home, false, false, null, null);
63+
}
64+
65+
private static void AddReference(Declaration toDeclaration, Declaration fromModuleDeclaration, ParserRuleContext context = null)
66+
{
67+
toDeclaration.AddReference(toDeclaration.QualifiedName.QualifiedModuleName, fromModuleDeclaration, fromModuleDeclaration, context, toDeclaration.IdentifierName, toDeclaration, Selection.Home, new List<Rubberduck.Parsing.Annotations.IAnnotation>());
68+
}
69+
70+
}
71+
}

0 commit comments

Comments
 (0)