internal static PropertyInfo ResolveProperty(Type type, string name, bool ignoreCase, object[] indexArgs, bool hasInstance, object setterValue = null, bool getter = true)
        {
            var candidates = type.GetAllProperties().Where(prop => MockingUtil.StringEqual(prop.Name, name, ignoreCase)).ToArray();

            if (candidates.Length == 1)
            {
                return(candidates[0]);
            }

            if (!getter)
            {
                Array.Resize(ref indexArgs, indexArgs.Length + 1);
                indexArgs[indexArgs.Length - 1] = setterValue;
            }

            var propMethods = candidates
                              .Select(prop => getter ? prop.GetGetMethod(true) : prop.GetSetMethod(true))
                              .Where(m => m != null && CanCall(m, hasInstance))
                              .ToArray();

            indexArgs = indexArgs ?? MockingUtil.NoObjects;
            object state;
            var    foundGetter = MockingUtil.BindToMethod(MockingUtil.AllMembers, propMethods, ref indexArgs, null, null, null, out state);

            return(candidates.First(prop => (getter ? prop.GetGetMethod(true) : prop.GetSetMethod(true)) == foundGetter));
        }
예제 #2
0
        public static ProfilerInterceptor.RefReturn <TReturn> CreateDynamicMethodInvoker <TReturn>(object target, MethodInfo method, object[] args)
        {
            if (args.Length != method.GetParameters().Length)
            {
                throw new MockException(
                          String.Format("Number of the supplied arguments does not match to the expected one in the method signature:" +
                                        " supplied '{0}', expected '{1}'", args.Length, method.GetParameters().Length));
            }

            ProfilerInterceptor.RefReturn <TReturn> @delegate =
                MockingUtil.CreateDynamicMethod <ProfilerInterceptor.RefReturn <TReturn> >(
                    il =>
            {
                // store arguments as local variables
                il.UnpackArgArray(OpCodes.Ldarg_1, method);

                // push object reference to the stack in case if instance method
                if (target != null)
                {
                    il.Emit(OpCodes.Ldarg_0);
                }

                // push stored arguments back to the stack
                il.PushArgArray(method);

                il.Emit((target != null) ? OpCodes.Callvirt : OpCodes.Call, method as MethodInfo);
                il.Emit(OpCodes.Ret);
            });

            return(@delegate);
        }
예제 #3
0
        private static object InterceptNewobj(RuntimeTypeHandle typeHandle, RuntimeMethodHandle methodHandle, object[] data)
        {
            if (!IsInterceptionEnabled || isFinalizerThread)
            {
                return(null);
            }

            try
            {
                ReentrancyCounter++;

                var method = MethodBase.GetMethodFromHandle(methodHandle, typeHandle);

                var invocation = new Invocation(MockingUtil.TryGetUninitializedObject(method.DeclaringType), method, data ?? new object[0]);

                if (DispatchInvocation(invocation))
                {
                    if (invocation.CallOriginal)
                    {
                        SkipMethodInterceptionOnce(method);
                        return(null);
                    }
                    if (invocation.IsReturnValueSet && invocation.ReturnValue != null)
                    {
                        return(invocation.ReturnValue);
                    }
                    return(invocation.Instance);
                }
                return(null);
            }
            finally
            {
                ReentrancyCounter--;
            }
        }
        public static MethodInfo GetMethodWithLocalFunction(Type type, string methodName, Type[] methodParamTypes, Type[] methodGenericTypes)
        {
#if !PORTABLE
            if (type.IsProxy())
            {
                type = type.BaseType;
            }
            MethodInfo method = type.GetMethod(methodName, MockingUtil.AllMembers, null, methodParamTypes, null);

            if (method == null)
            {
                throw new MissingMemberException(MockingUtil.BuildMissingMethodMessage(type, null, methodName));
            }

            if (method.ContainsGenericParameters && (!GenericTypesMatch(methodGenericTypes, method)))
            {
                throw new MissingMemberException(MockingUtil.BuildGenericMethodNonMatchingTypesMessage(type, method, methodGenericTypes));
            }

            if (method.ContainsGenericParameters)
            {
                method = method.MakeGenericMethod(methodGenericTypes);
            }

            return(method);
#else
            return(null);
#endif
        }
