Skip to content

Commit 3ee122b

Browse files
committed
Address review comments. Tweak DeclarationFinder to use readonly list instead of building.
1 parent bdd9cc6 commit 3ee122b

20 files changed

+744
-716
lines changed

Rubberduck.Core/UI/Command/FindAllImplementationsCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private SearchResultsViewModel CreateViewModel(Declaration target)
162162
{
163163
implementations = _state.DeclarationFinder.FindAllImplementationsOfInterface(classModule);
164164
}
165-
else if (target is ICanBeInterfaceMember member && member.IsInterfaceMember)
165+
else if (target is IInterfaceExposable member && member.IsInterfaceMember)
166166
{
167167
implementations = _state.DeclarationFinder.FindInterfaceImplementationMembers(target);
168168
}

Rubberduck.Parsing/Rubberduck.Parsing.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@
156156
<Compile Include="PreProcessing\ICompilationArgumentsProvider.cs" />
157157
<Compile Include="PreProcessing\ICompilationArgumentsCache.cs" />
158158
<Compile Include="Rewriter\ModuleRewriterFactory.cs" />
159-
<Compile Include="Symbols\ICanBeInterfaceMember.cs" />
159+
<Compile Include="Symbols\IInterfaceExposable.cs" />
160160
<Compile Include="Symbols\ModuleBodyElementDeclaration.cs" />
161161
<Compile Include="Symbols\ModuleDeclaration.cs" />
162162
<Compile Include="Symbols\ParsingExceptions\ExceptionErrorListenerFactory.cs" />

Rubberduck.Parsing/Symbols/DeclarationFinder.cs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class DeclarationFinder
3333
private IDictionary<DeclarationType, List<Declaration>> _userDeclarationsByType;
3434
private IDictionary<QualifiedSelection, List<Declaration>> _declarationsBySelection;
3535
private IDictionary<QualifiedSelection, List<IdentifierReference>> _referencesBySelection;
36-
private IDictionary<QualifiedModuleName, List<IdentifierReference>> _referencesByModule;
36+
private IReadOnlyDictionary<QualifiedModuleName, IReadOnlyList<IdentifierReference>> _referencesByModule;
3737
private IDictionary<QualifiedMemberName, List<IdentifierReference>> _referencesByMember;
3838

3939
private Lazy<IDictionary<DeclarationType, List<Declaration>>> _builtInDeclarationsByType;
@@ -43,7 +43,7 @@ public class DeclarationFinder
4343
private Lazy<IDictionary<VBAParser.ImplementsStmtContext, List<ModuleBodyElementDeclaration>>> _membersByImplementsContext;
4444
private Lazy<IDictionary<ClassModuleDeclaration, List<Declaration>>> _interfaceMembers;
4545
private Lazy<IDictionary<ClassModuleDeclaration, List<ClassModuleDeclaration>>> _interfaceImplementions;
46-
private Lazy<IDictionary<ICanBeInterfaceMember, List<ModuleBodyElementDeclaration>>> _implementationsByMember;
46+
private Lazy<IDictionary<IInterfaceExposable, List<ModuleBodyElementDeclaration>>> _implementationsByMember;
4747

