Skip to content

Commit 7415d64

Browse files
committed
Set up infrastructure to store failed procedure coercions
1 parent 94d8596 commit 7415d64

10 files changed

+159
-24
lines changed

Rubberduck.Parsing/Symbols/IDeclarationFinderFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ DeclarationFinder Create(
1414
IReadOnlyList<UnboundMemberDeclaration> unresolvedMemberDeclarations,
1515
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> unboundDefaultMemberAccesses,
1616
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedLetCoercions,
17+
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedProcedureCoercions,
1718
IHostApplication hostApp);
1819
void Release(DeclarationFinder declarationFinder);
1920
}

Rubberduck.Parsing/VBA/DeclarationCaching/ConcurrentlyConstructedDeclarationFinder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ public ConcurrentlyConstructedDeclarationFinder(
1818
IReadOnlyList<UnboundMemberDeclaration> unresolvedMemberDeclarations,
1919
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> unboundDefaultMemberAccesses,
2020
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedLetCoercions,
21+
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedProcedureCoercions,
2122
IHostApplication hostApp = null)
22-
:base(declarations, annotations, unresolvedMemberDeclarations, unboundDefaultMemberAccesses, failedLetCoercions, hostApp)
23+
:base(declarations, annotations, unresolvedMemberDeclarations, unboundDefaultMemberAccesses, failedLetCoercions, failedProcedureCoercions, hostApp)
2324
{}
2425

2526
protected override void ExecuteCollectionConstructionActions(List<Action> collectionConstructionActions)

Rubberduck.Parsing/VBA/DeclarationCaching/ConcurrentlyConstructedDeclarationFinderFactory.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ public DeclarationFinder Create(
1414
IReadOnlyList<UnboundMemberDeclaration> unresolvedMemberDeclarations,
1515
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> unboundDefaultMemberAccesses,
1616
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedLetCoercions,
17+
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedProcedureCoercions,
1718
IHostApplication hostApp)
1819
{
19-
return new ConcurrentlyConstructedDeclarationFinder(declarations, annotations, unresolvedMemberDeclarations, unboundDefaultMemberAccesses, failedLetCoercions, hostApp);
20+
return new ConcurrentlyConstructedDeclarationFinder(declarations, annotations, unresolvedMemberDeclarations, unboundDefaultMemberAccesses, failedLetCoercions, failedProcedureCoercions, hostApp);
2021
}
2122

2223
public void Release(DeclarationFinder declarationFinder)

Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinder.cs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public class DeclarationFinder
2525
private IDictionary<string, List<Declaration>> _declarationsByName;
2626
private IDictionary<QualifiedModuleName, List<Declaration>> _declarations;
2727
private readonly ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>> _newUnboundDefaultMemberAccesses;
28-
private readonly ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>> _newFailedLetCoersions;
28+
private readonly ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>> _newFailedLetCoercions;
29+
private readonly ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>> _newFailedProcedureCoercions;
2930
private readonly ConcurrentDictionary<QualifiedMemberName, ConcurrentBag<Declaration>> _newUndeclared;
3031
private readonly ConcurrentBag<UnboundMemberDeclaration> _newUnresolved;
3132
private List<UnboundMemberDeclaration> _unresolved;
@@ -42,6 +43,7 @@ public class DeclarationFinder
4243

4344
private readonly IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> _unboundDefaultMemberAccesses;
4445
private readonly IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> _failedLetCoercions;
46+
private readonly IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> _failedProcedureCoercions;
4547

