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); }