Skip to content

Commit 1a6df5f

Browse files
committed
Generate argument references for parameters
In other words, resolve which parameters arguments correspond to and save corresponding identifier references on a new collection on the parameter declaration. Also adds Let coercion resolution for the index in array accesses and improves the handling of joined resolution failed expressions. (Now, they always have a context.)
1 parent 2de65f7 commit 1a6df5f

File tree

10 files changed

+243
-29
lines changed

10 files changed

+243
-29
lines changed

Rubberduck.Parsing/Binding/ArgumentListArgument.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,26 @@ public ArgumentListArgument(IExpressionBinding binding, ParserRuleContext contex
2525
ArgumentType = argumentType;
2626
_namedArgumentExpressionCreator = namedArgumentExpressionCreator;
2727
_isAddressOfArgument = isAddressOfArgument;
28+
ReferencedParameter = null;
2829
}
2930

3031
public ArgumentListArgumentType ArgumentType { get; }
3132
public IBoundExpression NamedArgumentExpression { get; private set; }
3233
public IBoundExpression Expression { get; private set; }
34+
public ParameterDeclaration ReferencedParameter { get; private set; }
3335

34-
public void Resolve(Declaration calledProcedure, int parameterIndex)
36+
public void Resolve(Declaration calledProcedure, int parameterIndex, bool isArrayAccess = false)
3537
{
3638
var binding = _binding;
3739
if (calledProcedure != null)
3840
{
3941
NamedArgumentExpression = _namedArgumentExpressionCreator(calledProcedure);
42+
ReferencedParameter = ResolveReferencedParameter(calledProcedure, parameterIndex);
4043

41-
if (!_isAddressOfArgument && !CanBeObject(calledProcedure, parameterIndex))
44+
if (!_isAddressOfArgument
45+
&& (isArrayAccess
46+
|| ReferencedParameter != null
47+
&& !CanBeObject(ReferencedParameter)))
4248
{
4349
binding = new LetCoercionDefaultBinding(_context, binding);
4450
}
@@ -47,28 +53,25 @@ public void Resolve(Declaration calledProcedure, int parameterIndex)
4753
Expression = binding.Resolve();
4854
}
4955

50-
private bool CanBeObject(Declaration calledProcedure, int parameterIndex)
56+
private ParameterDeclaration ResolveReferencedParameter(Declaration calledProcedure, int parameterIndex)
5157
{
5258
if (NamedArgumentExpression != null)
5359
{
54-
var correspondingParameter = NamedArgumentExpression.ReferencedDeclaration as ParameterDeclaration;
55-
return CanBeObject(correspondingParameter);
60+
return NamedArgumentExpression.ReferencedDeclaration as ParameterDeclaration;
5661
}
5762

5863
if (parameterIndex >= 0 && calledProcedure is IParameterizedDeclaration parameterizedDeclaration)
5964
{
6065
var parameters = parameterizedDeclaration.Parameters.ToList();
6166
if (parameterIndex >= parameters.Count)
6267
{
63-
return parameters.Any(param => param.IsParamArray);
68+
return parameters.FirstOrDefault(param => param.IsParamArray);
6469
}
6570

66-
var correspondingParameter = parameters[parameterIndex];
67-
return CanBeObject(correspondingParameter);
68-
71+
return parameters[parameterIndex];
6972
}
7073

71-
return true;
74+
return null;
7275
}
7376

7477
private bool CanBeObject(ParameterDeclaration parameter)

Rubberduck.Parsing/Binding/Bindings/BinaryOpDefaultBinding.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ public IBoundExpression Resolve()
2626
if (leftExpr.Classification == ExpressionClassification.ResolutionFailed)
2727
{
2828
var failedExpr = (ResolutionFailedExpression) leftExpr;
29-
return failedExpr.Join(rightExpr);
29+
return failedExpr.Join(_context, rightExpr);
3030
}
3131

3232
if (rightExpr.Classification == ExpressionClassification.ResolutionFailed)
3333
{
3434
var failedExpr = (ResolutionFailedExpression)rightExpr;
35-
return failedExpr.Join(leftExpr);
35+
return failedExpr.Join(_context, leftExpr);
3636
}
3737

3838
return new BinaryOpExpression(null, _context, leftExpr, rightExpr);

Rubberduck.Parsing/Binding/Bindings/DictionaryAccessDefaultBinding.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ private static IBoundExpression Resolve(IBoundExpression lExpression, ArgumentLi
6767

6868
ResolveArgumentList(null, argumentList);
6969
var argumentExpressions = argumentList.Arguments.Select(arg => arg.Expression);
70-
return failedExpression.Join(argumentExpressions);
70+
return failedExpression.Join(expression, argumentExpressions);
7171
}
7272

7373
if (!(expression is VBAParser.LExpressionContext lExpressionContext))
@@ -107,7 +107,7 @@ private static IBoundExpression CreateFailedExpression(IBoundExpression lExpress
107107
failedExpr.AddSuccessfullyResolvedExpression(lExpression);
108108

109109
var argumentExpressions = argumentList.Arguments.Select(arg => arg.Expression);
110-
return failedExpr.Join(argumentExpressions);
110+
return failedExpr.Join(context, argumentExpressions);
111111
}
112112

113113
private static IBoundExpression ResolveViaDefaultMember(IBoundExpression lExpression, string asTypeName, Declaration asTypeDeclaration, ArgumentList argumentList, ParserRuleContext expression, ParserRuleContext defaultMemberContext, int recursionDepth = 1, RecursiveDefaultMemberAccessExpression containedExpression = null)

Rubberduck.Parsing/Binding/Bindings/IndexDefaultBinding.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ public IndexDefaultBinding(
4444
_argumentList = argumentList;
4545
}
4646

47-
private static void ResolveArgumentList(Declaration calledProcedure, ArgumentList argumentList)
47+
private static void ResolveArgumentList(Declaration calledProcedure, ArgumentList argumentList, bool isArrayAccess = false)
4848
{
4949
var arguments = argumentList.Arguments;
5050
for (var index = 0; index < arguments.Count; index++)
5151
{
52-
arguments[index].Resolve(calledProcedure, index);
52+
arguments[index].Resolve(calledProcedure, index, isArrayAccess);
5353
}
5454
}
5555

@@ -71,7 +71,7 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
7171

7272
ResolveArgumentList(null, argumentList);
7373
var argumentExpressions = argumentList.Arguments.Select(arg => arg.Expression);
74-
return failedExpression.Join(argumentExpressions);
74+
return failedExpression.Join(expression, argumentExpressions);
7575
}
7676

