1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Linq ;
4
+ using System . Text ;
4
5
using Antlr4 . Runtime ;
5
6
using Rubberduck . Parsing . Grammar ;
6
7
using Rubberduck . VBEditor ;
@@ -181,7 +182,7 @@ private Declaration ResolveType(VBAParser.ImplicitCallStmt_InStmtContext context
181
182
182
183
var type = ResolveInternal ( context . iCS_S_VariableOrProcedureCall ( ) , localScope )
183
184
?? ResolveInternal ( context . iCS_S_ProcedureOrArrayCall ( ) , localScope )
184
- ?? ResolveInternal ( context . iCS_S_MembersCall ( ) , localScope )
185
+ ?? ResolveInternal ( context . iCS_S_MembersCall ( ) , ContextAccessorType . GetValueOrReference )
185
186
?? ResolveInternal ( dictionaryCall , localScope , ContextAccessorType . GetValueOrReference , dictionaryCall == null ? null : dictionaryCall . dictionaryCallStmt ( ) ) ;
186
187
187
188
return ResolveType ( type ) ;
@@ -223,7 +224,7 @@ private Declaration ResolveType(Declaration parent)
223
224
224
225
private Declaration ResolveInternal ( ParserRuleContext callSiteContext , Declaration localScope , ContextAccessorType accessorType = ContextAccessorType . GetValueOrReference , VBAParser . DictionaryCallStmtContext fieldCall = null , bool hasExplicitLetStatement = false , bool isAssignmentTarget = false )
225
226
{
226
- if ( callSiteContext == null )
227
+ if ( callSiteContext == null || _alreadyResolved . Contains ( callSiteContext ) )
227
228
{
228
229
return null ;
229
230
}
@@ -233,32 +234,11 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
233
234
throw new ArgumentException ( "'" + callSiteContext . GetType ( ) . Name + "' is not an identifier context." , "callSiteContext" ) ;
234
235
}
235
236
236
-
237
- /* VBA allows ambiguous identifiers; if foo is declared at both
238
- * local and module scope, local scope takes precedence.
239
- * Identifier reference resolution should therefore start search for
240
- * declarations in this order:
241
- * 1. Local scope (variable)
242
- * 2a. Module scope (variable)
243
- * 2b. Module scope (procedure)
244
- * 3a. Project/Global scope (variable)
245
- * 3b. Project/Global scope (procedure)
246
- * 4a. Global (references) scope (variable)*
247
- * 4b. Global (references) scope (procedure)*
248
- *
249
- * *project references aren't accounted for... yet.
250
- */
251
-
252
237
if ( localScope == null )
253
238
{
254
239
localScope = _currentScope ;
255
240
}
256
241
257
- if ( _withBlockQualifiers . Any ( ) )
258
- {
259
- localScope = _withBlockQualifiers . Peek ( ) ;
260
- }
261
-
262
242
var identifierName = callSiteContext . GetText ( ) ;
263
243
Declaration callee ;
264
244
if ( localScope . DeclarationType == DeclarationType . Variable )
@@ -270,8 +250,8 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
270
250
else
271
251
{
272
252
callee = FindLocalScopeDeclaration ( identifierName , localScope )
273
- ?? FindModuleScopeDeclaration ( identifierName , localScope )
274
253
?? FindModuleScopeProcedure ( identifierName , localScope , accessorType , isAssignmentTarget )
254
+ ?? FindModuleScopeDeclaration ( identifierName , localScope )
275
255
?? FindProjectScopeDeclaration ( identifierName ) ;
276
256
}
277
257
@@ -281,8 +261,8 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
281
261
localScope = _currentScope ;
282
262
identifierName = callSiteContext . GetText ( ) ;
283
263
callee = FindLocalScopeDeclaration ( identifierName , localScope )
284
- ?? FindModuleScopeDeclaration ( identifierName , localScope )
285
264
?? FindModuleScopeProcedure ( identifierName , localScope , accessorType , isAssignmentTarget )
265
+ ?? FindModuleScopeDeclaration ( identifierName , localScope )
286
266
?? FindProjectScopeDeclaration ( identifierName ) ;
287
267
}
288
268
@@ -294,6 +274,7 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
294
274
var reference = CreateReference ( callSiteContext , callee , isAssignmentTarget , hasExplicitLetStatement ) ;
295
275
callee . AddReference ( reference ) ;
296
276
_alreadyResolved . Add ( reference . Context ) ;
277
+ _alreadyResolved . Add ( callSiteContext ) ;
297
278
298
279
if ( fieldCall != null )
299
280
{
@@ -362,13 +343,20 @@ private Declaration ResolveInternal(VBAParser.ICS_S_MembersCallContext context,
362
343
return null ;
363
344
}
364
345
365
- if ( localScope == null )
346
+ Declaration parent ;
347
+ if ( _withBlockQualifiers . Any ( ) )
366
348
{
367
- localScope = _currentScope ;
349
+ parent = _withBlockQualifiers . Peek ( ) ;
350
+ }
351
+ else
352
+ {
353
+ if ( localScope == null )
354
+ {
355
+ localScope = _currentScope ;
356
+ }
357
+ parent = ResolveInternal ( context . iCS_S_ProcedureOrArrayCall ( ) , localScope , accessorType , hasExplicitLetStatement , isAssignmentTarget )
358
+ ?? ResolveInternal ( context . iCS_S_VariableOrProcedureCall ( ) , localScope , accessorType , hasExplicitLetStatement , isAssignmentTarget ) ;
368
359
}
369
-
370
- var parent = ResolveInternal ( context . iCS_S_ProcedureOrArrayCall ( ) , localScope , accessorType , hasExplicitLetStatement , isAssignmentTarget )
371
- ?? ResolveInternal ( context . iCS_S_VariableOrProcedureCall ( ) , localScope , accessorType , hasExplicitLetStatement , isAssignmentTarget ) ;
372
360
373
361
if ( parent != null )
374
362
{
@@ -381,17 +369,25 @@ private Declaration ResolveInternal(VBAParser.ICS_S_MembersCallContext context,
381
369
}
382
370
383
371
var chainedCalls = context . iCS_S_MemberCall ( ) ;
372
+ var lastCall = chainedCalls . Last ( ) ;
384
373
foreach ( var memberCall in chainedCalls )
385
374
{
386
- var member = ResolveInternal ( memberCall . iCS_S_ProcedureOrArrayCall ( ) , parent , accessorType , hasExplicitLetStatement , isAssignmentTarget )
387
- ?? ResolveInternal ( memberCall . iCS_S_VariableOrProcedureCall ( ) , parent , accessorType , hasExplicitLetStatement , isAssignmentTarget ) ;
375
+ // if we're on the left side of an assignment, only the last memberCall is the assignment target.
376
+ var isLast = memberCall . Equals ( lastCall ) ;
377
+ var accessor = isLast
378
+ ? accessorType
379
+ : ContextAccessorType . GetValueOrReference ;
380
+ var isTarget = isLast && isAssignmentTarget ;
381
+
382
+ var member = ResolveInternal ( memberCall . iCS_S_ProcedureOrArrayCall ( ) , parent , accessor , hasExplicitLetStatement , isTarget )
383
+ ?? ResolveInternal ( memberCall . iCS_S_VariableOrProcedureCall ( ) , parent , accessor , hasExplicitLetStatement , isTarget ) ;
388
384
389
385
if ( member == null )
390
386
{
391
387
return null ;
392
388
}
393
389
394
- parent = member ;
390
+ parent = ResolveType ( member ) ;
395
391
}
396
392
397
393
var fieldCall = context . dictionaryCallStmt ( ) ;
@@ -522,8 +518,16 @@ public void Resolve(VBAParser.ICS_S_MembersCallContext context)
522
518
return ;
523
519
}
524
520
525
- var parent = ResolveInternal ( context . iCS_S_ProcedureOrArrayCall ( ) , _currentScope )
526
- ?? ResolveInternal ( context . iCS_S_VariableOrProcedureCall ( ) , _currentScope ) ;
521
+ Declaration parent ;
522
+ if ( _withBlockQualifiers . Any ( ) )
523
+ {
524
+ parent = _withBlockQualifiers . Peek ( ) ;
525
+ }
526
+ else
527
+ {
528
+ parent = ResolveInternal ( context . iCS_S_ProcedureOrArrayCall ( ) , _currentScope )
529
+ ?? ResolveInternal ( context . iCS_S_VariableOrProcedureCall ( ) , _currentScope ) ;
530
+ }
527
531
528
532
if ( parent != null && parent . Context != null )
529
533
{
@@ -545,7 +549,7 @@ public void Resolve(VBAParser.ICS_S_MembersCallContext context)
545
549
return ;
546
550
}
547
551
548
- parent = member ;
552
+ parent = ResolveType ( member ) ;
549
553
}
550
554
551
555
var fieldCall = context . dictionaryCallStmt ( ) ;
@@ -569,14 +573,7 @@ private void TryResolve<TContext>(TContext context) where TContext : ParserRuleC
569
573
return ;
570
574
}
571
575
572
- try
573
- {
574
- ResolveInternal ( context , _currentScope ) ;
575
- }
576
- catch ( InvalidOperationException )
577
- {
578
- // bug: more than a single match was found.
579
- }
576
+ ResolveInternal ( context , _currentScope ) ;
580
577
}
581
578
582
579
public void Resolve ( VBAParser . LetStmtContext context )
@@ -726,6 +723,12 @@ private Declaration FindLocalScopeDeclaration(string identifierName, Declaration
726
723
localScope = _currentScope ;
727
724
}
728
725
726
+ if ( _moduleTypes . Contains ( localScope . DeclarationType ) )
727
+ {
728
+ // "local scope" is not intended to be module level.
729
+ return null ;
730
+ }
731
+
729
732
if ( localScope . DeclarationType == DeclarationType . Function ||
730
733
localScope . DeclarationType == DeclarationType . PropertyGet )
731
734
{
@@ -762,8 +765,17 @@ private Declaration FindModuleScopeProcedure(string identifierName, Declaration
762
765
}
763
766
764
767
var matches = _declarations [ identifierName ] ;
765
- return matches . SingleOrDefault ( item =>
766
- IsProcedure ( item ) || IsPropertyAccessor ( item , accessorType , localScope , isAssignmentTarget ) ) ;
768
+ try
769
+ {
770
+ return matches . SingleOrDefault ( item =>
771
+ item . Project == localScope . Project
772
+ && item . ComponentName == localScope . ComponentName
773
+ && ( IsProcedure ( item , localScope ) || IsPropertyAccessor ( item , accessorType , localScope , isAssignmentTarget ) ) ) ;
774
+ }
775
+ catch ( InvalidOperationException e )
776
+ {
777
+ return null ;
778
+ }
767
779
}
768
780
769
781
private Declaration FindProjectScopeDeclaration ( string identifierName )
@@ -776,10 +788,12 @@ private Declaration FindProjectScopeDeclaration(string identifierName)
776
788
|| _moduleTypes . Contains ( item . DeclarationType ) /* because static classes are accessed just like modules */ ) ) ;
777
789
}
778
790
779
- private bool IsProcedure ( Declaration item )
791
+ private bool IsProcedure ( Declaration item , Declaration localScope )
780
792
{
781
- return item . DeclarationType == DeclarationType . Procedure
782
- || item . DeclarationType == DeclarationType . Function ;
793
+ return ( item . DeclarationType == DeclarationType . Procedure
794
+ || item . DeclarationType == DeclarationType . Function )
795
+ && ( _moduleTypes . Contains ( localScope . DeclarationType )
796
+ && item . ParentScope == localScope . Scope ) ;
783
797
}
784
798
785
799
private bool IsPropertyAccessor ( Declaration item , ContextAccessorType accessorType , Declaration localScope , bool isAssignmentTarget = false )
0 commit comments