Skip to content

Commit 91c57a8

Browse files
authored
Merge pull request #5148 from MDoerner/FixesAroundRecursiveFunctionCalls
Fixes around recursive function calls
2 parents 38c928e + 7f63d65 commit 91c57a8

File tree

8 files changed

+187
-38
lines changed

8 files changed

+187
-38
lines changed

Rubberduck.Parsing/Binding/Bindings/IndexDefaultBinding.cs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public sealed class IndexDefaultBinding : IExpressionBinding
1313
private readonly IExpressionBinding _lExpressionBinding;
1414
private IBoundExpression _lExpression;
1515
private readonly ArgumentList _argumentList;
16+
private readonly Declaration _parent;
1617

1718
private const int DEFAULT_MEMBER_RECURSION_LIMIT = 32;
1819

@@ -25,23 +26,27 @@ public sealed class IndexDefaultBinding : IExpressionBinding
2526
public IndexDefaultBinding(
2627
ParserRuleContext expression,
2728
IExpressionBinding lExpressionBinding,
28-
ArgumentList argumentList)
29+
ArgumentList argumentList,
30+
Declaration parent)
2931
: this(
3032
expression,
3133
(IBoundExpression)null,
32-
argumentList)
34+
argumentList,
35+
parent)
3336
{
3437
_lExpressionBinding = lExpressionBinding;
3538
}
3639

3740
public IndexDefaultBinding(
3841
ParserRuleContext expression,
3942
IBoundExpression lExpression,
40-
ArgumentList argumentList)
43+
ArgumentList argumentList,
44+
Declaration parent)
4145
{
4246
_expression = expression;
4347
_lExpression = lExpression;
4448
_argumentList = argumentList;
49+
_parent = parent;
4550
}
4651

4752
private static void ResolveArgumentList(Declaration calledProcedure, ArgumentList argumentList, bool isArrayAccess = false)
@@ -60,10 +65,10 @@ public IBoundExpression Resolve()
6065
_lExpression = _lExpressionBinding.Resolve();
6166
}
6267

63-
return Resolve(_lExpression, _argumentList, _expression);
68+
return Resolve(_lExpression, _argumentList, _expression, _parent);
6469
}
6570