4848
private Lazy<List<Declaration>> _nonBaseAsType;
4949
private Lazy<List<Declaration>> _eventHandlers;
@@ -129,7 +129,7 @@ private List<Action> CollectionConstructionActions(IReadOnlyList<Declaration> de
129129
.SelectMany(declaration => declaration.References)
130130
.GroupBy(reference =>
131131
Declaration.GetModuleParent(reference.ParentScoping).QualifiedName.QualifiedModuleName)
132-
.ToDictionary(),
132+
.ToReadonlyDictionary(),
133133
() =>
134134
_referencesByMember = declarations
135135
.SelectMany(declaration => declaration.References)
@@ -169,7 +169,7 @@ private void InitializeLazyCollections()
169169
_interfaceMembers = new Lazy<IDictionary<ClassModuleDeclaration, List<Declaration>>>(FindAllIinterfaceMembersByModule, true);
170170
_membersByImplementsContext = new Lazy<IDictionary<VBAParser.ImplementsStmtContext, List<ModuleBodyElementDeclaration>>>(FindAllImplementingMembersByImplementsContext, true);
171171
_interfaceImplementions = new Lazy<IDictionary<ClassModuleDeclaration, List<ClassModuleDeclaration>>>(FindAllImplementionsByInterface, true);
172-
_implementationsByMember = new Lazy<IDictionary<ICanBeInterfaceMember, List<ModuleBodyElementDeclaration>>>(FindAllImplementingMembersByMember, true);
172+
_implementationsByMember = new Lazy<IDictionary<IInterfaceExposable, List<ModuleBodyElementDeclaration>>>(FindAllImplementingMembersByMember, true);
173173
}
174174

175175
private IDictionary<(VBAParser.ImplementsStmtContext Context, Declaration Implementor), List<ModuleBodyElementDeclaration>> FindAllImplementingMembers()
@@ -195,7 +195,8 @@ private void InitializeLazyCollections()
195195
output.Add((impl.Context, impl.IdentifierReference.ParentScoping),
196196
((ClassModuleDeclaration) impl.IdentifierReference.ParentScoping).Members.Where(item =>
197197
item is ModuleBodyElementDeclaration member && ReferenceEquals(member.InterfaceImplemented,
198-
impl.IdentifierReference.Declaration)).Cast<ModuleBodyElementDeclaration>().ToList());
198+
impl.IdentifierReference.Declaration))
199+
.Cast<ModuleBodyElementDeclaration>().ToList());
199200
}
200201

201202
return output;
@@ -210,11 +211,12 @@ private Dictionary<ClassModuleDeclaration, List<ClassModuleDeclaration>> FindAll
210211
.Where(type => type.ImplementedInterfaces.Contains(intrface)).ToList());
211212
}
212213

213-
private IDictionary<ICanBeInterfaceMember, List<ModuleBodyElementDeclaration>> FindAllImplementingMembersByMember()
214+
private IDictionary<IInterfaceExposable, List<ModuleBodyElementDeclaration>> FindAllImplementingMembersByMember()
214215
{
215216
var implementations = _implementingMembers.Value.AllValues();
216217
return implementations
217-
.GroupBy(member => (ICanBeInterfaceMember)member.InterfaceMemberImplemented)
218+
219+
.GroupBy(member => (IInterfaceExposable)member.InterfaceMemberImplemented)
218220
.ToDictionary(member => member.Key, member => member.ToList());
219221
}
220222

@@ -231,7 +233,7 @@ private IDictionary<ClassModuleDeclaration, List<Declaration>> FindAllIinterface
231233
.ToDictionary(
232234
module => module,
233235
module => module.Members
234-
.Where(member => member is ICanBeInterfaceMember candidate && candidate.IsInterfaceMember)
236+
.Where(member => member is IInterfaceExposable candidate && candidate.IsInterfaceMember)
235237
.ToList());
236238
}
237239