4648
private Lazy<IDictionary<DeclarationType, List<Declaration>>> _builtInDeclarationsByType;
4749
private Lazy<IDictionary<Declaration, List<Declaration>>> _handlersByWithEventsField;
@@ -73,16 +75,19 @@ public DeclarationFinder(
7375
IReadOnlyList<UnboundMemberDeclaration> unresolvedMemberDeclarations,
7476
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> unboundDefaultMemberAccesses,
7577
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedLetCoercions,
78+
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedProcedureCoercions,
7679
IHostApplication hostApp = null)
7780
{
7881
_hostApp = hostApp;
7982
_unboundDefaultMemberAccesses = unboundDefaultMemberAccesses;
8083
_failedLetCoercions = failedLetCoercions;
84+
_failedProcedureCoercions = failedProcedureCoercions;
8185

8286
_newUndeclared = new ConcurrentDictionary<QualifiedMemberName, ConcurrentBag<Declaration>>(new Dictionary<QualifiedMemberName, ConcurrentBag<Declaration>>());
8387
_newUnresolved = new ConcurrentBag<UnboundMemberDeclaration>(new List<UnboundMemberDeclaration>());
8488
_newUnboundDefaultMemberAccesses = new ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>>();
85-
_newFailedLetCoersions = new ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>>();
89+
_newFailedLetCoercions = new ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>>();
90+
_newFailedProcedureCoercions = new ConcurrentDictionary<QualifiedModuleName, ConcurrentBag<IdentifierReference>>();
8691

8792
var collectionConstructionActions = CollectionConstructionActions(declarations, annotations, unresolvedMemberDeclarations);
8893
ExecuteCollectionConstructionActions(collectionConstructionActions);
@@ -351,14 +356,12 @@ public IEnumerable<Declaration> FindDeclarationsForSelection(QualifiedSelection
351356
.SelectMany(key => _declarationsBySelection[key]).Distinct();
352357
}
353358

354-
public IEnumerable<Declaration> FreshUndeclared => _newUndeclared.AllValues();
355-
356359
//This does not need a lock because enumerators over a ConcurrentBag uses a snapshot.
357360
public IEnumerable<UnboundMemberDeclaration> FreshUnresolvedMemberDeclarations => _newUnresolved.ToList();
358-
361+
public IEnumerable<Declaration> FreshUndeclared => _newUndeclared.AllValues();
359362
public IEnumerable<IdentifierReference> FreshUnboundDefaultMemberAccesses => _newUnboundDefaultMemberAccesses.AllValues();
360-
361-
public IEnumerable<IdentifierReference> FreshFailedLetCoercions => _newFailedLetCoersions.AllValues();
363+
public IEnumerable<IdentifierReference> FreshFailedLetCoercions => _newFailedLetCoercions.AllValues();
364+
public IEnumerable<IdentifierReference> FreshFailedProcedureCoercions => _newFailedProcedureCoercions.AllValues();
362365

363366
public IEnumerable<UnboundMemberDeclaration> UnresolvedMemberDeclarations => _unresolved;
364367

@@ -1076,8 +1079,14 @@ public void AddUnboundDefaultMemberAccess(IdentifierReference defaultMemberAcces
10761079

10771080
public void AddFailedLetCoercionReference(IdentifierReference failedLetCoercion)
10781081
{
1079-
var accesses = _newFailedLetCoersions.GetOrAdd(failedLetCoercion.QualifiedModuleName, new ConcurrentBag<IdentifierReference>());
1080-
accesses.Add(failedLetCoercion);
1082+
var failedCoercions = _newFailedLetCoercions.GetOrAdd(failedLetCoercion.QualifiedModuleName, new ConcurrentBag<IdentifierReference>());
1083+
failedCoercions.Add(failedLetCoercion);
1084+
}
1085+
1086+
public void AddFailedProcedureCoercionReference(IdentifierReference failedProcedureCoercion)
1087+
{
1088+
var failedCoercions = _newFailedProcedureCoercions.GetOrAdd(failedProcedureCoercion.QualifiedModuleName, new ConcurrentBag<IdentifierReference>());
1089+
failedCoercions.Add(failedProcedureCoercion);
10811090
}
10821091

10831092
public Declaration OnBracketedExpression(string expression, ParserRuleContext context)
@@ -1565,5 +1574,24 @@ public IEnumerable<IdentifierReference> FailedLetCoercions()
15651574
return _failedLetCoercions.Values
15661575
.SelectMany(coercion => coercion);
15671576
}
1577+
1578+
/// <summary>
1579+
/// Gets the failed procedure coercions in a module.
1580+
/// </summary>
1581+
public IReadOnlyCollection<IdentifierReference> FailedProcedureCoercions(QualifiedModuleName module)
1582+
{
1583+
return _failedProcedureCoercions.TryGetValue(module, out var failedProcedureCoercions)
1584+
? failedProcedureCoercions
1585+
: new HashSet<IdentifierReference>();
1586+
}
1587+
1588+
/// <summary>
1589+
/// Gets all failed procedure coercions.
1590+
/// </summary>
1591+
public IEnumerable<IdentifierReference> FailedProcedureCoercions()
1592+
{
1593+
return _failedProcedureCoercions.Values
1594+
.SelectMany(coercion => coercion);
1595+
}
15681596
}
15691597
}

