Пример #1
0
        public JSInvocationExpression NewDelegate(TypeReference delegateType, JSExpression thisReference, JSExpression targetMethod)
        {
            var targetDotExpression = targetMethod as JSDotExpressionBase;
            var jsMethod            = targetDotExpression != null ? targetDotExpression.Member as JSMethod : null;

            JSExpression[] invocationExpressionArguments;

            if (jsMethod == null)
            {
                // Not sure if it is possible.
                invocationExpressionArguments = new[] { thisReference, targetMethod };
            }
            else
            {
                var jsMethodAccess = targetMethod as JSMethodAccess;
                var arguments      = jsMethod == null
                    ? null
                    : jsMethod.Reference.Parameters.Select(
                    (parameter, index) => (JSExpression) new JSRawOutputIdentifier(parameter.ParameterType, "arguments[{0}]", index))
                                     .ToArray();

                bool isFromDelegate = jsMethod.Reference.Name == "Invoke" && TypeUtil.IsDelegateType(jsMethod.Reference.DeclaringType);

                JSExpression methodInvocation;
                if (isFromDelegate)
                {
                    methodInvocation = targetMethod;
                }
                else if (jsMethod.Method.IsStatic)
                {
                    methodInvocation = new JSDeferredExpression(JSInvocationExpression.InvokeStatic(jsMethod.Reference.DeclaringType, jsMethod, arguments));
                }
                else if (jsMethodAccess == null || jsMethodAccess.IsVirtual)
                {
                    methodInvocation = new JSDeferredExpression(JSInvocationExpression.InvokeMethod(jsMethod.Reference.DeclaringType, jsMethod, thisReference, arguments));
                }
                else
                {
                    methodInvocation = new JSDeferredExpression(JSInvocationExpression.InvokeBaseMethod(jsMethod.Reference.DeclaringType, jsMethod, thisReference, arguments));
                }

                invocationExpressionArguments = new[] {
                    thisReference,
                    methodInvocation,
                    new JSDeferredExpression(new JSMethodOfExpression(jsMethod.Reference, jsMethod.Method, jsMethod.MethodTypes, jsMethod.GenericArguments))
                };
            }

            return(JSInvocationExpression.InvokeStatic(
                       new JSDotExpression(
                           new JSType(delegateType),
                           new JSFakeMethod("New", delegateType, new[] { TypeSystem.Object, TypeSystem.Object }, MethodTypes)),
                       invocationExpressionArguments,
                       true));
        }
        private JSExpression ConstructInvocation(
            JSPropertyAccess pa, JSExpression argument = null
            )
        {
            JSExpression[] arguments;

            if (argument == null)
            {
                arguments = new JSExpression[0];
            }
            else
            {
                arguments = new JSExpression[] { argument }
            };

            var originalMethod    = pa.OriginalMethod;
            var declaringType     = originalMethod.Reference.DeclaringType;
            var declaringTypeDef  = TypeUtil.GetTypeDefinition(originalMethod.Reference.DeclaringType);
            var thisReferenceType = pa.ThisReference.GetActualType(TypeSystem);
            var isSelf            = TypeUtil.TypesAreAssignable(
                TypeInfo, thisReferenceType, declaringType
                );

            // ILSpy converts compound assignments from:
            //  x.set_Value(x.get_Value + n)
            // to
            //  x.get_Value += n;
            // so we have to detect this and reconstruct the correct method
            //  references.
            var actualMethod = originalMethod;
            var correctName  = String.Format(
                "{0}_{1}", pa.IsWrite ? "set" : "get",
                pa.Property.Property.ShortName
                );

            if (!actualMethod.Reference.Name.Contains(correctName))
            {
                var dt = originalMethod.Method.DeclaringType;

                var actualMethodInfo = dt.Members.Values
                                       .OfType <MethodInfo>().FirstOrDefault(
                    (m) => (
                        m.Name.Contains(correctName) &&
                        m.DeclaringType == originalMethod.Method.DeclaringType
                        )
                    );

                MethodReference actualMethodReference = actualMethodInfo.Member;
                if (originalMethod.Reference is GenericInstanceMethod)
                {
                    throw new InvalidDataException("Reconstructing an invocation of a generic instance method? Shouldn't be possible.");
                }
                else if (declaringType is GenericInstanceType)
                {
                    var declaringGit = (GenericInstanceType)declaringType;
                    var returnType   = actualMethodReference.ReturnType;

                    if (TypeUtil.IsOpenType(returnType))
                    {
                        var actualReturnType = JSExpression.SubstituteTypeArgs(TypeInfo, actualMethodReference.ReturnType, actualMethodReference);
                        returnType = actualReturnType;
                    }

                    actualMethodReference = new MethodReference(
                        actualMethodReference.Name, returnType, declaringGit
                        );
                }

                actualMethod = new JSMethod(
                    actualMethodReference, actualMethodInfo,
                    originalMethod.MethodTypes, originalMethod.GenericArguments
                    );
            }

            bool needsExplicitThis = !pa.IsVirtualCall && ILBlockTranslator.NeedsExplicitThis(
                declaringType, declaringTypeDef,
                originalMethod.Method.DeclaringType,
                isSelf, thisReferenceType,
                originalMethod.Method
                );

            JSInvocationExpressionBase invocation;

            if (pa.Property.Property.IsStatic)
            {
                invocation = JSInvocationExpression.InvokeStatic(
                    actualMethod.Reference.DeclaringType,
                    actualMethod,
                    arguments
                    );
            }
            else if (needsExplicitThis)
            {
                invocation = JSInvocationExpression.InvokeBaseMethod(
                    actualMethod.Reference.DeclaringType,
                    actualMethod, pa.ThisReference,
                    arguments
                    );
            }
            else
            {
                invocation = JSInvocationExpression.InvokeMethod(
                    pa.OriginalType, actualMethod, pa.ThisReference, arguments
                    );
            }

            JSExpression replacement;

            if (TypeUtil.IsStruct(pa.Property.Property.ReturnType))
            {
                replacement = new JSResultReferenceExpression(invocation);
            }
            else
            {
                replacement = invocation;
            }

            return(replacement);
        }