Skip to content

Commit 2563ed3

Browse files
committed
fixed parameterized property argument resolution
1 parent 41b736b commit 2563ed3

File tree

2 files changed

+84
-36
lines changed

2 files changed

+84
-36
lines changed

RetailCoder.VBE/VBA/RubberduckParser.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ public void RemoveProject(VBProject project)
4646

4747
public async Task<VBProjectParseResult> ParseAsync(VBProject project)
4848
{
49-
//return await Task.Run(() => Parse(project));
50-
// note: the above seems to cause an AccessViolationException
51-
return Parse(project);
49+
return await Task.Run(() => Parse(project));
50+
// note: the above has been seen to cause issues with VBProject.Equals and break navigation...
51+
//return Parse(project);
5252
}
5353

5454
public VBProjectParseResult Parse(VBProject project)

Rubberduck.Parsing/Symbols/IdentifierReferenceListener.cs

Lines changed: 81 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using Antlr4.Runtime;
55
using Antlr4.Runtime.Tree;
6+
using Microsoft.Vbe.Interop;
67
using Rubberduck.Parsing.Grammar;
78

89
namespace Rubberduck.Parsing.Symbols
@@ -13,6 +14,7 @@ public class IdentifierReferenceListener : VBABaseListener
1314
private readonly QualifiedModuleName _qualifiedName;
1415

1516
private string _currentScope;
17+
private DeclarationType _currentScopeType;
1618

