Skip to content

Commit 491b3b6

Browse files
committed
nested with blocks work, everything seems to resolve correctly.
1 parent 4d05bd1 commit 491b3b6

File tree

2 files changed

+63
-50
lines changed

2 files changed

+63
-50
lines changed

Rubberduck.Parsing/Symbols/IdentifierReferenceResolver.cs

Lines changed: 63 additions & 49 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.Text;
45
using Antlr4.Runtime;
56
using Rubberduck.Parsing.Grammar;
67
using Rubberduck.VBEditor;
@@ -181,7 +182,7 @@ private Declaration ResolveType(VBAParser.ImplicitCallStmt_InStmtContext context
181182

182183
var type = ResolveInternal(context.iCS_S_VariableOrProcedureCall(), localScope)
183184
?? ResolveInternal(context.iCS_S_ProcedureOrArrayCall(), localScope)
184-
?? ResolveInternal(context.iCS_S_MembersCall(), localScope)
185+
?? ResolveInternal(context.iCS_S_MembersCall(), ContextAccessorType.GetValueOrReference)
185186
?? ResolveInternal(dictionaryCall, localScope, ContextAccessorType.GetValueOrReference, dictionaryCall == null ? null : dictionaryCall.dictionaryCallStmt());
186187

187188
return ResolveType(type);
@@ -223,7 +224,7 @@ private Declaration ResolveType(Declaration parent)
223224

224225
private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declaration localScope, ContextAccessorType accessorType = ContextAccessorType.GetValueOrReference, VBAParser.DictionaryCallStmtContext fieldCall = null, bool hasExplicitLetStatement = false, bool isAssignmentTarget = false)
225226
{
226-
if (callSiteContext == null)
227+
if (callSiteContext == null || _alreadyResolved.Contains(callSiteContext))
227228
{
228229
return null;
229230
}
@@ -233,32 +234,11 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
233234
throw new ArgumentException("'" + callSiteContext.GetType().Name + "' is not an identifier context.", "callSiteContext");
234235
}
235236

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-
252237
if (localScope == null)
253238
{
254239
localScope = _currentScope;
255240
}
256241

257-
if (_withBlockQualifiers.Any())
258-
{
259-
localScope = _withBlockQualifiers.Peek();
260-
}
261-
262242
var identifierName = callSiteContext.GetText();
263243
Declaration callee;
264244
if (localScope.DeclarationType == DeclarationType.Variable)
@@ -270,8 +250,8 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
270250
else
271251
{
272252
callee = FindLocalScopeDeclaration(identifierName, localScope)
273-
?? FindModuleScopeDeclaration(identifierName, localScope)
274253
?? FindModuleScopeProcedure(identifierName, localScope, accessorType, isAssignmentTarget)
254+
?? FindModuleScopeDeclaration(identifierName, localScope)
275255
?? FindProjectScopeDeclaration(identifierName);
276256
}
277257

@@ -281,8 +261,8 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
281261
localScope = _currentScope;
282262
identifierName = callSiteContext.GetText();
283263
callee = FindLocalScopeDeclaration(identifierName, localScope)
284-
?? FindModuleScopeDeclaration(identifierName, localScope)
285264
?? FindModuleScopeProcedure(identifierName, localScope, accessorType, isAssignmentTarget)
265+
?? FindModuleScopeDeclaration(identifierName, localScope)
286266
?? FindProjectScopeDeclaration(identifierName);
287267
}
288268

@@ -294,6 +274,7 @@ private Declaration ResolveInternal(ParserRuleContext callSiteContext, Declarati
294274
var reference = CreateReference(callSiteContext, callee, isAssignmentTarget, hasExplicitLetStatement);
295275
callee.AddReference(reference);
296276
_alreadyResolved.Add(reference.Context);
277+
_alreadyResolved.Add(callSiteContext);
297278

298279
if (fieldCall != null)
299280
{
@@ -362,13 +343,20 @@ private Declaration ResolveInternal(VBAParser.ICS_S_MembersCallContext context,
362343
return null;
363344
}
364345

365-
if (localScope == null)
346+
Declaration parent;
347+
if (_withBlockQualifiers.Any())
366348
{
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);
368359
}
369-
370-
var parent = ResolveInternal(context.iCS_S_ProcedureOrArrayCall(), localScope, accessorType, hasExplicitLetStatement, isAssignmentTarget)
371-
?? ResolveInternal(context.iCS_S_VariableOrProcedureCall(), localScope, accessorType, hasExplicitLetStatement, isAssignmentTarget);
372360

373361
if (parent != null)
374362
{
@@ -381,17 +369,25 @@ private Declaration ResolveInternal(VBAParser.ICS_S_MembersCallContext context,
381369
}
382370

383371
var chainedCalls = context.iCS_S_MemberCall();
372+
var lastCall = chainedCalls.Last();
384373
foreach (var memberCall in chainedCalls)
385374
{
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);
388384

389385
if (member == null)
390386
{
391387
return null;
392388
}
393389

394-
parent = member;
390+
parent = ResolveType(member);
395391
}
396392

397393
var fieldCall = context.dictionaryCallStmt();
@@ -522,8 +518,16 @@ public void Resolve(VBAParser.ICS_S_MembersCallContext context)
522518
return;
523519
}
524520

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+
}
527531

528532
if (parent != null && parent.Context != null)
529533
{
@@ -545,7 +549,7 @@ public void Resolve(VBAParser.ICS_S_MembersCallContext context)
545549
return;
546550
}
547551

548-
parent = member;
552+
parent = ResolveType(member);
549553
}
550554

551555
var fieldCall = context.dictionaryCallStmt();
@@ -569,14 +573,7 @@ private void TryResolve<TContext>(TContext context) where TContext : ParserRuleC
569573
return;
570574
}
571575

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);
580577
}
581578

582579
public void Resolve(VBAParser.LetStmtContext context)
@@ -726,6 +723,12 @@ private Declaration FindLocalScopeDeclaration(string identifierName, Declaration
726723
localScope = _currentScope;
727724
}
728725

726+
if (_moduleTypes.Contains(localScope.DeclarationType))
727+
{
728+
// "local scope" is not intended to be module level.
729+
return null;
730+
}
731+
729732
if (localScope.DeclarationType == DeclarationType.Function ||
730733
localScope.DeclarationType == DeclarationType.PropertyGet)
731734
{
@@ -762,8 +765,17 @@ private Declaration FindModuleScopeProcedure(string identifierName, Declaration
762765
}
763766

764767
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+
}
767779
}
768780

769781
private Declaration FindProjectScopeDeclaration(string identifierName)
@@ -776,10 +788,12 @@ private Declaration FindProjectScopeDeclaration(string identifierName)
776788
|| _moduleTypes.Contains(item.DeclarationType) /* because static classes are accessed just like modules */));
777789
}
778790

779-
private bool IsProcedure(Declaration item)
791+
private bool IsProcedure(Declaration item, Declaration localScope)
780792
{
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);
783797
}
784798

785799
private bool IsPropertyAccessor(Declaration item, ContextAccessorType accessorType, Declaration localScope, bool isAssignmentTarget = false)

Rubberduck.Parsing/VBProjectParseResult.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using Antlr4.Runtime.Tree;
55
using Microsoft.Vbe.Interop;
66
using Rubberduck.Parsing.Symbols;
7-
using Rubberduck.VBA;
87
using Rubberduck.VBEditor;
98

109
namespace Rubberduck.Parsing

0 commit comments

Comments
 (0)