@@ -402,9 +404,10 @@ public IEnumerable<Declaration> FindInterfaceMembersForImplementsContext(VBAPars
402404
/// <returns>The selected interface if found, null if not found.</returns>
403405
public ClassModuleDeclaration FindInterface(QualifiedSelection selection)
404406
{
405-
return FindAllUserInterfaces().FirstOrDefault(declaration => declaration.References
406-
.Where(refrnce => refrnce.Context.GetAncestor<VBAParser.ImplementsStmtContext>() != null)
407-
.Any(reference => ReferenceEquals(reference.Declaration, declaration)));
407+
return FindAllUserInterfaces()
408+
.FirstOrDefault(declaration => declaration.References
409+
.Any(reference => reference.Context.GetAncestor<VBAParser.ImplementsStmtContext>() != null
410+
&& ReferenceEquals(reference.Declaration, declaration)));
408411
}
409412

410413
/// <summary>
@@ -454,7 +457,7 @@ public IEnumerable<ModuleBodyElementDeclaration> FindAllInterfaceImplementingMem
454457
/// <returns>All concrete implementations of the passed interface declaration.</returns>
455458
public IEnumerable<ModuleBodyElementDeclaration> FindInterfaceImplementationMembers(Declaration interfaceMember)
456459
{
457-
if (!(interfaceMember is ICanBeInterfaceMember member))
460+
if (!(interfaceMember is IInterfaceExposable member))
458461
{
459462
return Enumerable.Empty<ModuleBodyElementDeclaration>();
460463
}
@@ -1131,18 +1134,17 @@ private static bool IsSubroutineOrProperty(Declaration declaration)
11311134
/// <summary>
11321135
/// Creates a dictionary of identifier references, keyed by module.
11331136
/// </summary>
1134-
public IReadOnlyDictionary<QualifiedModuleName,IEnumerable<IdentifierReference>> IdentifierReferences()
1137+
public IReadOnlyDictionary<QualifiedModuleName, IReadOnlyList<IdentifierReference>> IdentifierReferences()
11351138
{
1136-
return new ReadOnlyDictionary<QualifiedModuleName, IEnumerable<IdentifierReference>>(
1137-
_referencesByModule.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.AsEnumerable()));
1139+
return _referencesByModule;
11381140
}
11391141

11401142
/// <summary>
11411143
/// Gets all identifier references in the specified module.
11421144
/// </summary>
11431145
public IEnumerable<IdentifierReference> IdentifierReferences(QualifiedModuleName module)
11441146
{
1145-
return _referencesByModule.TryGetValue(module, out List<IdentifierReference> value)
1147+
return _referencesByModule.TryGetValue(module, out var value)
11461148
? value
11471149
: Enumerable.Empty<IdentifierReference>();
11481150
}

Rubberduck.Parsing/Symbols/FunctionDeclaration.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public FunctionDeclaration(ComMember member, Declaration parent, QualifiedModule
6565
}
6666

6767
/// <inheritdoc/>
68-
protected override bool Implements(ICanBeInterfaceMember member)
68+
protected override bool Implements(IInterfaceExposable member)
6969
{
7070
if (ReferenceEquals(member, this))
7171
{
@@ -74,8 +74,8 @@ protected override bool Implements(ICanBeInterfaceMember member)
7474

7575
return member.DeclarationType == DeclarationType.Function
7676
&& member.IsInterfaceMember
77-
&& IsInterfaceImplementation
78-
&& IdentifierName.Equals(member.ImplementingIdentifierName);
77+
&& IdentifierName.Equals(member.ImplementingIdentifierName)
78+
&& ((ClassModuleDeclaration)member.ParentDeclaration).Subtypes.Any(implementation => ReferenceEquals(implementation, ParentDeclaration));
7979
}
8080
}
8181
}

