Skip to content

Commit

Permalink
Prevent argument count mismatch
Browse files Browse the repository at this point in the history
The expression splitting logic is a little hacky when it comes to
assignments to property or indexer setters: first, a split operation
is performed as if we were looking at a property or indexer *getter*;
the `InvocationShape` receives the correct method, but is one argument
short. Once that first `InvocationShape` has been built, we can create
a second, patched and fully correct version that includes the assign-
ment (RHS) argument.

This commit relaxes validation rules for the first `InvocationShape`
(i.e. the one with the potential argument count mismatch).
  • Loading branch information
stakx committed Jun 30, 2020
1 parent 0176fa0 commit fa36249
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 8 deletions.
11 changes: 6 additions & 5 deletions src/Moq/ExpressionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ void Split(Expression e, out Expression r /* remainder */, out InvocationShape p
property = ((IndexExpression)lhs.Expression.Body).Indexer;
}
var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName);
var arguments = new Expression[lhs.Arguments.Count + 1];
var arguments = new Expression[lhs.Method.GetParameters().Length];
for (var ai = 0; ai < arguments.Length - 1; ++ai)
{
arguments[ai] = lhs.Arguments[ai];
Expand Down Expand Up @@ -254,13 +254,14 @@ void Split(Expression e, out Expression r /* remainder */, out InvocationShape p
r = indexExpression.Object;
var parameter = Expression.Parameter(r.Type, r is ParameterExpression ope ? ope.Name : ParameterName);
var indexer = indexExpression.Indexer;
var arguments = indexExpression.Arguments;
var canRead = indexer.CanRead(out var getter);
p = new InvocationShape(
expression: Expression.Lambda(
Expression.MakeIndex(parameter, indexer, arguments),
Expression.MakeIndex(parameter, indexer, indexExpression.Arguments),
parameter),
method: indexer.GetGetMethod(true),
arguments);
method: canRead ? getter : indexer.GetSetMethod(true),
arguments: indexExpression.Arguments,
skipMatcherInitialization: !canRead);
return;
}

Expand Down
6 changes: 3 additions & 3 deletions src/Moq/InvocationShape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public static InvocationShape CreateFrom(Invocation invocation)
#endif
private readonly bool exactGenericTypeArguments;

public InvocationShape(LambdaExpression expression, MethodInfo method, IReadOnlyList<Expression> arguments = null, bool exactGenericTypeArguments = false)
public InvocationShape(LambdaExpression expression, MethodInfo method, IReadOnlyList<Expression> arguments = null, bool exactGenericTypeArguments = false, bool skipMatcherInitialization = false)
{
Debug.Assert(expression != null);
Debug.Assert(method != null);
Expand All @@ -82,14 +82,14 @@ public InvocationShape(LambdaExpression expression, MethodInfo method, IReadOnly

this.Expression = expression;
this.Method = method;
if (arguments != null)
if (arguments != null && !skipMatcherInitialization)
{
(this.argumentMatchers, this.Arguments) = MatcherFactory.CreateMatchers(arguments, method.GetParameters());
}
else
{
this.argumentMatchers = noArgumentMatchers;
this.Arguments = noArguments;
this.Arguments = arguments ?? noArguments;
}

this.exactGenericTypeArguments = exactGenericTypeArguments;
Expand Down

0 comments on commit fa36249

Please sign in to comment.