Skip to content

Commit 1686b6c

Browse files
committed
fixed UDT member references... without breaking parameter references
1 parent 604be0a commit 1686b6c

File tree

1 file changed

+80
-32
lines changed

1 file changed

+80
-32
lines changed

Rubberduck.Parsing/Symbols/IdentifierReferenceListener.cs

Lines changed: 80 additions & 32 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.Windows.Forms;
45
using Antlr4.Runtime;
56
using Antlr4.Runtime.Tree;
67
using Rubberduck.Parsing.Grammar;
@@ -251,6 +252,28 @@ private bool EnterIdentifier(ParserRuleContext context, Selection selection, boo
251252
return false;
252253
}
253254

255+
public override void EnterVsNew(VBAParser.VsNewContext context)
256+
{
257+
_skipIdentifiers = true;
258+
var identifiers = context.valueStmt().GetRuleContexts<VBAParser.ImplicitCallStmt_InStmtContext>();
259+
260+
var lastIdentifier = identifiers.Last();
261+
var name = lastIdentifier.GetText();
262+
263+
var matches = _declarations[name].Where(d => d.DeclarationType == DeclarationType.Class).ToList();
264+
var result = matches.Count <= 1
265+
? matches.SingleOrDefault()
266+
: GetClosestScopeDeclaration(matches, context, DeclarationType.Class);
267+
268+
var reference = new IdentifierReference(_qualifiedName, result.IdentifierName, lastIdentifier.GetSelection(), context, result);
269+
result.AddReference(reference);
270+
}
271+
272+
public override void ExitVsNew(VBAParser.VsNewContext context)
273+
{
274+
_skipIdentifiers = false;
275+
}
276+
254277
private readonly Stack<Declaration> _withQualifiers = new Stack<Declaration>();
255278
public override void EnterWithStmt(VBAParser.WithStmtContext context)
256279
{
@@ -410,12 +433,6 @@ private Declaration Resolve(VBAParser.ICS_S_MembersCallContext context)
410433
return Resolve(context, out discarded);
411434
}
412435

413-
private Declaration Resolve(VBAParser.ICS_B_ProcedureCallContext context)
414-
{
415-
var name = context.certainIdentifier().GetText();
416-
return FindProcedureDeclaration(name, context.certainIdentifier()); // note: is this a StackOverflowException waiting to bite me?
417-
}
418-
419436
private Declaration Resolve(VBAParser.ICS_B_MemberProcedureCallContext context)
420437
{
421438
var parent = context.implicitCallStmt_InStmt();
@@ -431,7 +448,6 @@ private Declaration Resolve(VBAParser.ICS_B_MemberProcedureCallContext context)
431448

432449
var type = _declarations[parentCall.AsTypeName].SingleOrDefault(item =>
433450
item.DeclarationType == DeclarationType.Class
434-
//|| item.DeclarationType == DeclarationType.Module
435451
|| item.DeclarationType == DeclarationType.UserDefinedType);
436452

437453
var members = _declarations.FindMembers(type);
@@ -492,11 +508,34 @@ public override void EnterVsAssign(VBAParser.VsAssignContext context)
492508
}
493509
}
494510