Rubberduck.Parsing/VBA/DeclarationCaching/DeclarationFinderFactory.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ public DeclarationFinder Create(IReadOnlyList<Declaration> declarations,
1313
IReadOnlyList<UnboundMemberDeclaration> unresolvedMemberDeclarations,
1414
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> unboundDefaultMemberAccesses,
1515
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedLetCoercions,
16+
IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> failedProcedureCoercions,
1617
IHostApplication hostApp)
1718
{
18-
return new DeclarationFinder(declarations, annotations, unresolvedMemberDeclarations, unboundDefaultMemberAccesses, failedLetCoercions, hostApp);
19+
return new DeclarationFinder(declarations, annotations, unresolvedMemberDeclarations, unboundDefaultMemberAccesses, failedLetCoercions, failedProcedureCoercions, hostApp);
1920
}
2021

2122
public void Release(DeclarationFinder declarationFinder)

Rubberduck.Parsing/VBA/ModuleState.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,17 @@ public class ModuleState
2626
public SyntaxErrorException ModuleException { get; private set; }
2727
public IDictionary<(string scopeIdentifier, DeclarationType scopeType), Attributes> ModuleAttributes { get; private set; }
2828
public IDictionary<(string scopeIdentifier, DeclarationType scopeType), ParserRuleContext> MembersAllowingAttributes { get; private set; }
29+
2930
public IReadOnlyCollection<IdentifierReference> UnboundDefaultMemberAccesses => _unboundDefaultMemberAccesses.ToList();
3031
public IReadOnlyCollection<IdentifierReference> FailedLetCoercions => _failedLetCoercions.ToList();
32+
public IReadOnlyCollection<IdentifierReference> FailedProcedureCoercions => _failedProcedureCoercions.ToList();
3133

3234
public bool IsNew { get; private set; }
3335
public bool IsMarkedAsModified { get; private set; }
3436

3537
private readonly HashSet<IdentifierReference> _unboundDefaultMemberAccesses = new HashSet<IdentifierReference>();
3638
private readonly HashSet<IdentifierReference> _failedLetCoercions = new HashSet<IdentifierReference>();
39+
private readonly HashSet<IdentifierReference> _failedProcedureCoercions = new HashSet<IdentifierReference>();
3740

3841
public ModuleState(ConcurrentDictionary<Declaration, byte> declarations)
3942
{
@@ -172,12 +175,12 @@ public void ClearUnboundDefaultMemberAccesses()
172175
_unboundDefaultMemberAccesses.Clear();
173176
}
174177