66-
private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth = 0, RecursiveDefaultMemberAccessExpression containedExpression = null)
71+
private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth = 0, RecursiveDefaultMemberAccessExpression containedExpression = null)
6772
{
6873
if (lExpression.Classification == ExpressionClassification.ResolutionFailed)
6974
{
@@ -84,15 +89,15 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
8489
switch (lExpression)
8590
{
8691
case IndexExpression indexExpression:
87-
var doubleIndexExpression = ResolveLExpressionIsIndexExpression(indexExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
92+
var doubleIndexExpression = ResolveLExpressionIsIndexExpression(indexExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
8893
if (doubleIndexExpression != null)
8994
{
9095
return doubleIndexExpression;
9196
}
9297

9398
break;
9499
case DictionaryAccessExpression dictionaryAccessExpression:
95-
var indexOnBangExpression = ResolveLExpressionIsDictionaryAccessExpression(dictionaryAccessExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
100+
var indexOnBangExpression = ResolveLExpressionIsDictionaryAccessExpression(dictionaryAccessExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
96101
if (indexOnBangExpression != null)
97102
{
98103
return indexOnBangExpression;
@@ -101,9 +106,11 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
101106
break;
102107
}
103108

104-
if (IsVariablePropertyFunctionWithoutParameters(lExpression))
109+
if (IsVariablePropertyFunctionWithoutParameters(lExpression)
110+
&& !(lExpression.Classification == ExpressionClassification.Variable
111+
&& parent.Equals(lExpression.ReferencedDeclaration)))
105112
{
106-
var parameterlessLExpressionAccess = ResolveLExpressionIsVariablePropertyFunctionNoParameters(lExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
113+
var parameterlessLExpressionAccess = ResolveLExpressionIsVariablePropertyFunctionNoParameters(lExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
107114
if (parameterlessLExpressionAccess != null)
108115
{
109116
return parameterlessLExpressionAccess;
@@ -114,7 +121,9 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
114121

115122
if (lExpression.Classification == ExpressionClassification.Property
116123
|| lExpression.Classification == ExpressionClassification.Function
117-
|| lExpression.Classification == ExpressionClassification.Subroutine)
124+
|| lExpression.Classification == ExpressionClassification.Subroutine
125+
|| lExpression.Classification == ExpressionClassification.Variable
126+
&& parent.Equals(lExpression.ReferencedDeclaration))
118127
{
119128
var procedureDeclaration = lExpression.ReferencedDeclaration as IParameterizedDeclaration;
120129
var parameters = procedureDeclaration?.Parameters?.ToList();
@@ -126,27 +135,29 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
126135
}
127136

128137
ResolveArgumentList(null, argumentList);
129-
return CreateFailedExpression(lExpression, argumentList, expression, defaultMemberResolutionRecursionDepth > 0);
138+
return CreateFailedExpression(lExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth > 0);
130139
}
131140

132-
private static IBoundExpression CreateFailedExpression(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext context, bool isDefaultMemberResolution)
141+
private static IBoundExpression CreateFailedExpression(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext context, Declaration parent, bool isDefaultMemberResolution)
133142
{
134-
if (IsFailedDefaultMemberResolution(lExpression))
143+
if (IsFailedDefaultMemberResolution(lExpression, parent))
135144
{
136145
return CreateFailedDefaultMemberAccessExpression(lExpression, argumentList, context);
137146
}
138147

139148
return CreateResolutionFailedExpression(lExpression, argumentList, context, isDefaultMemberResolution);
140149
}
141150

142-
private static bool IsFailedDefaultMemberResolution(IBoundExpression lExpression)
151+
private static bool IsFailedDefaultMemberResolution(IBoundExpression lExpression, Declaration parent)
143152
{
144153
if (lExpression.Classification == ExpressionClassification.ResolutionFailed)
145154
{
146155
return false;
147156
}
148157

149-
if (IsVariablePropertyFunctionWithoutParameters(lExpression))
158+
if (IsVariablePropertyFunctionWithoutParameters(lExpression)
159+
&& !(lExpression.Classification == ExpressionClassification.Variable
160+
&& parent.Equals(lExpression.ReferencedDeclaration)))
150161
{
151162
return true;
152163
}
@@ -191,7 +202,7 @@ private static IBoundExpression CreateFailedDefaultMemberAccessExpression(IBound
191202
return failedExpr.JoinAsFailedResolution(context, argumentExpressions.Concat(new[] { lExpression }));
192203
}
193204

194-
private IBoundExpression ResolveLExpressionIsVariablePropertyFunctionNoParameters(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
205+
private IBoundExpression ResolveLExpressionIsVariablePropertyFunctionNoParameters(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
195206
{
196207
/*
197208
<l-expression> is classified as a variable, or <l-expression> is classified as a property or function
@@ -215,7 +226,7 @@ with a parameter list that cannot accept any parameters and an <argument-list> t
215226
var asTypeName = indexedDeclaration.AsTypeName;
216227
var asTypeDeclaration = indexedDeclaration.AsTypeDeclaration;
217228

218-
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, defaultMemberResolutionRecursionDepth + 1, containedExpression);
229+
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, parent, defaultMemberResolutionRecursionDepth + 1, containedExpression);
219230
}
220231

221232
private static bool IsVariablePropertyFunctionWithoutParameters(IBoundExpression lExpression)
@@ -232,7 +243,7 @@ private static bool IsVariablePropertyFunctionWithoutParameters(IBoundExpression
232243
}
233244
}
234245

235-
private IBoundExpression ResolveLExpressionIsIndexExpression(IndexExpression indexExpression, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
246+
private IBoundExpression ResolveLExpressionIsIndexExpression(IndexExpression indexExpression, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
236247
{
237248
/*
238249
<l-expression> is classified as an index expression and the argument list is not empty.
@@ -256,10 +267,10 @@ private IBoundExpression ResolveLExpressionIsIndexExpression(IndexExpression ind
256267
var asTypeName = indexedDeclaration.AsTypeName;
257268
var asTypeDeclaration = indexedDeclaration.AsTypeDeclaration;
258269

259-
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, defaultMemberResolutionRecursionDepth + 1, containedExpression);
270+
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, parent, defaultMemberResolutionRecursionDepth + 1, containedExpression);
260271
}
261272

262-
private IBoundExpression ResolveLExpressionIsDictionaryAccessExpression(DictionaryAccessExpression dictionaryAccessExpression, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
273+
private IBoundExpression ResolveLExpressionIsDictionaryAccessExpression(DictionaryAccessExpression dictionaryAccessExpression, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
263274
{
264275
//This is equivalent to the case in which the lExpression is an IndexExpression with the difference that it cannot be an array access.
265276

@@ -277,10 +288,10 @@ private IBoundExpression ResolveLExpressionIsDictionaryAccessExpression(Dictiona
277288
var asTypeName = indexedDeclaration.AsTypeName;
278289
var asTypeDeclaration = indexedDeclaration.AsTypeDeclaration;
279290

280-
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, defaultMemberResolutionRecursionDepth + 1, containedExpression);
291+
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, parent, defaultMemberResolutionRecursionDepth + 1, containedExpression);
281292
}
282293

283-
private IBoundExpression ResolveDefaultMember(string asTypeName, Declaration asTypeDeclaration, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
294+
private IBoundExpression ResolveDefaultMember(string asTypeName, Declaration asTypeDeclaration, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
284295
{
285296
/*
286297
The declared type of <l-expression> is Object or Variant, and <argument-list> contains no
@@ -328,7 +339,7 @@ declared type.
328339
if (parameters.All(parameter => parameter.IsOptional)
329340
&& DEFAULT_MEMBER_RECURSION_LIMIT >= defaultMemberResolutionRecursionDepth)
330341
{
331-
return ResolveRecursiveDefaultMember(defaultMember, defaultMemberClassification, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
342+
return ResolveRecursiveDefaultMember(defaultMember, defaultMemberClassification, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
332343
}
333344
}
334345

@@ -342,12 +353,12 @@ private static bool ArgumentListIsCompatible(ICollection<ParameterDeclaration> p
342353
&& parameters.Count(parameter => !parameter.IsOptional && !parameter.IsParamArray) <= (argumentList?.Arguments.Count ?? 0);
343354
}
344355

345-
private IBoundExpression ResolveRecursiveDefaultMember(Declaration defaultMember, ExpressionClassification defaultMemberClassification, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
356+
private IBoundExpression ResolveRecursiveDefaultMember(Declaration defaultMember, ExpressionClassification defaultMemberClassification, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
346357
{
347358
var defaultMemberRecursionExpression = new RecursiveDefaultMemberAccessExpression(defaultMember, defaultMemberClassification, _lExpression.Context, defaultMemberResolutionRecursionDepth, containedExpression);
348359

349360
var defaultMemberAsLExpression = new SimpleNameExpression(defaultMember, defaultMemberClassification, expression);
350-
return Resolve(defaultMemberAsLExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, defaultMemberRecursionExpression);
361+
return Resolve(defaultMemberAsLExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, defaultMemberRecursionExpression);
351362
}
352363

353364
private ExpressionClassification DefaultMemberExpressionClassification(Declaration defaultMember)

Rubberduck.Parsing/Binding/Bindings/ProcedureCoercionDefaultBinding.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public sealed class ProcedureCoercionDefaultBinding : IExpressionBinding
1111
private readonly ParserRuleContext _expression;
1212
private readonly IExpressionBinding _wrappedExpressionBinding;
1313
private readonly bool _hasExplicitCall;
14+
private readonly Declaration _parent;
1415
private IBoundExpression _wrappedExpression;
1516

1617
//This is a wrapper used to model procedure coercion in call statements without arguments.
@@ -19,23 +20,27 @@ public sealed class ProcedureCoercionDefaultBinding : IExpressionBinding
1920
public ProcedureCoercionDefaultBinding(
2021
ParserRuleContext expression,
2122
IExpressionBinding wrappedExpressionBinding,
22-
bool hasExplicitCall)
23+
bool hasExplicitCall,
24+
Declaration parent)
2325
: this(
2426
expression,
2527
(IBoundExpression)null,
26-
hasExplicitCall)
28+
hasExplicitCall,
29+
parent)
2730
{
2831
_wrappedExpressionBinding = wrappedExpressionBinding;
2932
}
3033

3134
public ProcedureCoercionDefaultBinding(
3235
ParserRuleContext expression,
3336
IBoundExpression wrappedExpression,
34-
bool hasExplicitCall)
37+
bool hasExplicitCall,
38+
Declaration parent)
3539
{
3640
_expression = expression;
3741
_wrappedExpression = wrappedExpression;
3842
_hasExplicitCall = hasExplicitCall;
43+
_parent = parent;
3944
}
4045

4146
public IBoundExpression Resolve()
@@ -45,17 +50,18 @@ public IBoundExpression Resolve()
4550
_wrappedExpression = _wrappedExpressionBinding.Resolve();
4651
}
4752

48-
return Resolve(_wrappedExpression, _expression, _hasExplicitCall);
53+
return Resolve(_wrappedExpression, _expression, _hasExplicitCall, _parent);
4954
}
5055

51-
private static IBoundExpression Resolve(IBoundExpression wrappedExpression, ParserRuleContext expression, bool hasExplicitCall)
56+
private static IBoundExpression Resolve(IBoundExpression wrappedExpression, ParserRuleContext expression, bool hasExplicitCall, Declaration parent)
5257
{
5358
//Procedure coercion only happens for expressions classified as variables.
5459
if (wrappedExpression.Classification != ExpressionClassification.Variable)
5560
{
5661
return wrappedExpression;
5762
}
5863

64+
//The wrapped declaration is not of a specific class type or Object.
5965
var wrappedDeclaration = wrappedExpression.ReferencedDeclaration;
6066
if (wrappedDeclaration == null
6167
|| !wrappedDeclaration.IsObject
@@ -66,7 +72,13 @@ private static IBoundExpression Resolve(IBoundExpression wrappedExpression, Pars
6672
return wrappedExpression;
6773
}
6874

69-
//The wrapped declaration is of a specific class type or Object.
75+
//Recursive function call
76+
//The reference to the function is originally resolved as a variable because that is appropriate for the return value variable of the same name.
77+
if (wrappedExpression.Classification == ExpressionClassification.Variable
78+
&& wrappedDeclaration.Equals(parent))
79+
{
80+
return wrappedExpression;
81+
}
7082

7183
var asTypeName = wrappedDeclaration.AsTypeName;
7284
var asTypeDeclaration = wrappedDeclaration.AsTypeDeclaration;

0 commit comments

Comments
 (0)