Skip to content

Commit

Permalink
Fix resolver around recursive function calls
Browse files Browse the repository at this point in the history
This fixes that the reference to the contained function was treated like a variable instead of a function call.
  • Loading branch information
MDoerner committed Sep 15, 2019
1 parent 0e37374 commit 7f63d65
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 36 deletions.
61 changes: 36 additions & 25 deletions Rubberduck.Parsing/Binding/Bindings/IndexDefaultBinding.cs
Expand Up @@ -13,6 +13,7 @@ public sealed class IndexDefaultBinding : IExpressionBinding
private readonly IExpressionBinding _lExpressionBinding;
private IBoundExpression _lExpression;
private readonly ArgumentList _argumentList;
private readonly Declaration _parent;

private const int DEFAULT_MEMBER_RECURSION_LIMIT = 32;

Expand All @@ -25,23 +26,27 @@ public sealed class IndexDefaultBinding : IExpressionBinding
public IndexDefaultBinding(
ParserRuleContext expression,
IExpressionBinding lExpressionBinding,
ArgumentList argumentList)
ArgumentList argumentList,
Declaration parent)
: this(
expression,
(IBoundExpression)null,
argumentList)
argumentList,
parent)
{
_lExpressionBinding = lExpressionBinding;
}

public IndexDefaultBinding(
ParserRuleContext expression,
IBoundExpression lExpression,
ArgumentList argumentList)
ArgumentList argumentList,
Declaration parent)
{
_expression = expression;
_lExpression = lExpression;
_argumentList = argumentList;
_parent = parent;
}

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

return Resolve(_lExpression, _argumentList, _expression);
return Resolve(_lExpression, _argumentList, _expression, _parent);
}