Rubberduck.Parsing/Symbols/ICanBeInterfaceMember.cs renamed to Rubberduck.Parsing/Symbols/IInterfaceExposable.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace Rubberduck.Parsing.Symbols
22
{
3-
public interface ICanBeInterfaceMember
3+
public interface IInterfaceExposable
44
{
55
/// <summary>
66
/// Returns true if the member is part of an interface definition.
@@ -22,31 +22,31 @@ public interface ICanBeInterfaceMember
2222
string AsTypeName { get; }
2323
}
2424

25-
internal static class InterfaceMemberExtensions
25+
internal static class InterfaceExposableExtensions
2626
{
2727
/// <summary>
28-
/// Provides a default implementation of ICanBeInterfaceMember.IsInterfaceMember
28+
/// Provides a default implementation of IInterfaceExposable.IsInterfaceMember
2929
/// </summary>
3030
/// <param name="member">The member to test.</param>
3131
/// <returns>Returns true if the member is part of an interface definition.</returns>
32-
internal static bool IsInterfaceMember(this ICanBeInterfaceMember member) =>
32+
internal static bool IsInterfaceMember(this IInterfaceExposable member) =>
3333
(member.Accessibility == Accessibility.Public || member.Accessibility == Accessibility.Implicit) &&
3434
member.InterfaceDeclaration != null;
3535

3636
/// <summary>
37-
/// Provides a default implementation of ICanBeInterfaceMember.InterfaceDeclaration
37+
/// Provides a default implementation of IInterfaceExposable.InterfaceDeclaration
3838
/// </summary>
3939
/// <param name="member">The member to find the InterfaceDeclaration of.</param>
4040
/// <returns>Tthe Declaration of the interface that this is a member of, or null if IsInterfaceMember is false.</returns>
41-
internal static ClassModuleDeclaration InterfaceDeclaration(this ICanBeInterfaceMember member) =>
41+
internal static ClassModuleDeclaration InterfaceDeclaration(this IInterfaceExposable member) =>
4242
member.ParentDeclaration is ClassModuleDeclaration parent && parent.IsInterface ? parent : null;
4343

4444
/// <summary>
45-
/// Provides a default implementation of ICanBeInterfaceMember.ImplementingIdentifierName
45+
/// Provides a default implementation of IInterfaceExposable.ImplementingIdentifierName
4646
/// </summary>
4747
/// <param name="member">The member to find the ImplementingIdentifierName of.</param>
4848
/// <returns>The identifier name of members implementing this member, or null if IsInterfaceMember is false.</returns>
49-
internal static string ImplementingIdentifierName(this ICanBeInterfaceMember member) =>
49+
internal static string ImplementingIdentifierName(this IInterfaceExposable member) =>
5050
member.InterfaceDeclaration != null
5151
? $"{member.InterfaceDeclaration.IdentifierName}_{member.IdentifierName}"
5252
: null;

Rubberduck.Parsing/Symbols/ModuleBodyElementDeclaration.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Xml;
45
using Antlr4.Runtime;
56
using Rubberduck.Parsing.Annotations;
67
using Rubberduck.Parsing.Grammar;
@@ -9,7 +10,7 @@
910

1011
namespace Rubberduck.Parsing.Symbols
1112
{
12-
public abstract class ModuleBodyElementDeclaration : Declaration, IParameterizedDeclaration, ICanBeInterfaceMember, ICanBeDefaultMember
13+
public abstract class ModuleBodyElementDeclaration : Declaration, IParameterizedDeclaration, IInterfaceExposable, ICanBeDefaultMember
1314
{
1415
protected ModuleBodyElementDeclaration(
1516
QualifiedMemberName name,
@@ -100,7 +101,7 @@ protected void AddParameters(IEnumerable<ParameterDeclaration> parameters)
100101
/// </summary>
101102
/// <param name="interfaceMember">The member to test for implementation of.</param>
102103
/// <returns>True if this Declaration is a concrete implementation of interfaceMember.</returns>
103-
protected abstract bool Implements(ICanBeInterfaceMember interfaceMember);
104+
protected abstract bool Implements(IInterfaceExposable interfaceMember);
104105

105106
/// <inheritdoc/>
106107
public bool IsInterfaceMember => this.IsInterfaceMember();
@@ -133,18 +134,32 @@ private static (bool IsInterfaceImplementation, ClassModuleDeclaration Interface
133134
return (false, null);
134135
}
135136

137+
/*
138+
* The following MS-VBAL rule effectively limits the the IdentifierName of an implemented interface member to the last token in 'identifiers':
139+
*
140+
* 5.2.4.2 - A class may not be used as an interface class if the names of any of its public variable or method
141+
* methods contain an underscore character (Unicode u+005F).
142+
*
143+
* Note that there is NOT a corresponding restriction on the <class-type-name>.
144+
*/
145+
136146
var supertype = string.Join("_", identifiers.Take(identifiers.Length - 1));
137147

138148
var implements = classModule.Supertypes.Cast<ClassModuleDeclaration>().FirstOrDefault(intrface =>
139149
intrface.IdentifierName.Equals(supertype)
140150
&& intrface.References.Any(reference => ReferenceEquals(reference.ParentScoping, classModule)));
141151

142-
return (implements != null, implements);
152+
if (implements == null)
153+
{
154+
return (false, null);
155+
}
156+
157+
return implements.Members.Any(member => element.Implements(member as IInterfaceExposable)) ? (true, implements) : (false, null);
143158
}
144159

145160
private static Declaration MemberImplemented(ModuleBodyElementDeclaration element)
146161
{
147-
return element.InterfaceImplemented?.Members.FirstOrDefault(member => element.Implements(member as ICanBeInterfaceMember));
162+
return element.InterfaceImplemented?.Members.FirstOrDefault(member => element.Implements(member as IInterfaceExposable));
148163
}
149164
}
150165
}

Rubberduck.Parsing/Symbols/ModuleDeclaration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ protected ModuleDeclaration(
4343
private readonly List<Declaration> _members = new List<Declaration>();
4444
public IReadOnlyList<Declaration> Members => _members;
4545

46-
public void AddMember(Declaration member)
46+
internal void AddMember(Declaration member)
4747
{
4848
_members.Add(member);
4949
}

Rubberduck.Parsing/Symbols/PropertyDeclaration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@ protected PropertyDeclaration(
4848
base.IsObject || (Parameters.OrderBy(p => p.Selection).LastOrDefault()?.IsObject ?? false);
4949

5050
/// <inheritdoc/>
51-
protected abstract override bool Implements(ICanBeInterfaceMember member);
51+
protected abstract override bool Implements(IInterfaceExposable member);
5252
}
5353
}

Rubberduck.Parsing/Symbols/PropertyGetDeclaration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public PropertyGetDeclaration(ComField field, Declaration parent, QualifiedModul
8383
{ }
8484

8585
/// <inheritdoc/>
86-
protected override bool Implements(ICanBeInterfaceMember member)
86+
protected override bool Implements(IInterfaceExposable member)
8787
{
8888
if (ReferenceEquals(member, this))
8989
{
@@ -92,7 +92,7 @@ protected override bool Implements(ICanBeInterfaceMember member)
9292

9393
return (member.DeclarationType == DeclarationType.PropertyGet || member.DeclarationType == DeclarationType.Variable)
9494
&& member.IsInterfaceMember
95-
&& IsInterfaceImplementation
95+
&& ((ClassModuleDeclaration)member.ParentDeclaration).Subtypes.Any(implementation => ReferenceEquals(implementation, ParentDeclaration))
9696
&& IdentifierName.Equals(member.ImplementingIdentifierName);
9797
}
9898
}

Rubberduck.Parsing/Symbols/PropertyLetDeclaration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,16 @@ public PropertyLetDeclaration(ComField field, Declaration parent, QualifiedModul
7373
{ }
7474

7575
/// <inheritdoc/>
76-
protected override bool Implements(ICanBeInterfaceMember member)
76+
protected override bool Implements(IInterfaceExposable member)
7777
{
7878
if (ReferenceEquals(member, this))
7979
{
8080
return false;
8181
}
8282

8383
return member.IsInterfaceMember
84-
&& IsInterfaceImplementation
8584
&& IdentifierName.Equals(member.ImplementingIdentifierName)
85+
&& ((ClassModuleDeclaration)member.ParentDeclaration).Subtypes.Any(implementation => ReferenceEquals(implementation, ParentDeclaration))
8686
&& (member.DeclarationType == DeclarationType.PropertyLet
8787
|| member.DeclarationType == DeclarationType.Variable
8888
&& !member.IsObject);

0 commit comments

Comments
 (0)