175-
public ModuleState AddFailedLetCoercion(IdentifierReference failedLetCoercion)
178+
public ModuleState AddFailedLetCoercion(IdentifierReference failedProcedureCoercion)
176179
{
177-
if (failedLetCoercion.IsDefaultMemberAccess
178-
&& !_failedLetCoercions.Contains(failedLetCoercion))
180+
if (failedProcedureCoercion.IsDefaultMemberAccess
181+
&& !_failedLetCoercions.Contains(failedProcedureCoercion))
179182
{
180-
_failedLetCoercions.Add(failedLetCoercion);
183+
_failedLetCoercions.Add(failedProcedureCoercion);
181184
}
182185

183186
return this;
@@ -188,6 +191,22 @@ public void ClearFailedLetCoercions()
188191
_failedLetCoercions.Clear();
189192
}
190193

194+
public ModuleState AddFailedProcedureCoercion(IdentifierReference failedLetCoercion)
195+
{
196+
if (failedLetCoercion.IsDefaultMemberAccess
197+
&& !_failedProcedureCoercions.Contains(failedLetCoercion))
198+
{
199+
_failedProcedureCoercions.Add(failedLetCoercion);
200+
}
201+
202+
return this;
203+
}
204+
205+
public void ClearFailedProcedureCoercions()
206+
{
207+
_failedProcedureCoercions.Clear();
208+
}
209+
191210
public void MarkAsModified()
192211
{
193212
IsMarkedAsModified = true;
@@ -208,7 +227,8 @@ public void Dispose()
208227
ModuleAttributes?.Clear();
209228
_unboundDefaultMemberAccesses?.Clear();
210229
_failedLetCoercions?.Clear();
211-
230+
_failedProcedureCoercions?.Clear();
231+
212232
_isDisposed = true;
213233
}
214234
}

Rubberduck.Parsing/VBA/ReferenceManagement/BoundExpressionVisitor.cs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -610,14 +610,21 @@ private void Visit(
610610
{
611611
Visit(expression.WrappedExpression, module, scope, parent);
612612

613-
if (expression.Classification != ExpressionClassification.Unbound
614-
&& expression.ReferencedDeclaration != null)
615-
{
616-
AddDefaultMemberReference(expression, module, scope, parent);
617-
}
618-
else
613+
switch (expression.Classification)
619614
{
620-
AddUnboundDefaultMemberReference(expression, module, scope, parent);
615+
case ExpressionClassification.ResolutionFailed:
616+
AddFailedProcedureCoercionReference(expression, module, scope, parent);
617+
break;
618+
case ExpressionClassification.Unbound:
619+
AddUnboundDefaultMemberReference(expression, module, scope, parent);
620+
break;
621+
default:
622+
if (expression.ReferencedDeclaration != null)
623+
{
624+
AddDefaultMemberReference(expression, module, scope, parent);
625+
}
626+
627+
break;
621628
}
622629
}
623630

@@ -679,6 +686,33 @@ private void AddUnboundDefaultMemberReference(
679686
_declarationFinder.AddUnboundDefaultMemberAccess(reference);
680687
}
681688

689+
private void AddFailedProcedureCoercionReference(
690+
ProcedureCoercionExpression expression,
691+
QualifiedModuleName module,
692+
Declaration scope,
693+
Declaration parent)
694+
{
695+
var callSiteContext = expression.Context;
696+
var identifier = callSiteContext.GetText();
697+
var selection = callSiteContext.GetSelection();
698+
var callee = expression.ReferencedDeclaration;
699+
var reference = new IdentifierReference(
700+
module,
701+
scope,
702+
parent,
703+
identifier,
704+
selection,
705+
callSiteContext,
706+
callee,
707+
false,
708+
false,
709+
FindIdentifierAnnotations(module, selection.StartLine),
710+
false,
711+
isNonIndexedDefaultMemberAccess: true,
712+
defaultMemberRecursionDepth: expression.DefaultMemberRecursionDepth);
713+
_declarationFinder.AddFailedProcedureCoercionReference(reference);
714+
}
715+
682716
private void Visit(
683717
NewExpression expression,
684718
QualifiedModuleName module,

Rubberduck.Parsing/VBA/ReferenceManagement/ReferenceResolveRunnerBase.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ public void ResolveReferences(IReadOnlyCollection<QualifiedModuleName> toResolve
116116
AddNewUnresolvedMemberDeclarations();
117117
AddNewUnboundDefaultMemberAccesses();
118118
AddNewFailedLetCoercions();
119+
AddNewFailedProcedureCoercions();
119120

120121
_toResolve.Clear();
121122
}
@@ -129,6 +130,7 @@ private void PerformPreResolveCleanup(IReadOnlyCollection<QualifiedModuleName> t
129130
{
130131
_state.ClearUnboundDefaultMemberAccesses(module);
131132
_state.ClearFailedLetCoercions(module);
133+
_state.ClearFailedProcedureCoercions(module);
132134
}
133135
}
134136

@@ -325,5 +327,15 @@ private void AddNewFailedLetCoercions()
325327
_state.AddFailedLetCoercions(coercion.Key, coercion);
326328
}
327329
}
330+
331+
private void AddNewFailedProcedureCoercions()
332+
{
333+
var failedProcedureCoercions = _state.DeclarationFinder.FreshFailedProcedureCoercions
334+
.GroupBy(coercion => coercion.QualifiedModuleName);
335+
foreach (var coercion in failedProcedureCoercions)
336+
{
337+
_state.AddFailedProcedureCoercions(coercion.Key, coercion);
338+
}
339+
}
328340
}
329341
}

