6
6
using Antlr4 . Runtime . Tree ;
7
7
using NLog ;
8
8
using Rubberduck . Parsing . Common ;
9
+ using Rubberduck . Parsing . ComReflection ;
9
10
using Rubberduck . Parsing . Symbols ;
10
11
using Rubberduck . Parsing . VBA . DeclarationCaching ;
11
12
using Rubberduck . Parsing . VBA . Extensions ;
@@ -29,12 +30,14 @@ public abstract class ReferenceResolveRunnerBase : IReferenceResolveRunner
29
30
protected readonly IParserStateManager _parserStateManager ;
30
31
private readonly IModuleToModuleReferenceManager _moduleToModuleReferenceManager ;
31
32
private readonly IReferenceRemover _referenceRemover ;
33
+ private readonly IUserComProjectProvider _userComProjectProvider ;
32
34
33
35
public ReferenceResolveRunnerBase (
34
36
RubberduckParserState state ,
35
37
IParserStateManager parserStateManager ,
36
- IModuleToModuleReferenceManager moduletToModuleReferenceManager ,
37
- IReferenceRemover referenceRemover )
38
+ IModuleToModuleReferenceManager moduleToModuleReferenceManager ,
39
+ IReferenceRemover referenceRemover ,
40
+ IUserComProjectProvider userComProjectProvider )
38
41
{
39
42
if ( state == null )
40
43
{
@@ -44,19 +47,24 @@ public ReferenceResolveRunnerBase(
44
47
{
45
48
throw new ArgumentNullException ( nameof ( parserStateManager ) ) ;
46
49
}
47
- if ( moduletToModuleReferenceManager == null )
50
+ if ( moduleToModuleReferenceManager == null )
48
51
{
49
- throw new ArgumentNullException ( nameof ( moduletToModuleReferenceManager ) ) ;
52
+ throw new ArgumentNullException ( nameof ( moduleToModuleReferenceManager ) ) ;
50
53
}
51
54
if ( referenceRemover == null )
52
55
{
53
56
throw new ArgumentNullException ( nameof ( referenceRemover ) ) ;
54
57
}
58
+ if ( userComProjectProvider == null )
59
+ {
60
+ throw new ArgumentNullException ( nameof ( userComProjectProvider ) ) ;
61
+ }
55
62
56
63
_state = state ;
57
64
_parserStateManager = parserStateManager ;
58
- _moduleToModuleReferenceManager = moduletToModuleReferenceManager ;
65
+ _moduleToModuleReferenceManager = moduleToModuleReferenceManager ;
59
66
_referenceRemover = referenceRemover ;
67
+ _userComProjectProvider = userComProjectProvider ;
60
68
}
61
69
62
70
@@ -81,18 +89,18 @@ public void ResolveReferences(IReadOnlyCollection<QualifiedModuleName> toResolve
81
89
82
90
var parsingStageTimer = ParsingStageTimer . StartNew ( ) ;
83
91
84
- ExecuteCompilationPasses ( _toResolve . AsReadOnly ( ) , token ) ;
92
+ AddSuperTypeNamesForDocumentModules ( _toResolve . AsReadOnly ( ) , _state , _userComProjectProvider ) ;
85
93
token . ThrowIfCancellationRequested ( ) ;
86
94
87
95
parsingStageTimer . Stop ( ) ;
88
- parsingStageTimer . Log ( "Executed compilation passes in {0}ms." ) ;
89
- parsingStageTimer . Restart ( ) ;
96
+ parsingStageTimer . Log ( "Added supertypes for document modules in {0}ms." ) ;
90
97
91
- AddSupertypesForDocumentModules ( _toResolve . AsReadOnly ( ) , _state ) ;
98
+ ExecuteCompilationPasses ( _toResolve . AsReadOnly ( ) , token ) ;
92
99
token . ThrowIfCancellationRequested ( ) ;
93
100
94
101
parsingStageTimer . Stop ( ) ;
95
- parsingStageTimer . Log ( "Added supertypes for document modules in {0}ms." ) ;
102
+ parsingStageTimer . Log ( "Executed compilation passes in {0}ms." ) ;
103
+ parsingStageTimer . Restart ( ) ;
96
104
97
105
var parseTreesToResolve = _state . ParseTrees . Where ( kvp => _toResolve . Contains ( kvp . Key ) ) . ToList ( ) ;
98
106
token . ThrowIfCancellationRequested ( ) ;
@@ -151,90 +159,46 @@ private void ExecuteCompilationPasses(IReadOnlyCollection<QualifiedModuleName> m
151
159
}
152
160
}
153
161
154
- private void AddSupertypesForDocumentModules ( IReadOnlyCollection < QualifiedModuleName > modules , RubberduckParserState state )
155
- {
156
- var documentModuleDeclarations = state . DeclarationFinder . UserDeclarations ( DeclarationType . Document )
157
- . OfType < DocumentModuleDeclaration > ( )
158
- . Where ( declaration => modules . Contains ( declaration . QualifiedName . QualifiedModuleName ) ) ;
159
-
160
- foreach ( var documentDeclaration in documentModuleDeclarations )
161
- {
162
- var documentSupertype = SupertypeForDocument ( documentDeclaration . QualifiedName . QualifiedModuleName , state ) ;
163
- if ( documentSupertype != null )
164
- {
165
- documentDeclaration . AddSupertype ( documentSupertype ) ;
166
- }
167
- }
168
- }
162
+ // skip IDispatch.. just about everything implements it and RD doesn't need to care about it; don't care about IUnknown either
163
+ private static readonly HashSet < string > IgnoredComInterfaces = new HashSet < string > ( new [ ] { "IDispatch" , "IUnknown" } ) ;
169
164
170
- private Declaration SupertypeForDocument ( QualifiedModuleName module , RubberduckParserState state )
165
+ private void AddSuperTypeNamesForDocumentModules ( IReadOnlyCollection < QualifiedModuleName > modules , RubberduckParserState state , IUserComProjectProvider userComProjectProvider )
171
166
{
172
- if ( module . ComponentType != ComponentType . Document )
173
- {
174
- return null ;
175
- }
167
+ //todo: Figure out how to unit test this.
176
168
177
- var component = _state . ProjectsProvider . Component ( module ) ;
178
- if ( component == null || component . IsWrappingNullReference )
179
- {
180
- return null ;
181
- }
169
+ var documentModuleDeclarationsByProject = state . DeclarationFinder . UserDeclarations ( DeclarationType . Document )
170
+ . OfType < DocumentModuleDeclaration > ( )
171
+ . Where ( declaration => modules . Contains ( declaration . QualifiedName . QualifiedModuleName ) )
172
+ . GroupBy ( declaration => declaration . ProjectId ) ;
182
173
183
- Declaration superType = null ;
184
- // TODO: Replace with TypeLibAPI call, require a solution regarding thread synchronization or caching
185
- /*
186
- using (var properties = component.Properties)
174
+ foreach ( var projectGroup in documentModuleDeclarationsByProject )
187
175
{
188
- int documentPropertyCount = 0;
189
- try
176
+ var userComProject = userComProjectProvider . UserProject ( projectGroup . Key ) ;
177
+ var documents = projectGroup . ToDictionary ( module => module . IdentifierName ) ;
178
+ foreach ( var comModule in userComProject . Members )
190
179
{
191
- if (properties == null || properties.IsWrappingNullReference )
180
+ if ( ! ( documents . TryGetValue ( comModule . Name , out var document ) ) )
192
181
{
193
- return null ;
182
+ continue ;
194
183
}
195
- documentPropertyCount = properties.Count;
196
- }
197
- catch(COMException)
198
- {
199
- return null;
200
- }
201
-
202
- foreach (var coclass in state.CoClasses)
203
- {
204
- try
205
- {
206
- if (coclass.Key.Count != documentPropertyCount)
207
- {
208
- continue;
209
- }
210
-
211
- var allNamesMatch = true;
212
- for (var i = 0; i < coclass.Key.Count; i++)
213
- {
214
- using (var property = properties[i+1])
215
- {
216
- if (coclass.Key[i] != property?.Name)
217
- {
218
- allNamesMatch = false;
219
- break;
220
- }
221
- }
222
- }
223
-
224
- if (allNamesMatch)
225
- {
226
- superType = coclass.Value;
227
- break;
228
- }
229
- }
230
- catch (COMException)
184
+
185
+ var inheritedInterfaces = comModule is ComCoClass documentCoClass
186
+ ? documentCoClass . ImplementedInterfaces
187
+ : ( comModule as ComInterface ) ? . InheritedInterfaces ;
188
+
189
+ //todo: Find a way to deal with the VBE's document type assignment behaviour not relying on an assumption about an interface naming convention.
190
+ var superTypeNames = inheritedInterfaces ?
191
+ . Where ( i => ! i . IsRestricted && ! IgnoredComInterfaces . Contains ( i . Name ) )
192
+ . Select ( i => i . Name )
193
+ . Select ( name => name . StartsWith ( "_" ) ? name . Substring ( 1 ) : name ) //This emulates the VBE's behaviour to allow assignment to the coclass type instead on the interface.
194
+ ?? Enumerable . Empty < string > ( ) ;
195
+
196
+ foreach ( var superTypeName in superTypeNames )
231
197
{
198
+ document . AddSupertypeName ( superTypeName ) ;
232
199
}
233
200
}
234
201
}
235
- */
236
-
237
- return superType ;
238
202
}
239
203
240
204
protected void ResolveReferences ( DeclarationFinder finder , QualifiedModuleName module , IParseTree tree , CancellationToken token )
0 commit comments