예제 #5
0
 public static object GetDefaultValue(this Type t)
 {
     Debug.Assert(t != typeof(void));
     return
         (t.IsPointer ? IntPtr.Zero
                         : t.IsValueType && t != typeof(void) ? MockingUtil.CreateInstance(t)
                         : null);
 }
예제 #6
0
        internal string InputToString()
        {
            var sb = new StringBuilder();

            sb.AppendFormat("{0}.{1}(", Instance != null ? MockingUtil.GetUnproxiedType(Instance) : method.DeclaringType, method.Name);
            sb.Append(", ".Join(Args));
            sb.Append(")");
            return(sb.ToString());
        }
예제 #7
0
        private static Expression CreateFieldAssignmentExpression(FieldInfo assignee, ParameterExpression valueParam)
        {
            var fieldType = assignee.FieldType;

            var action = MockingUtil.CreateDynamicMethodWithVisibilityChecks(typeof(void), new[] { fieldType }, il =>
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Stsfld, assignee);
                il.Emit(OpCodes.Ret);
            });

            return(Expression.Call(null, action, valueParam));
        }
예제 #8
0
        public ref TRefReturn GetProperty <TRefReturn>(string name)
        {
            return(ref ProfilerInterceptor.GuardInternal((target, arguments) =>
            {
                var prop = MockingUtil.ResolveProperty(this.type, name, false, null, this.instance != null);
                var method = prop.GetGetMethod(true);

                ProfilerInterceptor.RefReturn <TRefReturn> @delegate =
                    MockingUtil.CreateDynamicMethodInvoker <TRefReturn>(target, method, arguments);

                return ref ProfilerInterceptor.GuardExternal(@delegate, target, arguments);
            }, this.instance, MockingUtil.NoObjects));
        }
        public static MethodInfo GetMethodWithLocalFunction(Type type, string methodName, Type[] methodParamTypes)
        {
#if !PORTABLE
            if (type.IsProxy())
            {
                type = type.BaseType;
            }
            MethodInfo method = type.GetMethod(methodName, MockingUtil.AllMembers, null, methodParamTypes, null);

            if (method == null)
            {
                throw new MissingMemberException(MockingUtil.BuildMissingMethodMessage(type, null, methodName));
            }
            return(method);
#else
            return(null);
#endif
        }
예제 #10
0
        public ref TRefReturn CallMethod <TRefReturn>(string name, params object[] args)
        {
            return(ref ProfilerInterceptor.GuardInternal((target, arguments) =>
            {
                arguments = arguments ?? MockingUtil.NoObjects;
                var candidates = type.GetAllMethods()
                                 .Where(m => m.Name == name && MockingUtil.CanCall(m, this.instance != null))
                                 .Select(m => MockingUtil.TrySpecializeGenericMethod(m, arguments.Select(a => a != null ? a.GetType() : null).ToArray()) ?? m)
                                 .ToArray();
                object state;
                var method = MockingUtil.BindToMethod(MockingUtil.AllMembers, candidates, ref arguments, null, null, null, out state);

                ProfilerInterceptor.RefReturn <TRefReturn> @delegate =
                    MockingUtil.CreateDynamicMethodInvoker <TRefReturn>(target, method as MethodInfo, arguments);

                return ref ProfilerInterceptor.GuardExternal(@delegate, target, arguments);
            }, this.instance, args ?? MockingUtil.NoObjects));
        }
예제 #11
0
        public static MethodInfo GetRealMethodInfoFromGeneric(MethodInfo method, object[] args)
        {
            try
            {
                var generics   = new Dictionary <Type, Type>();
                var parameters = method.GetParameters();
                var parsedArgs = MockingUtil.GetTypesFromArguments(args);
                for (int i = 0; i < args.Length; i++)
                {
                    MockingUtil.GetGenericsTypesFromActualType(parameters[i].ParameterType, parsedArgs[i], generics);
                }

                var genericArgs = method.GetGenericArguments().Select(x => generics[x]).ToArray();
                return(method.MakeGenericMethod(genericArgs));
            }
            catch
            {
                return(null);
            }
        }