private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth = 0, RecursiveDefaultMemberAccessExpression containedExpression = null)
private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth = 0, RecursiveDefaultMemberAccessExpression containedExpression = null)
{
if (lExpression.Classification == ExpressionClassification.ResolutionFailed)
{
Expand All @@ -84,15 +89,15 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
switch (lExpression)
{
case IndexExpression indexExpression:
var doubleIndexExpression = ResolveLExpressionIsIndexExpression(indexExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
var doubleIndexExpression = ResolveLExpressionIsIndexExpression(indexExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
if (doubleIndexExpression != null)
{
return doubleIndexExpression;
}

break;
case DictionaryAccessExpression dictionaryAccessExpression:
var indexOnBangExpression = ResolveLExpressionIsDictionaryAccessExpression(dictionaryAccessExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
var indexOnBangExpression = ResolveLExpressionIsDictionaryAccessExpression(dictionaryAccessExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
if (indexOnBangExpression != null)
{
return indexOnBangExpression;
Expand All @@ -101,9 +106,11 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
break;
}

if (IsVariablePropertyFunctionWithoutParameters(lExpression))
if (IsVariablePropertyFunctionWithoutParameters(lExpression)
&& !(lExpression.Classification == ExpressionClassification.Variable
&& parent.Equals(lExpression.ReferencedDeclaration)))
{
var parameterlessLExpressionAccess = ResolveLExpressionIsVariablePropertyFunctionNoParameters(lExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
var parameterlessLExpressionAccess = ResolveLExpressionIsVariablePropertyFunctionNoParameters(lExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
if (parameterlessLExpressionAccess != null)
{
return parameterlessLExpressionAccess;
Expand All @@ -114,7 +121,9 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu

if (lExpression.Classification == ExpressionClassification.Property
|| lExpression.Classification == ExpressionClassification.Function
|| lExpression.Classification == ExpressionClassification.Subroutine)
|| lExpression.Classification == ExpressionClassification.Subroutine
|| lExpression.Classification == ExpressionClassification.Variable
&& parent.Equals(lExpression.ReferencedDeclaration))
{
var procedureDeclaration = lExpression.ReferencedDeclaration as IParameterizedDeclaration;
var parameters = procedureDeclaration?.Parameters?.ToList();
Expand All @@ -126,27 +135,29 @@ private IBoundExpression Resolve(IBoundExpression lExpression, ArgumentList argu
}

ResolveArgumentList(null, argumentList);
return CreateFailedExpression(lExpression, argumentList, expression, defaultMemberResolutionRecursionDepth > 0);
return CreateFailedExpression(lExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth > 0);
}

private static IBoundExpression CreateFailedExpression(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext context, bool isDefaultMemberResolution)
private static IBoundExpression CreateFailedExpression(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext context, Declaration parent, bool isDefaultMemberResolution)
{
if (IsFailedDefaultMemberResolution(lExpression))
if (IsFailedDefaultMemberResolution(lExpression, parent))
{
return CreateFailedDefaultMemberAccessExpression(lExpression, argumentList, context);
}

return CreateResolutionFailedExpression(lExpression, argumentList, context, isDefaultMemberResolution);
}

private static bool IsFailedDefaultMemberResolution(IBoundExpression lExpression)
private static bool IsFailedDefaultMemberResolution(IBoundExpression lExpression, Declaration parent)
{
if (lExpression.Classification == ExpressionClassification.ResolutionFailed)
{
return false;
}

if (IsVariablePropertyFunctionWithoutParameters(lExpression))
if (IsVariablePropertyFunctionWithoutParameters(lExpression)
&& !(lExpression.Classification == ExpressionClassification.Variable
&& parent.Equals(lExpression.ReferencedDeclaration)))
{
return true;
}
Expand Down Expand Up @@ -191,7 +202,7 @@ private static IBoundExpression CreateFailedDefaultMemberAccessExpression(IBound
return failedExpr.JoinAsFailedResolution(context, argumentExpressions.Concat(new[] { lExpression }));
}

private IBoundExpression ResolveLExpressionIsVariablePropertyFunctionNoParameters(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
private IBoundExpression ResolveLExpressionIsVariablePropertyFunctionNoParameters(IBoundExpression lExpression, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
{
/*
<l-expression> is classified as a variable, or <l-expression> is classified as a property or function
Expand All @@ -215,7 +226,7 @@ private IBoundExpression ResolveLExpressionIsVariablePropertyFunctionNoParameter
var asTypeName = indexedDeclaration.AsTypeName;
var asTypeDeclaration = indexedDeclaration.AsTypeDeclaration;

return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, defaultMemberResolutionRecursionDepth + 1, containedExpression);
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, parent, defaultMemberResolutionRecursionDepth + 1, containedExpression);
}

private static bool IsVariablePropertyFunctionWithoutParameters(IBoundExpression lExpression)
Expand All @@ -232,7 +243,7 @@ private static bool IsVariablePropertyFunctionWithoutParameters(IBoundExpression
}
}

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

return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, defaultMemberResolutionRecursionDepth + 1, containedExpression);
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, parent, defaultMemberResolutionRecursionDepth + 1, containedExpression);
}

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

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

return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, defaultMemberResolutionRecursionDepth + 1, containedExpression);
return ResolveDefaultMember(asTypeName, asTypeDeclaration, argumentList, expression, parent, defaultMemberResolutionRecursionDepth + 1, containedExpression);
}

private IBoundExpression ResolveDefaultMember(string asTypeName, Declaration asTypeDeclaration, ArgumentList argumentList, ParserRuleContext expression, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
private IBoundExpression ResolveDefaultMember(string asTypeName, Declaration asTypeDeclaration, ArgumentList argumentList, ParserRuleContext expression, Declaration parent, int defaultMemberResolutionRecursionDepth, RecursiveDefaultMemberAccessExpression containedExpression)
{
/*
The declared type of <l-expression> is Object or Variant, and <argument-list> contains no
Expand Down Expand Up @@ -328,7 +339,7 @@ declared type.
if (parameters.All(parameter => parameter.IsOptional)
&& DEFAULT_MEMBER_RECURSION_LIMIT >= defaultMemberResolutionRecursionDepth)
{
return ResolveRecursiveDefaultMember(defaultMember, defaultMemberClassification, argumentList, expression, defaultMemberResolutionRecursionDepth, containedExpression);
return ResolveRecursiveDefaultMember(defaultMember, defaultMemberClassification, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, containedExpression);
}
}

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

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

var defaultMemberAsLExpression = new SimpleNameExpression(defaultMember, defaultMemberClassification, expression);
return Resolve(defaultMemberAsLExpression, argumentList, expression, defaultMemberResolutionRecursionDepth, defaultMemberRecursionExpression);
return Resolve(defaultMemberAsLExpression, argumentList, expression, parent, defaultMemberResolutionRecursionDepth, defaultMemberRecursionExpression);
}

private ExpressionClassification DefaultMemberExpressionClassification(Declaration defaultMember)
Expand Down
Expand Up @@ -11,6 +11,7 @@ public sealed class ProcedureCoercionDefaultBinding : IExpressionBinding
private readonly ParserRuleContext _expression;
private readonly IExpressionBinding _wrappedExpressionBinding;
private readonly bool _hasExplicitCall;
private readonly Declaration _parent;
private IBoundExpression _wrappedExpression;

//This is a wrapper used to model procedure coercion in call statements without arguments.
Expand All @@ -19,23 +20,27 @@ public sealed class ProcedureCoercionDefaultBinding : IExpressionBinding
public ProcedureCoercionDefaultBinding(
ParserRuleContext expression,
IExpressionBinding wrappedExpressionBinding,
bool hasExplicitCall)
bool hasExplicitCall,
Declaration parent)
: this(
expression,
(IBoundExpression)null,
hasExplicitCall)
hasExplicitCall,
parent)
{
_wrappedExpressionBinding = wrappedExpressionBinding;
}

public ProcedureCoercionDefaultBinding(
ParserRuleContext expression,
IBoundExpression wrappedExpression,
bool hasExplicitCall)
bool hasExplicitCall,
Declaration parent)
{
_expression = expression;
_wrappedExpression = wrappedExpression;
_hasExplicitCall = hasExplicitCall;
_parent = parent;
}

public IBoundExpression Resolve()
Expand All @@ -45,17 +50,18 @@ public IBoundExpression Resolve()
_wrappedExpression = _wrappedExpressionBinding.Resolve();
}

return Resolve(_wrappedExpression, _expression, _hasExplicitCall);
return Resolve(_wrappedExpression, _expression, _hasExplicitCall, _parent);
}

private static IBoundExpression Resolve(IBoundExpression wrappedExpression, ParserRuleContext expression, bool hasExplicitCall)
private static IBoundExpression Resolve(IBoundExpression wrappedExpression, ParserRuleContext expression, bool hasExplicitCall, Declaration parent)
{
//Procedure coercion only happens for expressions classified as variables.
if (wrappedExpression.Classification != ExpressionClassification.Variable)
{
return wrappedExpression;
}

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

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

var asTypeName = wrappedDeclaration.AsTypeName;
var asTypeDeclaration = wrappedDeclaration.AsTypeDeclaration;
Expand Down

0 comments on commit 7f63d65

Please sign in to comment.