Skip to content

Commit 6928b91

Browse files
committed
references to properties resolve to correct member
1 parent 76a7275 commit 6928b91

File tree

1 file changed

+107
-36
lines changed

1 file changed

+107
-36
lines changed

Rubberduck.Parsing/Symbols/IdentifierReferenceListener.cs

Lines changed: 107 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.ComponentModel;
43
using System.Linq;
54
using Antlr4.Runtime;
65
using Rubberduck.Parsing.Grammar;
@@ -24,6 +23,7 @@ private enum ContextAccessorType
2423
private readonly HashSet<DeclarationType> _memberTypes;
2524

2625
private readonly Stack<Declaration> _withBlockQualifiers;
26+
private readonly HashSet<RuleContext> _alreadyResolved;
2727

2828
public IdentifierReferenceListener(QualifiedModuleName qualifiedModuleName, Declarations declarations)
2929
{
@@ -47,7 +47,8 @@ public IdentifierReferenceListener(QualifiedModuleName qualifiedModuleName, Decl
4747
});
4848

4949
_withBlockQualifiers = new Stack<Declaration>();
50-
50+
_alreadyResolved = new HashSet<RuleContext>();
51+
5152
SetCurrentScope();
5253
}
5354

@@ -62,6 +63,8 @@ private void SetCurrentScope()
6263
_moduleTypes.Contains(item.DeclarationType)
6364
&& item.Project == _qualifiedModuleName.Project
6465
&& item.ComponentName == _qualifiedModuleName.ComponentName);
66+
67+
_alreadyResolved.Clear();
6568
}
6669

6770
/// <summary>
@@ -299,7 +302,7 @@ private Declaration Resolve(ParserRuleContext callSiteContext, Declaration local
299302
var identifierName = callSiteContext.GetText();
300303
var callee = FindLocalScopeDeclaration(identifierName, localScope)
301304
?? FindModuleScopeDeclaration(identifierName, localScope)
302-
?? FindModuleScopeProcedure(identifierName, localScope, accessorType)
305+
?? FindModuleScopeProcedure(identifierName, localScope, accessorType, isAssignmentTarget)
303306
?? FindProjectScopeDeclaration(identifierName);
304307

305308
if (callee == null)
@@ -309,7 +312,7 @@ private Declaration Resolve(ParserRuleContext callSiteContext, Declaration local
309312
identifierName = callSiteContext.GetText();
310313
callee = FindLocalScopeDeclaration(identifierName, localScope)
311314
?? FindModuleScopeDeclaration(identifierName, localScope)
312-
?? FindModuleScopeProcedure(identifierName, localScope, accessorType)
315+
?? FindModuleScopeProcedure(identifierName, localScope, accessorType, isAssignmentTarget)
313316
?? FindProjectScopeDeclaration(identifierName);
314317
}
315318

@@ -320,6 +323,7 @@ private Declaration Resolve(ParserRuleContext callSiteContext, Declaration local
320323

321324
var reference = CreateReference(callSiteContext, callee, isAssignmentTarget, hasExplicitLetStatement);
322325
callee.AddReference(reference);
326+
_alreadyResolved.Add(callSiteContext.Parent);
323327

324328
if (fieldCall != null)
325329
{
@@ -362,6 +366,7 @@ private Declaration Resolve(VBAParser.DictionaryCallStmtContext fieldCall, Decla
362366
var identifierContext = fieldCall.ambiguousIdentifier();
363367
var reference = CreateReference(identifierContext, result, isAssignmentTarget, hasExplicitLetStatement);
364368
result.AddReference(reference);
369+
_alreadyResolved.Add(fieldCall);
365370

366371
return result;
367372
}
@@ -399,6 +404,7 @@ private Declaration Resolve(VBAParser.ICS_S_MembersCallContext context, ContextA
399404
{
400405
var parentReference = CreateReference(parent.Context, parent);
401406
parent.AddReference(parentReference);
407+
_alreadyResolved.Add(parent.Context);
402408
}
403409

404410
var chainedCalls = context.iCS_S_MemberCall();
@@ -440,6 +446,7 @@ private Declaration Resolve(VBAParser.ICS_B_ProcedureCallContext context)
440446

441447
var reference = CreateReference(identifierContext, callee);
442448
callee.AddReference(reference);
449+
_alreadyResolved.Add(context);
443450

444451
return callee;
445452
}
@@ -508,27 +515,56 @@ private Declaration FindModuleScopeDeclaration(string identifierName, Declaratio
508515
/// <param name="identifierName">The name of the identifier to find.</param>
509516
/// <param name="localScope">The scope considered local.</param>
510517
/// <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)
512519
{
513520
if (localScope == null)
514521
{
515522
localScope = _currentScope;
516523
}
517524

518525
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))
527527
.ToList();
528528

529529
return result.SingleOrDefault();
530530
}
531531

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+
532568
/// <summary>
533569
/// Finds a global (project) scope declaration for an unqualified (unambiguous) call.
534570
/// </summary>
@@ -543,31 +579,17 @@ private Declaration FindProjectScopeDeclaration(string identifierName)
543579
|| item.DeclarationType == DeclarationType.Module));
544580
}
545581

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-
560582
#endregion
561583

562584
#region IVBAListener overrides
563585

564-
public override void EnterICS_B_ProcedureCall(VBAParser.ICS_B_ProcedureCallContext context)
565-
{
566-
Resolve(context);
567-
}
568-
569586
public override void EnterICS_B_MemberProcedureCall(VBAParser.ICS_B_MemberProcedureCallContext context)
570587
{
588+
if (_alreadyResolved.Contains(context))
589+
{
590+
return;
591+
}
592+
571593
var parentScope = Resolve(context.implicitCallStmt_InStmt(), _currentScope, ContextAccessorType.GetValueOrReference);
572594
var parentType = ResolveType(parentScope);
573595

@@ -590,6 +612,7 @@ public override void EnterICS_B_MemberProcedureCall(VBAParser.ICS_B_MemberProced
590612
{
591613
var reference = CreateReference(identifierContext, member);
592614
member.AddReference(reference);
615+
_alreadyResolved.Add(context);
593616
}
594617

595618
var fieldCall = context.dictionaryCallStmt();
@@ -598,22 +621,70 @@ public override void EnterICS_B_MemberProcedureCall(VBAParser.ICS_B_MemberProced
598621

599622
public override void EnterICS_S_VariableOrProcedureCall(VBAParser.ICS_S_VariableOrProcedureCallContext context)
600623
{
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+
}
602637
}
603638

604639
public override void EnterICS_S_ProcedureOrArrayCall(VBAParser.ICS_S_ProcedureOrArrayCallContext context)
605640
{
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+
}
607654
}
608655

609656
public override void EnterICS_S_MembersCall(VBAParser.ICS_S_MembersCallContext context)
610657
{
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+
}
612671
}
613672

614673
public override void EnterICS_S_DictionaryCall(VBAParser.ICS_S_DictionaryCallContext context)
615674
{
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+
}
617688
}
618689

619690
public override void EnterLetStmt(VBAParser.LetStmtContext context)

0 commit comments

Comments
 (0)