예제 #12
0
        public static void RaiseEventThruReflection(object instance, EventInfo evt, object[] args)
        {
            MethodInfo raise;

            if ((raise = evt.GetRaiseMethod(true)) != null)
            {
                if (!raise.IsStatic && instance == null)
                {
                    throw new MockException("Unable to deduce the instance on which to raise the event");
                }

                //TODO: don't call reflection methods in GuardExternal when the profiler is working
                ProfilerInterceptor.GuardExternal(() => SecuredReflectionMethods.Invoke(raise, instance, args));
            }
            else
            {
                BindingFlags all   = BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
                var          field = evt.DeclaringType.GetField(evt.Name, all)               // C# event
                                     ?? evt.DeclaringType.GetField(evt.Name + "Event", all); //VB event

                if (field != null && field.FieldType == evt.EventHandlerType)
                {
                    if (!field.IsStatic && instance == null)
                    {
                        throw new MockException("Unable to deduce the instance on which to raise the event");
                    }

                    var handler = (Delegate)SecuredReflectionMethods.GetField(field, instance);
                    if (ProfilerInterceptor.IsProfilerAttached)
                    {
                        var invoker = MockingUtil.MakeFuncCaller(handler);
                        ProfilerInterceptor.GuardExternal(() => invoker(args, handler));
                    }
                    else
                    {
                        var invokeMethod = field.FieldType.GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public);
                        ProfilerInterceptor.GuardExternal(() => SecuredReflectionMethods.Invoke(invokeMethod, handler, args));
                    }
                }
            }
        }