7777
if (lExpression.Classification == ExpressionClassification.Unbound)
@@ -130,7 +130,7 @@ private static IBoundExpression CreateFailedExpression(IBoundExpression lExpress
130130
var failedExpr = new ResolutionFailedExpression(context, isDefaultMemberResolution);
131131
failedExpr.AddSuccessfullyResolvedExpression(lExpression);
132132
var argumentExpressions = argumentList.Arguments.Select(arg => arg.Expression);
133-
return failedExpr.Join(argumentExpressions);
133+
return failedExpr.Join(context, argumentExpressions);
134134
}
135135

136136
private IBoundExpression ResolveLExpressionIsVariablePropertyFunctionNoParameters(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
@@ -359,7 +359,7 @@ declared type of the array’s element type.
359359
TODO: Implement compatibility checking
360360
*/
361361

362-
ResolveArgumentList(indexedDeclaration.AsTypeDeclaration, argumentList);
362+
ResolveArgumentList(indexedDeclaration, argumentList, true);
363363
return new IndexExpression(indexedDeclaration, ExpressionClassification.Variable, expression, _lExpression, argumentList, isArrayAccess: true, defaultMemberRecursionDepth: defaultMemberRecursionDepth, containedDefaultMemberRecursionExpression: containedExpression);
364364
}
365365