495-
private Declaration FindProcedureDeclaration(string procedureName, ParserRuleContext context)
511+
private static readonly DeclarationType[] PropertyAccessors =
512+
{
513+
DeclarationType.PropertyGet,
514+
DeclarationType.PropertyLet,
515+
DeclarationType.PropertySet
516+
};
517+
518+
private Declaration FindProcedureDeclaration(string procedureName, ParserRuleContext context, DeclarationType accessor = DeclarationType.PropertyGet)
496519
{
497520
var matches = _declarations[procedureName]
498521
.Where(declaration => ProcedureDeclarations.Contains(declaration.DeclarationType))
499-
.Where(IsInScope);
522+
.Where(IsInScope)
523+
.ToList();
524+
525+
if (!matches.Any())
526+
{
527+
return null;
528+
}
529+
530+
if (matches.Count == 1)
531+
{
532+
return matches.First();
533+
}
534+
535+
if (matches.All(m => PropertyAccessors.Contains(m.DeclarationType)))
536+
{
537+
return matches.Find(m => m.DeclarationType == accessor);
538+
}
500539

501540
var procedure = GetClosestScopeDeclaration(matches, context);
502541
return procedure;
@@ -567,52 +606,61 @@ private Declaration GetClosestScopeDeclaration(IEnumerable<Declaration> declarat
567606
}
568607

569608
var matches = declarations as IList<Declaration> ?? declarations.ToList();
570-
var currentScope = matches.FirstOrDefault(declaration =>
571-
IsCurrentScopeMember(accessorType, declaration)
572-
&& (declaration.DeclarationType == accessorType
573-
|| accessorType == DeclarationType.PropertyGet));
574-
575-
if (currentScope != null)
609+
if (!matches.Any())
576610
{
577-
//return currentScope;
611+
return null;
578612
}
579613

580-
var moduleScope = matches.SingleOrDefault(declaration => declaration.Scope == ModuleScope);
581-
if (moduleScope != null)
614+
var currentScope = matches.SingleOrDefault(declaration => declaration.Scope == _currentScope
615+
&& !PropertyAccessors.Contains(declaration.DeclarationType));
616+
if (currentScope != null)
582617
{
583-
return moduleScope;
618+
return currentScope;
584619
}
585620

621+
// note: commented-out because it breaks the UDT member references, but property getters behave strangely still
622+
//var currentScope = matches.SingleOrDefault(declaration =>
623+
// IsCurrentScopeMember(accessorType, declaration)
624+
// && (declaration.DeclarationType == accessorType
625+
// || accessorType == DeclarationType.PropertyGet));
626+
627+
//if (matches.First().IdentifierName == "procedure")
628+
//{
629+
// // for debugging - "procedure" is both a UDT member and a parameter to a procedure.
630+
//}
631+
586632
if (matches.Count == 1)
587633
{
588634
return matches[0];
589635
}
590636

637+
var moduleScope = matches.SingleOrDefault(declaration => declaration.Scope == ModuleScope);
638+
if (moduleScope != null)
639+
{
640+
return moduleScope;
641+
}
642+
591643
var memberProcedureCallContext = context.Parent as VBAParser.ICS_B_MemberProcedureCallContext;
592644
if (memberProcedureCallContext != null)
593645
{
594646
return Resolve(memberProcedureCallContext);
595-
var parent = memberProcedureCallContext;
596-
var parentMemberName = memberProcedureCallContext.ambiguousIdentifier().GetText();
597-
var matchingParents = _declarations.Items.Where(d => d.IdentifierName == parentMemberName
598-
&& (d.DeclarationType == DeclarationType.Class || d.DeclarationType == DeclarationType.UserDefinedType));
599-
600-
var parentType = _withQualifiers.Any()
601-
? _withQualifiers.Peek()
602-
: matches.SingleOrDefault(m =>
603-
matchingParents.Any(p =>
604-
(p.DeclarationType == DeclarationType.Class && m.ComponentName == p.AsTypeName)
605-
|| (p.DeclarationType == DeclarationType.UserDefinedType)));
647+
}
606648

607-
return parentType == null ? null : matches.SingleOrDefault(m => m.ParentScope == parentType.Scope);
649+
var implicitCall = context.Parent.Parent as VBAParser.ImplicitCallStmt_InStmtContext;
650+
if (implicitCall != null)
651+
{
652+
return Resolve(implicitCall.iCS_S_VariableOrProcedureCall())
653+
?? Resolve(implicitCall.iCS_S_ProcedureOrArrayCall())
654+
?? Resolve(implicitCall.iCS_S_DictionaryCall())
655+
?? Resolve(implicitCall.iCS_S_MembersCall());
608656
}
609657

610658
return matches.SingleOrDefault(m => m.ParentScope == _currentScope);
611659
}
612660

613661
private bool IsCurrentScopeMember(DeclarationType accessorType, Declaration declaration)
614662
{
615-
if (declaration.Scope != _currentScope && accessorType != DeclarationType.Class)
663+
if (declaration.Scope != ModuleScope && accessorType != DeclarationType.Class)
616664
{
617665
return false;
618666
}

0 commit comments

Comments
 (0)