예제 #13
0
        private static object InterceptNewobj(RuntimeTypeHandle typeHandle, RuntimeMethodHandle methodHandle, object[] data)
        {
            if (!IsInterceptionEnabled || isFinalizerThread)
            {
                return(null);
            }

            try
            {
                ReentrancyCounter++;

                var method = MethodBase.GetMethodFromHandle(methodHandle, typeHandle);

#if DEBUG
                ProfilerLogger.Info("*** +++ [MANAGED] Intercepting constructor call for {0}.{1}", method.DeclaringType.Name, method.Name);
#endif

                var invocation = new Invocation(MockingUtil.TryGetUninitializedObject(method.DeclaringType), method, data ?? new object[0]);

                if (DispatchInvocation(invocation))
                {
                    if (invocation.CallOriginal)
                    {
                        SkipMethodInterceptionOnce(method);
                        return(null);
                    }
                    if (invocation.IsReturnValueSet && invocation.ReturnValue != null)
                    {
                        return(invocation.ReturnValue);
                    }
                    return(invocation.Instance);
                }
                return(null);
            }
            finally
            {
                ReentrancyCounter--;
            }
        }
        internal static MethodInfo GetMethodByName(Type type, Type returnType, string memberName, ref object[] args)
        {
            if (type.IsProxy())
            {
                type = type.BaseType;
            }

            var candidateMethods = type.GetAllMethods()
                                   .Where(m => m.Name == memberName)
                                   .Concat(type.GetAllProperties()
                                           .Where(p => p.Name == memberName)
                                           .SelectMany(p => new[] { p.GetGetMethod(true), p.GetSetMethod(true) })
                                           .Where(m => m != null))
                                   .Select(m =>
            {
                if (m.IsGenericMethodDefinition &&
                    returnType != typeof(void) &&
                    m.GetGenericArguments().Length == 1 &&
                    m.ReturnType.ContainsGenericParameters)
                {
                    var generics = new Dictionary <Type, Type>();
                    if (MockingUtil.GetGenericsTypesFromActualType(m.ReturnType, returnType, generics))
                    {
                        return(m.MakeGenericMethod(generics.Values.Single()));
                    }
                }
                return(m);
            })
                                   .ToArray();

            MethodInfo mockedMethod = null;

            if (candidateMethods.Length == 1)
            {
                var singleCandidate   = candidateMethods[0];
                var returnTypeMatches = ReturnTypeMatches(returnType, singleCandidate);
                var argsIgnored       = args == null || args.Length == 0;
                if (returnTypeMatches && argsIgnored)
                {
                    mockedMethod = singleCandidate;
                    args         = mockedMethod.GetParameters()
                                   .Select(p =>
                    {
                        var byref     = p.ParameterType.IsByRef;
                        var paramType = byref ? p.ParameterType.GetElementType() : p.ParameterType;
                        if (paramType.IsPointer)
                        {
                            paramType = typeof(IntPtr);
                        }
                        var isAny = (Expression)typeof(ArgExpr).GetMethod("IsAny").MakeGenericMethod(paramType).Invoke(null, null);
                        if (byref)
                        {
                            isAny = ArgExpr.Ref(isAny);
                        }
                        return(isAny);
                    })
                                   .ToArray();
                }
            }

            if (mockedMethod == null)
            {
                mockedMethod = FindMethodBySignature(candidateMethods, returnType, args);
                if (mockedMethod == null && returnType == typeof(void))
                {
                    mockedMethod = FindMethodBySignature(candidateMethods, null, args);
                }
            }

            if (mockedMethod == null)
            {
                var mockedProperty = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
                                     .FirstOrDefault(property => property.Name == memberName);
                if (mockedProperty != null)
                {
                    var getter = mockedProperty.GetGetMethod(true);
                    if (getter != null && getter.ArgumentsMatchSignature(args))
                    {
                        mockedMethod = getter;
                    }

                    if (mockedMethod == null)
                    {
                        var setter = mockedProperty.GetSetMethod(true);
                        if (setter != null && setter.ArgumentsMatchSignature(args))
                        {
                            mockedMethod = setter;
                        }
                    }

                    if (mockedMethod == null)
                    {
                        throw new MissingMemberException(BuildMissingMethodMessage(type, mockedProperty, memberName));
                    }
                }
            }

            if (mockedMethod == null)
            {
                throw new MissingMemberException(BuildMissingMethodMessage(type, null, memberName));
            }

            if (mockedMethod.ContainsGenericParameters)
            {
                mockedMethod = MockingUtil.GetRealMethodInfoFromGeneric(mockedMethod, args);
            }

            if (mockedMethod.DeclaringType != mockedMethod.ReflectedType)
            {
                mockedMethod = GetMethodByName(mockedMethod.DeclaringType, returnType, memberName, ref args);
            }

            return(mockedMethod);
        }
예제 #15
0
        public static object CreateObject(this Type type, object[] args)
        {
            args = args ?? NoObjects;

            var constructorInfos = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            if (constructorInfos.Length == 0 || (type.IsValueType && args.Length == 0))
            {
                if (args.Length > 0)
                {
                    throw new MockException("Type has no non-default constructors.");
                }

                return(type.GetDefaultValue());
            }

            object state;
            var    ctor = (ConstructorInfo)MockingUtil.BindToMethod(MockingUtil.Default,
                                                                    constructorInfos, ref args, null, null, null, out state);

            var ctorParameters = ctor.GetParameters();

            for (int i = 0; i < ctorParameters.Length; ++i)
            {
                var paramType = ctorParameters[i].ParameterType;
                if (paramType.IsValueType && args[i] == null)
                {
                    args[i] = paramType.GetDefaultValue();
                }
                else if (args[i] != null && !paramType.IsAssignableFrom(args[i].GetType()))
                {
                    args[i] = Convert.ChangeType(args[i], paramType, System.Globalization.CultureInfo.CurrentCulture);
                }
            }

#if !PORTABLE
            var newCall = MockingUtil.CreateDynamicMethod <Func <object[], object> >(il =>
            {
                il.UnpackArgArray(OpCodes.Ldarg_0, ctor);
                il.PushArgArray(ctor);
                il.Emit(OpCodes.Newobj, ctor);
                if (type.IsValueType)
                {
                    il.Emit(OpCodes.Box, type);
                }
                il.Emit(OpCodes.Ret);
            });

            return(ProfilerInterceptor.GuardExternal(() =>
            {
                try
                {
                    return newCall(args);
                }
                catch (MemberAccessException ex)
                {
                    GC.KeepAlive(ex);
                    return MockingUtil.CreateInstance(type, args);
                }
            }));
#else
            return(MockingUtil.CreateInstance(type, args));
#endif
        }