Rubberduck.Parsing/Binding/Bindings/TypeOfIsDefaultBinding.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ public IBoundExpression Resolve()
2626
if (expr.Classification == ExpressionClassification.ResolutionFailed)
2727
{
2828
var failedExpr = (ResolutionFailedExpression)expr;
29-
return failedExpr.Join(typeExpr);
29+
return failedExpr.Join(_context, typeExpr);
3030
}
3131

3232
if (typeExpr.Classification == ExpressionClassification.ResolutionFailed)
3333
{
3434
var failedExpr = (ResolutionFailedExpression)typeExpr;
35-
return failedExpr.Join(expr);
35+
return failedExpr.Join(_context, expr);
3636
}
3737

3838
return new TypeOfIsExpression(null, _context, expr, typeExpr);

Rubberduck.Parsing/Binding/Expressions/ResolutionFailedExpression.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public ResolutionFailedExpression(ParserRuleContext context, bool isDefaultMembe
1515
IsJoinedExpression = false;
1616
}
1717

18-
public ResolutionFailedExpression(params ResolutionFailedExpression[] expressions)
19-
: base(null, ExpressionClassification.ResolutionFailed, null)
18+
public ResolutionFailedExpression(ParserRuleContext context, params ResolutionFailedExpression[] expressions)
19+
: base(null, ExpressionClassification.ResolutionFailed, context)
2020
{
2121
IsDefaultMemberResolution = false;
2222
IsJoinedExpression = true;
@@ -41,17 +41,17 @@ public void AddSuccessfullyResolvedExpressions(IEnumerable<IBoundExpression> exp
4141

4242
public static class ResolutionFailedExpressionExtensions
4343
{
44-
public static ResolutionFailedExpression Join(this ResolutionFailedExpression expression, params IBoundExpression[] otherExpressions)
44+
public static ResolutionFailedExpression Join(this ResolutionFailedExpression expression, ParserRuleContext context, params IBoundExpression[] otherExpressions)
4545
{
46-
return expression.Join((IEnumerable<IBoundExpression>)otherExpressions);
46+
return expression.Join(context, (IEnumerable<IBoundExpression>)otherExpressions);
4747
}
4848

49-
public static ResolutionFailedExpression Join(this ResolutionFailedExpression expression, IEnumerable<IBoundExpression> otherExpressions)
49+
public static ResolutionFailedExpression Join(this ResolutionFailedExpression expression, ParserRuleContext context, IEnumerable<IBoundExpression> otherExpressions)
5050
{
5151
var otherExprs = otherExpressions.ToList();
5252

5353
var failedExpressions = otherExprs.OfType<ResolutionFailedExpression>().Concat(new []{expression}).ToArray();
54-
var failedExpression = new ResolutionFailedExpression(failedExpressions);
54+
var failedExpression = new ResolutionFailedExpression(context, failedExpressions);
5555

5656
var successfulExpressions = otherExprs.Where(expr => expr.Classification != ExpressionClassification.ResolutionFailed);
5757

Rubberduck.Parsing/Symbols/Declaration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,12 +641,12 @@ public override int GetHashCode()
641641
}
642642
}
643643

644-
public void ClearReferences()
644+
public virtual void ClearReferences()
645645
{
646646
_references = new ConcurrentDictionary<IdentifierReference, int>();
647647
}
648648

649-
public void RemoveReferencesFrom(IReadOnlyCollection<QualifiedModuleName> modulesByWhichToRemoveReferences)
649+
public virtual void RemoveReferencesFrom(IReadOnlyCollection<QualifiedModuleName> modulesByWhichToRemoveReferences)
650650
{
651651
_references = new ConcurrentDictionary<IdentifierReference, int>(_references.Where(reference => !modulesByWhichToRemoveReferences.Contains(reference.Key.QualifiedModuleName)));
652652
}

Rubberduck.Parsing/Symbols/ParameterDeclaration.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
using System.Collections.Concurrent;
2+
using System.Collections.Generic;
3+
using System.Linq;
14
using Antlr4.Runtime;
5+
using Rubberduck.Parsing.Annotations;
26
using Rubberduck.Parsing.ComReflection;
37
using Rubberduck.Parsing.Grammar;
48
using Rubberduck.Parsing.VBA.Extensions;
@@ -118,5 +122,44 @@ public ParameterDeclaration(ComParameter parameter, Declaration parent, Qualifie
118122
public bool IsImplicitByRef { get; }
119123
public bool IsParamArray { get; set; }
120124
public string DefaultValue { get; set; } = string.Empty;
125+
126+
private ConcurrentDictionary<IdentifierReference, int> _argumentReferences = new ConcurrentDictionary<IdentifierReference, int>();
127+
public IEnumerable<IdentifierReference> ArgumentReferences => _argumentReferences.Keys;
128+
129+
public void AddArgumentReference(
130+
QualifiedModuleName module,
131+
Declaration scope,
132+
Declaration parent,
133+
ParserRuleContext callSiteContext,
134+
string identifier,
135+
Declaration callee,
136+
Selection selection,
137+
IEnumerable<IAnnotation> annotations)
138+
{
139+
var newReference = new IdentifierReference(
140+
module,
141+
scope,
142+
parent,
143+
identifier,
144+
selection,
145+
callSiteContext,
146+
callee,
147+
false,
148+
false,
149+
annotations);
150+
_argumentReferences.AddOrUpdate(newReference, 1, (key, value) => 1);
151+
}
152+
153+
public override void ClearReferences()
154+
{
155+
_argumentReferences = new ConcurrentDictionary<IdentifierReference, int>();
156+
base.ClearReferences();
157+
}
158+
159+
public override void RemoveReferencesFrom(IReadOnlyCollection<QualifiedModuleName> modulesByWhichToRemoveReferences)
160+
{
161+
_argumentReferences = new ConcurrentDictionary<IdentifierReference, int>(_argumentReferences.Where(reference => !modulesByWhichToRemoveReferences.Contains(reference.Key.QualifiedModuleName)));
162+
base.RemoveReferencesFrom(modulesByWhichToRemoveReferences);
163+
}
121164
}
122165
}

Rubberduck.Parsing/VBA/ReferenceManagement/BoundExpressionVisitor.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,11 @@ private void Visit(
217217
// Argument lists are not affected by the resolution of the target of the index expression.
218218
foreach (var argument in expression.ArgumentList.Arguments)
219219
{
220+
if (argument.ReferencedParameter != null)
221+
{
222+
AddArgumentReference(argument, module, scope, parent);
223+
}
224+
220225
if (argument.Expression != null)
221226
{
222227
Visit(argument.Expression, module, scope, parent);
@@ -228,6 +233,29 @@ private void Visit(
228233
}
229234
}
230235

236+
private void AddArgumentReference(
237+
ArgumentListArgument argument,
238+
QualifiedModuleName module,
239+
Declaration scope,
240+
Declaration parent
241+
)
242+
{
243+
var expression = argument.Expression;
244+
var callSiteContext = expression.Context;
245+
var identifier = callSiteContext.GetText();
246+
var selection = callSiteContext.GetSelection();
247+
var callee = argument.ReferencedParameter;
248+
argument.ReferencedParameter.AddArgumentReference(
249+
module,
250+
scope,
251+
parent,
252+
callSiteContext,
253+
identifier,
254+
callee,
255+
selection,
256+
FindIdentifierAnnotations(module, selection.StartLine));
257+
}
258+
231259
private void AddArrayAccessReference(
232260
IndexExpression expression,
233261
QualifiedModuleName module,
@@ -344,6 +372,11 @@ private void Visit(
344372
// Argument List not affected by being unbound.
345373
foreach (var argument in expression.ArgumentList.Arguments)
346374
{
375+
if (argument.ReferencedParameter != null)
376+
{
377+
AddArgumentReference(argument, module, scope, parent);
378+
}
379+
347380
if (argument.Expression != null)
348381
{
349382
Visit(argument.Expression, module, scope, parent);

0 commit comments

Comments
 (0)