1
1
using System ;
2
2
using System . Collections . Generic ;
3
- using System . ComponentModel ;
4
3
using System . Linq ;
5
4
using Antlr4 . Runtime ;
6
5
using Rubberduck . Parsing . Grammar ;
@@ -24,6 +23,7 @@ private enum ContextAccessorType
24
23
private readonly HashSet < DeclarationType > _memberTypes ;
25
24
26
25
private readonly Stack < Declaration > _withBlockQualifiers ;
26
+ private readonly HashSet < RuleContext > _alreadyResolved ;
27
27
28
28
public IdentifierReferenceListener ( QualifiedModuleName qualifiedModuleName , Declarations declarations )
29
29
{
@@ -47,7 +47,8 @@ public IdentifierReferenceListener(QualifiedModuleName qualifiedModuleName, Decl
47
47
} ) ;
48
48
49
49
_withBlockQualifiers = new Stack < Declaration > ( ) ;
50
-
50
+ _alreadyResolved = new HashSet < RuleContext > ( ) ;
51
+
51
52
SetCurrentScope ( ) ;
52
53
}
53
54
@@ -62,6 +63,8 @@ private void SetCurrentScope()
62
63
_moduleTypes . Contains ( item . DeclarationType )
63
64
&& item . Project == _qualifiedModuleName . Project
64
65
&& item . ComponentName == _qualifiedModuleName . ComponentName ) ;
66
+
67
+ _alreadyResolved . Clear ( ) ;
65
68
}
66
69
67
70
/// <summary>
@@ -299,7 +302,7 @@ private Declaration Resolve(ParserRuleContext callSiteContext, Declaration local
299
302
var identifierName = callSiteContext . GetText ( ) ;
300
303
var callee = FindLocalScopeDeclaration ( identifierName , localScope )
301
304
?? FindModuleScopeDeclaration ( identifierName , localScope )
302
- ?? FindModuleScopeProcedure ( identifierName , localScope , accessorType )
305
+ ?? FindModuleScopeProcedure ( identifierName , localScope , accessorType , isAssignmentTarget )
303
306
?? FindProjectScopeDeclaration ( identifierName ) ;
304
307
305
308
if ( callee == null )
@@ -309,7 +312,7 @@ private Declaration Resolve(ParserRuleContext callSiteContext, Declaration local
309
312
identifierName = callSiteContext . GetText ( ) ;
310
313
callee = FindLocalScopeDeclaration ( identifierName , localScope )
311
314
?? FindModuleScopeDeclaration ( identifierName , localScope )
312
- ?? FindModuleScopeProcedure ( identifierName , localScope , accessorType )
315
+ ?? FindModuleScopeProcedure ( identifierName , localScope , accessorType , isAssignmentTarget )
313
316
?? FindProjectScopeDeclaration ( identifierName ) ;
314
317
}
315
318
@@ -320,6 +323,7 @@ private Declaration Resolve(ParserRuleContext callSiteContext, Declaration local
320
323
321
324
var reference = CreateReference ( callSiteContext , callee , isAssignmentTarget , hasExplicitLetStatement ) ;
322
325
callee . AddReference ( reference ) ;
326
+ _alreadyResolved . Add ( callSiteContext . Parent ) ;
323
327
324
328
if ( fieldCall != null )
325
329
{
@@ -362,6 +366,7 @@ private Declaration Resolve(VBAParser.DictionaryCallStmtContext fieldCall, Decla
362
366
var identifierContext = fieldCall . ambiguousIdentifier ( ) ;
363
367
var reference = CreateReference ( identifierContext , result , isAssignmentTarget , hasExplicitLetStatement ) ;
364
368
result . AddReference ( reference ) ;
369
+ _alreadyResolved . Add ( fieldCall ) ;
365
370
366
371
return result ;
367
372
}
@@ -399,6 +404,7 @@ private Declaration Resolve(VBAParser.ICS_S_MembersCallContext context, ContextA
399
404
{
400
405
var parentReference = CreateReference ( parent . Context , parent ) ;
401
406
parent . AddReference ( parentReference ) ;
407
+ _alreadyResolved . Add ( parent . Context ) ;
402
408
}
403
409
404
410
var chainedCalls = context . iCS_S_MemberCall ( ) ;
@@ -440,6 +446,7 @@ private Declaration Resolve(VBAParser.ICS_B_ProcedureCallContext context)
440
446
441
447
var reference = CreateReference ( identifierContext , callee ) ;
442
448
callee . AddReference ( reference ) ;
449
+ _alreadyResolved . Add ( context ) ;
443
450
444
451
return callee ;
445
452
}
@@ -508,27 +515,56 @@ private Declaration FindModuleScopeDeclaration(string identifierName, Declaratio
508
515
/// <param name="identifierName">The name of the identifier to find.</param>
509
516
/// <param name="localScope">The scope considered local.</param>
510
517
/// <param name="accessorType">Disambiguates <see cref="DeclarationType.PropertyLet"/> and <see cref="DeclarationType.PropertySet"/> accessors.</param>
511
- private Declaration FindModuleScopeProcedure ( string identifierName , Declaration localScope , ContextAccessorType accessorType )
518
+ private Declaration FindModuleScopeProcedure ( string identifierName , Declaration localScope , ContextAccessorType accessorType , bool isAssignmentTarget = false )
512
519
{
513
520
if ( localScope == null )
514
521
{
515
522
localScope = _currentScope ;
516
523
}
517
524
518
525
var result = _declarations [ identifierName ] . Where ( item =>
519
- item . ParentScope == localScope . ParentScope
520
- && ( item . DeclarationType == DeclarationType . Function
521
- || item . DeclarationType == DeclarationType . Procedure
522
- || ( accessorType == ContextAccessorType . GetValueOrReference && item . DeclarationType == DeclarationType . PropertyGet )
523
- || ( ( accessorType == ContextAccessorType . AssignValue && item . DeclarationType . HasFlag ( DeclarationType . PropertyLet )
524
- && ( localScope . DeclarationType == item . DeclarationType ) || localScope . ParentScope != item . ParentScope )
525
- || ( accessorType == ContextAccessorType . AssignReference && item . DeclarationType . HasFlag ( DeclarationType . PropertySet )
526
- && localScope . DeclarationType == item . DeclarationType ) || localScope . ParentScope != item . ParentScope ) ) )
526
+ IsProcedure ( item ) || IsPropertyAccessor ( item , accessorType , localScope , isAssignmentTarget ) )
527
527
. ToList ( ) ;
528
528
529
529
return result . SingleOrDefault ( ) ;
530
530
}
531
531
532
+ private bool IsProcedure ( Declaration item )
533
+ {
534
+ return item . DeclarationType == DeclarationType . Procedure
535
+ || item . DeclarationType == DeclarationType . Function ;
536
+ }
537
+
538
+ private bool IsPropertyAccessor ( Declaration item , ContextAccessorType accessorType , Declaration localScope , bool isAssignmentTarget = false )
539
+ {
540
+ var isProperty = item . DeclarationType . HasFlag ( DeclarationType . Property ) ;
541
+ if ( ! isProperty )
542
+ {
543
+ return false ;
544
+ }
545
+
546
+ if ( item . Equals ( localScope ) && item . DeclarationType == DeclarationType . PropertyGet )
547
+ {
548
+ // we're resolving the getter's return value assignment
549
+ return true ;
550
+ }
551
+ if ( item . Equals ( localScope ) )
552
+ {
553
+ // getter can't reference setter.. right?
554
+ return false ;
555
+ }
556
+
557
+ return ( accessorType == ContextAccessorType . AssignValue &&
558
+ item . DeclarationType == DeclarationType . PropertyLet )
559
+ ||
560
+ ( accessorType == ContextAccessorType . AssignReference &&
561
+ item . DeclarationType == DeclarationType . PropertySet )
562
+ ||
563
+ ( accessorType == ContextAccessorType . GetValueOrReference &&
564
+ item . DeclarationType == DeclarationType . PropertyGet &&
565
+ ! isAssignmentTarget ) ;
566
+ }
567
+
532
568
/// <summary>
533
569
/// Finds a global (project) scope declaration for an unqualified (unambiguous) call.
534
570
/// </summary>
@@ -543,31 +579,17 @@ private Declaration FindProjectScopeDeclaration(string identifierName)
543
579
|| item . DeclarationType == DeclarationType . Module ) ) ;
544
580
}
545
581
546
- /// <summary>
547
- /// Finds a global (project) scope declaration for a qualified call.
548
- /// </summary>
549
- /// <param name="identifierName"></param>
550
- /// <param name="moduleName"></param>
551
- /// <returns></returns>
552
- private Declaration FindProjectScopeDeclaration ( string identifierName , string moduleName )
553
- {
554
- return _declarations [ identifierName ] . SingleOrDefault ( item =>
555
- item . ComponentName == moduleName &&
556
- ( item . Accessibility == Accessibility . Public
557
- || item . Accessibility == Accessibility . Global ) ) ;
558
- }
559
-
560
582
#endregion
561
583
562
584
#region IVBAListener overrides
563
585
564
- public override void EnterICS_B_ProcedureCall ( VBAParser . ICS_B_ProcedureCallContext context )
565
- {
566
- Resolve ( context ) ;
567
- }
568
-
569
586
public override void EnterICS_B_MemberProcedureCall ( VBAParser . ICS_B_MemberProcedureCallContext context )
570
587
{
588
+ if ( _alreadyResolved . Contains ( context ) )
589
+ {
590
+ return ;
591
+ }
592
+
571
593
var parentScope = Resolve ( context . implicitCallStmt_InStmt ( ) , _currentScope , ContextAccessorType . GetValueOrReference ) ;
572
594
var parentType = ResolveType ( parentScope ) ;
573
595
@@ -590,6 +612,7 @@ public override void EnterICS_B_MemberProcedureCall(VBAParser.ICS_B_MemberProced
590
612
{
591
613
var reference = CreateReference ( identifierContext , member ) ;
592
614
member . AddReference ( reference ) ;
615
+ _alreadyResolved . Add ( context ) ;
593
616
}
594
617
595
618
var fieldCall = context . dictionaryCallStmt ( ) ;
@@ -598,22 +621,70 @@ public override void EnterICS_B_MemberProcedureCall(VBAParser.ICS_B_MemberProced
598
621
599
622
public override void EnterICS_S_VariableOrProcedureCall ( VBAParser . ICS_S_VariableOrProcedureCallContext context )
600
623
{
601
- Resolve ( context , _currentScope ) ;
624
+ if ( _alreadyResolved . Contains ( context ) )
625
+ {
626
+ return ;
627
+ }
628
+
629
+ try
630
+ {
631
+ Resolve ( context , _currentScope ) ;
632
+ }
633
+ catch ( InvalidOperationException )
634
+ {
635
+ // more than a single match was found.
636
+ }
602
637
}
603
638
604
639
public override void EnterICS_S_ProcedureOrArrayCall ( VBAParser . ICS_S_ProcedureOrArrayCallContext context )
605
640
{
606
- Resolve ( context , _currentScope ) ;
641
+ if ( _alreadyResolved . Contains ( context ) )
642
+ {
643
+ return ;
644
+ }
645
+
646
+ try
647
+ {
648
+ Resolve ( context , _currentScope ) ;
649
+ }
650
+ catch ( InvalidOperationException )
651
+ {
652
+ // more than a single match was found.
653
+ }
607
654
}
608
655
609
656
public override void EnterICS_S_MembersCall ( VBAParser . ICS_S_MembersCallContext context )
610
657
{
611
- Resolve ( context , _currentScope ) ;
658
+ if ( _alreadyResolved . Contains ( context ) )
659
+ {
660
+ return ;
661
+ }
662
+
663
+ try
664
+ {
665
+ Resolve ( context , _currentScope ) ;
666
+ }
667
+ catch ( InvalidOperationException )
668
+ {
669
+ // more than a single match was found.
670
+ }
612
671
}
613
672
614
673
public override void EnterICS_S_DictionaryCall ( VBAParser . ICS_S_DictionaryCallContext context )
615
674
{
616
- Resolve ( context , _currentScope ) ;
675
+ if ( _alreadyResolved . Contains ( context ) )
676
+ {
677
+ return ;
678
+ }
679
+
680
+ try
681
+ {
682
+ Resolve ( context , _currentScope ) ;
683
+ }
684
+ catch ( InvalidOperationException )
685
+ {
686
+ // more than a single match was found.
687
+ }
617
688
}
618
689
619
690
public override void EnterLetStmt ( VBAParser . LetStmtContext context )
0 commit comments