예제 #16
0
        internal static CallPattern FromExpression(MocksRepository repository, Expression expr)
        {
            var callPattern = new CallPattern();

            expr = ((LambdaExpression)expr).Body;

            // the expression may end with a boxing conversion, remove that
            while (expr.NodeType == ExpressionType.Convert)
            {
                expr = ((UnaryExpression)expr).Operand;
            }

            Expression target;
            MethodBase method = null;

            Expression[] args;

            // We're parsing either a property/field expression or a method call.
            // parse the top of the expression tree and extract the expressions
            // that will turn into the constituents of the call pattern.
            if (expr is MemberExpression)
            {
                var memberExpr = (MemberExpression)expr;
                if (!(memberExpr.Member is PropertyInfo))
                {
                    throw new MockException("Fields cannot be mocked, only properties.");
                }

                var property = (PropertyInfo)memberExpr.Member;
                target = memberExpr.Expression;
                method = property.GetGetMethod(true);
                args   = null;
            }
            else if (expr is MethodCallExpression)
            {
                var methodCall = (MethodCallExpression)expr;

                method = methodCall.Method;
                target = methodCall.Object;
                args   = methodCall.Arguments.ToArray();

                if (target != null && !target.Type.IsInterface && !target.Type.IsProxy() && target.Type != method.DeclaringType)
                {
                    method = MockingUtil.GetConcreteImplementer((MethodInfo)method, target.Type);
                }
            }
            else if (expr is NewExpression)
            {
#if !PORTABLE
                if (ProfilerInterceptor.IsReJitEnabled)
                {
                    throw new MockException("Mocking the new operator is not avaiable with OnDemand option enabled. Please use .IgnoreInstance()");
                }
#endif

                var newExpr = (NewExpression)expr;

                method = newExpr.Constructor;

                if (method == null && newExpr.Type.IsValueType)
                {
                    throw new MockException("Empty constructor of value type is not associated with runnable code and cannot be intercepted.");
                }

                target = null;
                args   = newExpr.Arguments.ToArray();
            }
            else if (expr is InvocationExpression)
            {
                var invocation = (InvocationExpression)expr;
                target = invocation.Expression;
                args   = invocation.Arguments.ToArray();
            }
            else if (expr.NodeType == ExpressionType.Assign)
            {
                var binary = (BinaryExpression)expr;
                if (binary.Left is MemberExpression)
                {
                    MemberExpression memberExpr = (MemberExpression)binary.Left;
                    if (!(memberExpr.Member is PropertyInfo))
                    {
                        throw new MockException("Fields cannot be mocked, only properties.");
                    }

                    var property = (PropertyInfo)memberExpr.Member;
                    target = memberExpr.Expression;
                    method = property.GetSetMethod(true);
                    args   = new[] { binary.Right };
                }
                else if (binary.Left is IndexExpression)
                {
                    IndexExpression indexExpr = (IndexExpression)binary.Left;
                    target = indexExpr.Object;
                    method = indexExpr.Indexer.GetSetMethod(true);
                    args   = indexExpr.Arguments.Concat(new[] { binary.Right }).ToArray();
                }
                else
                {
                    throw new MockException("Left-hand of assignment is not a member or indexer.");
                }
            }
            else if (expr is IndexExpression)
            {
                var index = (IndexExpression)expr;
                target = index.Object;
                var property = index.Indexer;
                method = property.GetGetMethod(true);
                args   = index.Arguments.ToArray();
            }
            else
            {
                throw new MockException("The expression does not represent a method call, property access, new expression or a delegate invocation.");
            }

            // Create the matcher for the instance part of the call pattern.
            // If the base of the target expression is a new expression (new T()),
            // or null (e.g. (null as T) or ((T) null)), then use AnyMatcher for the instance part,
            // otherwise evaluate the instance expression and use a value matcher with the evaluated result.
            var        rootTarget = expr;
            Expression prevToRoot = null;
            while (true)
            {
                var memberExpr = rootTarget as MemberExpression;
                if (memberExpr != null && memberExpr.Expression != null && memberExpr.Member is PropertyInfo)
                {
                    prevToRoot = rootTarget;
                    rootTarget = memberExpr.Expression;
                    continue;
                }

                var callExpr = rootTarget as MethodCallExpression;
                if (callExpr != null && callExpr.Object != null)
                {
                    prevToRoot = rootTarget;
                    rootTarget = callExpr.Object;
                    continue;
                }

                if (rootTarget != null && (rootTarget.NodeType == ExpressionType.Convert || rootTarget.NodeType == ExpressionType.TypeAs))
                {
                    rootTarget = ((UnaryExpression)rootTarget).Operand;
                    continue;
                }

                if (rootTarget is InvocationExpression)
                {
                    prevToRoot = rootTarget;
                    rootTarget = ((InvocationExpression)rootTarget).Expression;
                    continue;
                }

                if (rootTarget is BinaryExpression)
                {
                    prevToRoot = rootTarget;
                    rootTarget = ((BinaryExpression)rootTarget).Left;
                    continue;
                }

                if (rootTarget is IndexExpression)
                {
                    prevToRoot = rootTarget;
                    rootTarget = ((IndexExpression)rootTarget).Object;
                    continue;
                }

                break;
            }

            object targetMockObject = null;
            Type   targetMockType   = null;
            bool   isStatic         = false;
            var    rootMatcher      = MocksRepository.TryCreateMatcherFromArgMember(rootTarget);

            if (rootMatcher != null)
            {
                callPattern.InstanceMatcher = rootMatcher;
            }
            else if (rootTarget is MemberExpression)
            {
                var memberExpr = (MemberExpression)rootTarget;
                targetMockObject = memberExpr.Member is FieldInfo?memberExpr.EvaluateExpression()
                                       : memberExpr.Expression != null?memberExpr.Expression.EvaluateExpression()
                                           : null;

                targetMockType = memberExpr.Member is FieldInfo ? memberExpr.Type : memberExpr.Member.DeclaringType;

                var asPropertyInfo = memberExpr.Member as PropertyInfo;
                isStatic = asPropertyInfo != null
                    ? (asPropertyInfo.GetGetMethod(true) ?? asPropertyInfo.GetSetMethod(true)).IsStatic
                    : false;
            }
            else if (rootTarget is MethodCallExpression)
            {
                var methodCallExpr = (MethodCallExpression)rootTarget;
                targetMockObject = methodCallExpr.Object != null?methodCallExpr.Object.EvaluateExpression() : null;

                targetMockType = methodCallExpr.Method.DeclaringType;
                isStatic       = methodCallExpr.Method.IsStatic;
            }
            else if (rootTarget is NewExpression)
            {
                callPattern.InstanceMatcher = new AnyMatcher();
            }
            else if (rootTarget is ConstantExpression)
            {
                var constant = (ConstantExpression)rootTarget;
                if (constant.Value == null)
                {
                    callPattern.InstanceMatcher = new AnyMatcher();
                }
                else
                {
                    if (constant.Type.IsCompilerGenerated() && prevToRoot != null && prevToRoot.Type != typeof(void))
                    {
                        targetMockObject = prevToRoot.EvaluateExpression();
                        targetMockType   = prevToRoot.Type;
                    }
                    else
                    {
                        targetMockObject = constant.Value;
                        targetMockType   = constant.Type;
                    }
                }
            }
            if (targetMockObject != null)
            {
                targetMockType = targetMockObject.GetType();
            }

            if (callPattern.InstanceMatcher != null && prevToRoot != expr && prevToRoot != null)
            {
                throw new MockException("Using a matcher for the root member together with recursive mocking is not supported. Arrange the property or method of the root member in a separate statement.");
            }

            if (callPattern.InstanceMatcher == null)
            {
                // TODO: implicit creation of mock mixins shouldn't explicitly refer to behaviors, but
                // should get them from some configuration made outside the Core.
                Debug.Assert(targetMockObject != null || targetMockType != null);
                MockingUtil.UnwrapDelegateTarget(ref targetMockObject);
                var mixin = MocksRepository.GetMockMixin(targetMockObject, targetMockType);
                if (mixin == null)
                {
                    if (isStatic)
                    {
                        MockCreationSettings settings = MockCreationSettings.GetSettings(Behavior.CallOriginal);
                        repository.InterceptStatics(targetMockType, settings, false);
                    }
                    else if (targetMockObject != null)
                    {
                        MockCreationSettings settings = MockCreationSettings.GetSettings(Behavior.CallOriginal);
                        repository.CreateExternalMockMixin(targetMockType, targetMockObject, settings);
                    }
                }

                var targetValue = target != null?target.EvaluateExpression() : null;

                var delgMethod = MockingUtil.UnwrapDelegateTarget(ref targetValue);
                if (delgMethod != null)
                {
                    method = delgMethod.GetInheritanceChain().First(m => !m.DeclaringType.IsProxy());
                }

                callPattern.InstanceMatcher = new ReferenceMatcher(targetValue);
            }

            // now we have the method part of the call pattern
            Debug.Assert(method != null);
            callPattern.SetMethod(method, checkCompatibility: true);

            //Finally, construct the arguments part of the call pattern.
            using (repository.StartArrangeArgMatching())
            {
                bool hasParams = false;
                bool hasSingleValueInParams = false;

                if (args != null && args.Length > 0)
                {
                    var lastParameter = method.GetParameters().Last();
                    if (Attribute.IsDefined(lastParameter, typeof(ParamArrayAttribute)) && args.Last() is NewArrayExpression)
                    {
                        hasParams = true;
                        var paramsArg = (NewArrayExpression)args.Last();
                        args = args.Take(args.Length - 1).Concat(paramsArg.Expressions).ToArray();
                        if (paramsArg.Expressions.Count == 1)
                        {
                            hasSingleValueInParams = true;
                        }
                    }

                    foreach (var argument in args)
                    {
                        callPattern.ArgumentMatchers.Add(MocksRepository.CreateMatcherForArgument(argument));
                    }

                    if (hasParams)
                    {
                        int paramsCount = method.GetParameters().Count();
                        if (hasSingleValueInParams)
                        {
                            IMatcher      matcher     = callPattern.ArgumentMatchers[paramsCount - 1];
                            ITypedMatcher typeMatcher = matcher as ITypedMatcher;
                            if (typeMatcher != null && typeMatcher.Type != method.GetParameters().Last().ParameterType)
                            {
                                callPattern.ArgumentMatchers[paramsCount - 1] = new ParamsMatcher(new IMatcher[] { matcher });
                            }
                        }
                        else
                        {
                            IEnumerable <IMatcher> paramMatchers = callPattern.ArgumentMatchers.Skip(paramsCount - 1).Take(callPattern.ArgumentMatchers.Count - paramsCount + 1);
                            callPattern.ArgumentMatchers = callPattern.ArgumentMatchers.Take(paramsCount - 1).ToList();
                            callPattern.ArgumentMatchers.Add(new ParamsMatcher(paramMatchers.ToArray()));
                        }
                    }
                }
            }

            MethodBase methodFromCallPattern = repository.GetMethodFromCallPattern(callPattern);

            callPattern.AdjustForExtensionMethod();
            callPattern.SetMethod(methodFromCallPattern, checkCompatibility: false);

            return(callPattern);
        }