1719
public IdentifierReferenceListener(VBComponentParseResult result, Declarations declarations)
1820
: this(result.QualifiedName, declarations)
@@ -33,15 +35,19 @@ public IdentifierReferenceListener(QualifiedModuleName qualifiedName, Declaratio
3335
private void SetCurrentScope()
3436
{
3537
_currentScope = ModuleScope;
38+
_currentScopeType = _qualifiedName.Component.Type == vbext_ComponentType.vbext_ct_StdModule
39+
? DeclarationType.Module
40+
: DeclarationType.Class;
3641
}
3742

3843
/// <summary>
3944
/// Sets current scope to specified module member.
4045
/// </summary>
4146
/// <param name="name">The name of the member owning the current scope.</param>
42-
private void SetCurrentScope(string name)
47+
private void SetCurrentScope(string name, DeclarationType scopeType)
4348
{
4449
_currentScope = _qualifiedName + "." + name;
50+
_currentScopeType = scopeType;
4551
}
4652

4753
public override void EnterLiteral(VBAParser.LiteralContext context)
@@ -81,7 +87,7 @@ private void HandleNumberLiteral(ITerminalNode numberLiteral)
8187

8288
public override void EnterSubStmt(VBAParser.SubStmtContext context)
8389
{
84-
SetCurrentScope(context.ambiguousIdentifier().GetText());
90+
SetCurrentScope(context.ambiguousIdentifier().GetText(), DeclarationType.Procedure);
8591
}
8692

8793
public override void ExitSubStmt(VBAParser.SubStmtContext context)
@@ -91,7 +97,7 @@ public override void ExitSubStmt(VBAParser.SubStmtContext context)
9197

9298
public override void EnterFunctionStmt(VBAParser.FunctionStmtContext context)
9399
{
94-
SetCurrentScope(context.ambiguousIdentifier().GetText());
100+
SetCurrentScope(context.ambiguousIdentifier().GetText(), DeclarationType.Function);
95101
}
96102

97103
public override void ExitFunctionStmt(VBAParser.FunctionStmtContext context)
@@ -101,7 +107,7 @@ public override void ExitFunctionStmt(VBAParser.FunctionStmtContext context)
101107

102108
public override void EnterPropertyGetStmt(VBAParser.PropertyGetStmtContext context)
103109
{
104-
SetCurrentScope(context.ambiguousIdentifier().GetText());
110+
SetCurrentScope(context.ambiguousIdentifier().GetText(), DeclarationType.PropertyGet);
105111
}
106112

107113
public override void ExitPropertyGetStmt(VBAParser.PropertyGetStmtContext context)
@@ -111,7 +117,7 @@ public override void ExitPropertyGetStmt(VBAParser.PropertyGetStmtContext contex
111117

112118
public override void EnterPropertyLetStmt(VBAParser.PropertyLetStmtContext context)
113119
{
114-
SetCurrentScope(context.ambiguousIdentifier().GetText());
120+
SetCurrentScope(context.ambiguousIdentifier().GetText(), DeclarationType.PropertyLet);
115121
}
116122

117123
public override void ExitPropertyLetStmt(VBAParser.PropertyLetStmtContext context)
@@ -121,7 +127,7 @@ public override void ExitPropertyLetStmt(VBAParser.PropertyLetStmtContext contex
121127

122128
public override void EnterPropertySetStmt(VBAParser.PropertySetStmtContext context)
123129
{
124-
SetCurrentScope(context.ambiguousIdentifier().GetText());
130+
SetCurrentScope(context.ambiguousIdentifier().GetText(), DeclarationType.PropertySet);
125131
}
126132

127133
public override void ExitPropertySetStmt(VBAParser.PropertySetStmtContext context)
@@ -153,15 +159,15 @@ public override void EnterSetStmt(VBAParser.SetStmtContext context)
153159
private VBAParser.AmbiguousIdentifierContext FindAssignmentTarget(VBAParser.ImplicitCallStmt_InStmtContext leftSide, DeclarationType accessorType)
154160
{
155161
VBAParser.AmbiguousIdentifierContext context;
156-
var call = Resolve(leftSide.iCS_S_ProcedureOrArrayCall(), out context)
157-
?? Resolve(leftSide.iCS_S_VariableOrProcedureCall(), out context)
158-
?? Resolve(leftSide.iCS_S_DictionaryCall(), out context)
159-
?? Resolve(leftSide.iCS_S_MembersCall(), out context);
162+
var call = Resolve(leftSide.iCS_S_ProcedureOrArrayCall(), out context, accessorType)
163+
?? Resolve(leftSide.iCS_S_VariableOrProcedureCall(), out context, accessorType)
164+
?? Resolve(leftSide.iCS_S_DictionaryCall(), out context, accessorType)
165+
?? Resolve(leftSide.iCS_S_MembersCall(), out context, accessorType);
160166

161167
return context;
162168
}
163169

164-
private VBAParser.AmbiguousIdentifierContext EnterDictionaryCall(VBAParser.DictionaryCallStmtContext dictionaryCall, VBAParser.AmbiguousIdentifierContext parentIdentifier = null)
170+
private VBAParser.AmbiguousIdentifierContext EnterDictionaryCall(VBAParser.DictionaryCallStmtContext dictionaryCall, VBAParser.AmbiguousIdentifierContext parentIdentifier = null, DeclarationType accessorType = DeclarationType.PropertyGet)
165171
{
166172
if (dictionaryCall == null)
167173
{
@@ -170,7 +176,8 @@ private VBAParser.AmbiguousIdentifierContext EnterDictionaryCall(VBAParser.Dicti
170176

171177
if (parentIdentifier != null)
172178
{
173-
if (!EnterIdentifier(parentIdentifier, parentIdentifier.GetSelection()))
179+
var isTarget = accessorType == DeclarationType.PropertyLet || accessorType == DeclarationType.PropertySet;
180+
if (!EnterIdentifier(parentIdentifier, parentIdentifier.GetSelection(), isTarget, accessorType:accessorType))
174181
// we're referencing "member" in "member!field"
175182
{
176183
return null;
@@ -306,7 +313,7 @@ public override void ExitWithStmt(VBAParser.WithStmtContext context)
306313
_withQualifiers.Pop();
307314
}
308315

309-
private Declaration Resolve(VBAParser.ICS_S_ProcedureOrArrayCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext)
316+
private Declaration Resolve(VBAParser.ICS_S_ProcedureOrArrayCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext, DeclarationType accessorType)
310317
{
311318
if (context == null)
312319
{
@@ -318,7 +325,7 @@ private Declaration Resolve(VBAParser.ICS_S_ProcedureOrArrayCallContext context,
318325
var name = identifier.GetText();
319326

320327
var procedure = FindProcedureDeclaration(name, identifier);
321-
var result = procedure ?? FindVariableDeclaration(name, identifier);
328+
var result = procedure ?? FindVariableDeclaration(name, identifier, accessorType);
322329

323330
identifierContext = result == null
324331
? null
@@ -331,10 +338,10 @@ private Declaration Resolve(VBAParser.ICS_S_ProcedureOrArrayCallContext context,
331338
private Declaration Resolve(VBAParser.ICS_S_ProcedureOrArrayCallContext context)
332339
{
333340
VBAParser.AmbiguousIdentifierContext discarded;
334-
return Resolve(context, out discarded);
341+
return Resolve(context, out discarded, DeclarationType.PropertyGet);
335342
}
336343

337-
private Declaration Resolve(VBAParser.ICS_S_VariableOrProcedureCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext)
344+
private Declaration Resolve(VBAParser.ICS_S_VariableOrProcedureCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext, DeclarationType accessorType)
338345
{
339346
if (context == null)
340347
{
@@ -345,8 +352,8 @@ private Declaration Resolve(VBAParser.ICS_S_VariableOrProcedureCallContext conte
345352
var identifier = context.ambiguousIdentifier();
346353
var name = identifier.GetText();
347354

348-
var procedure = FindProcedureDeclaration(name, identifier);
349-
var result = procedure ?? FindVariableDeclaration(name, identifier);
355+
var procedure = FindProcedureDeclaration(name, identifier, accessorType);
356+
var result = procedure ?? FindVariableDeclaration(name, identifier, accessorType);
350357

351358
identifierContext = result == null
352359
? null
@@ -359,21 +366,21 @@ private Declaration Resolve(VBAParser.ICS_S_VariableOrProcedureCallContext conte
359366
private Declaration Resolve(VBAParser.ICS_S_VariableOrProcedureCallContext context)
360367
{
361368
VBAParser.AmbiguousIdentifierContext discarded;
362-
return Resolve(context, out discarded);
369+
return Resolve(context, out discarded, DeclarationType.PropertyGet);
363370
}
364371

365-
private Declaration Resolve(VBAParser.ICS_S_DictionaryCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext, VBAParser.AmbiguousIdentifierContext parentIdentifier = null)
372+
private Declaration Resolve(VBAParser.ICS_S_DictionaryCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext, DeclarationType accessorType, VBAParser.AmbiguousIdentifierContext parentIdentifier = null)
366373
{
367374
if (context == null)
368375
{
369376
identifierContext = null;
370377
return null;
371378
}
372379

373-
var identifier = EnterDictionaryCall(context.dictionaryCallStmt(), parentIdentifier);
380+
var identifier = EnterDictionaryCall(context.dictionaryCallStmt(), parentIdentifier, accessorType);
374381
var name = identifier.GetText();
375382

376-
var result = FindVariableDeclaration(name, identifier);
383+
var result = FindVariableDeclaration(name, identifier, accessorType);
377384

378385
identifierContext = result == null
379386
? null
@@ -386,10 +393,10 @@ private Declaration Resolve(VBAParser.ICS_S_DictionaryCallContext context, out V
386393
private Declaration Resolve(VBAParser.ICS_S_DictionaryCallContext context, VBAParser.AmbiguousIdentifierContext parentIdentifier = null)
387394
{
388395
VBAParser.AmbiguousIdentifierContext discarded;
389-
return Resolve(context, out discarded, parentIdentifier);
396+
return Resolve(context, out discarded, DeclarationType.PropertyGet, parentIdentifier);
390397
}
391398

392-
private Declaration Resolve(VBAParser.ICS_S_MembersCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext)
399+
private Declaration Resolve(VBAParser.ICS_S_MembersCallContext context, out VBAParser.AmbiguousIdentifierContext identifierContext, DeclarationType accessorType)
393400
{
394401
if (context == null)
395402
{
@@ -434,7 +441,7 @@ private Declaration Resolve(VBAParser.ICS_S_MembersCallContext context, out VBAP
434441
private Declaration Resolve(VBAParser.ICS_S_MembersCallContext context)
435442
{
436443
VBAParser.AmbiguousIdentifierContext discarded;
437-
return Resolve(context, out discarded);
444+
return Resolve(context, out discarded, DeclarationType.PropertyGet);
438445
}
439446

440447
private Declaration Resolve(VBAParser.ICS_B_MemberProcedureCallContext context)
@@ -469,7 +476,7 @@ public override void EnterVsAssign(VBAParser.VsAssignContext context)
469476
var callStatementB = context.Parent.Parent.Parent as VBAParser.ICS_S_VariableOrProcedureCallContext;
470477
var callStatementC = context.Parent.Parent.Parent as VBAParser.ICS_B_MemberProcedureCallContext;
471478
var callStatementD = context.Parent.Parent.Parent as VBAParser.ICS_B_ProcedureCallContext;
472-
479+
473480
var procedureName = string.Empty;
474481
ParserRuleContext identifierContext = null;
475482
if (callStatementA != null)
@@ -545,13 +552,13 @@ private Declaration FindProcedureDeclaration(string procedureName, ParserRuleCon
545552
return procedure;
546553
}
547554

548-
private Declaration FindVariableDeclaration(string procedureName, ParserRuleContext context)
555+
private Declaration FindVariableDeclaration(string procedureName, ParserRuleContext context, DeclarationType accessorType)
549556
{
550557
var matches = _declarations[procedureName]
551558
.Where(declaration => declaration.DeclarationType == DeclarationType.Variable || declaration.DeclarationType == DeclarationType.Parameter)
552559
.Where(IsInScope);
553560

554-
var variable = GetClosestScopeDeclaration(matches, context);
561+
var variable = GetClosestScopeDeclaration(matches, context, accessorType);
555562
return variable;
556563
}
557564

@@ -602,6 +609,13 @@ private bool IsInScope(Declaration declaration)
602609
|| IsGlobalProcedure(declaration);
603610
}
604611

612+
private static readonly Type[] PropertyContexts =
613+
{
614+
typeof (VBAParser.PropertyGetStmtContext),
615+
typeof (VBAParser.PropertyLetStmtContext),
616+
typeof (VBAParser.PropertySetStmtContext)
617+
};
618+
605619
private Declaration GetClosestScopeDeclaration(IEnumerable<Declaration> declarations, ParserRuleContext context, DeclarationType accessorType = DeclarationType.PropertyGet)
606620
{
607621
if (context.Parent.Parent.Parent is VBAParser.AsTypeClauseContext)
@@ -615,11 +629,19 @@ private Declaration GetClosestScopeDeclaration(IEnumerable<Declaration> declarat
615629
return null;
616630
}
617631

618-
var currentScope = matches.SingleOrDefault(declaration => declaration.Scope == _currentScope
619-
&& !PropertyAccessors.Contains(declaration.DeclarationType));
620-
if (currentScope != null)
632+
// handle indexed property getters
633+
var currentScopeMatches = matches.Where(declaration =>
634+
(declaration.Scope == _currentScope && !PropertyContexts.Contains(declaration.Context.Parent.Parent.GetType()))
635+
|| ((declaration.Context != null && declaration.Context.Parent.Parent is VBAParser.PropertyGetStmtContext
636+
&& _currentScopeType == DeclarationType.PropertyGet)
637+
|| (declaration.Context != null && declaration.Context.Parent.Parent is VBAParser.PropertySetStmtContext
638+
&& _currentScopeType == DeclarationType.PropertySet)
639+
|| (declaration.Context != null && declaration.Context.Parent.Parent is VBAParser.PropertyLetStmtContext
640+
&& _currentScopeType == DeclarationType.PropertyLet)))
641+
.ToList();
642+
if (currentScopeMatches.Count == 1)
621643
{
622-
return currentScope;
644+
return currentScopeMatches[0];
623645
}
624646

625647
// note: commented-out because it breaks the UDT member references, but property getters behave strangely still
@@ -644,6 +666,32 @@ private Declaration GetClosestScopeDeclaration(IEnumerable<Declaration> declarat
644666
return moduleScope;
645667
}
646668

669+
var splitScope = _currentScope.Split('.');
670+
if (splitScope.Length > 2) // Project.Module.Procedure - i.e. if scope is deeper than module-level
671+
{
672+
var scope = splitScope[0] + '.' + splitScope[1];
673+
var scopeMatches = matches.Where(m => m.ParentScope == scope
674+
&& (!PropertyAccessors.Contains(m.DeclarationType)
675+
|| m.DeclarationType == accessorType)).ToList();
676+
if (scopeMatches.Count == 1)
677+
{
678+
return scopeMatches.Single();
679+
}
680+
681+
// handle standard library member shadowing:
682+
if (!matches.All(m => m.IsBuiltIn))
683+
{
684+
var ambiguousMatches = matches.Where(m => !m.IsBuiltIn
685+
&& (!PropertyAccessors.Contains(m.DeclarationType)
686+
|| m.DeclarationType == accessorType)).ToList();
687+
688+
if (ambiguousMatches.Count == 1)
689+
{
690+
return ambiguousMatches.Single();
691+
}
692+
}
693+
}
694+
647695
var memberProcedureCallContext = context.Parent as VBAParser.ICS_B_MemberProcedureCallContext;
648696
if (memberProcedureCallContext != null)
649697
{
@@ -659,7 +707,7 @@ private Declaration GetClosestScopeDeclaration(IEnumerable<Declaration> declarat
659707
?? Resolve(implicitCall.iCS_S_MembersCall());
660708
}
661709

662-
return matches.SingleOrDefault(m => m.ParentScope == _currentScope);
710+
return null;
663711
}
664712

665713
private bool IsCurrentScopeMember(DeclarationType accessorType, Declaration declaration)

0 commit comments

Comments
 (0)