Rubberduck.Parsing/VBA/RubberduckParserState.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ private void RefreshFinder(IHostApplication host)
196196
AllUnresolvedMemberDeclarationsFromModuleStates,
197197
AllUnboundDefaultMemberAccessesFromModuleStates,
198198
AllFailedLetCoercionsFromModuleStates,
199+
AllFailedProcedureCoercionsFromModuleStates,
199200
host);
200201
_declarationFinderFactory.Release(oldDeclarationFinder);
201202
}
@@ -787,6 +788,23 @@ private IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierR
787788
}
788789
}
789790

791+
/// <summary>
792+
/// Gets a copy of the failed procedure coercions directly from the module states. (Used for refreshing the DeclarationFinder.)
793+
/// </summary>
794+
private IReadOnlyDictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>> AllFailedProcedureCoercionsFromModuleStates
795+
{
796+
get
797+
{
798+
var failedProcedureCoercions = new Dictionary<QualifiedModuleName, IReadOnlyCollection<IdentifierReference>>();
799+
foreach (var (module, state) in _moduleStates)
800+
{
801+
failedProcedureCoercions.Add(module, state.FailedProcedureCoercions);
802+
}
803+
804+
return failedProcedureCoercions;
805+
}
806+
}
807+
790808
/// <summary>
791809
/// Gets a copy of the collected declarations, excluding the built-in ones.
792810
/// </summary>
@@ -899,6 +917,23 @@ public void ClearFailedLetCoercions(QualifiedModuleName module)
899917
}
900918
}
901919

920+
public void AddFailedProcedureCoercions(QualifiedModuleName module, IEnumerable<IdentifierReference> failedProcedureCoercions)
921+
{
922+
var moduleState = _moduleStates.GetOrAdd(module, new ModuleState(new ConcurrentDictionary<Declaration, byte>()));
923+
foreach (var failedProcedureCoercion in failedProcedureCoercions)
924+
{
925+
moduleState.AddFailedProcedureCoercion(failedProcedureCoercion);
926+
}
927+
}
928+
929+
public void ClearFailedProcedureCoercions(QualifiedModuleName module)
930+
{
931+
if (_moduleStates.TryGetValue(module, out var moduleState))
932+
{
933+
moduleState.ClearFailedProcedureCoercions();
934+
}
935+
}
936+
902937
public void ClearStateCache(string projectId)
903938
{
904939
try

0 commit comments

Comments
 (0)