public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data) { if (objectCreateExpression.Arguments.Count == 2) { Expression obj = objectCreateExpression.Arguments.First(); Expression func = objectCreateExpression.Arguments.Last(); Annotation annotation = func.Annotation <Annotation>(); if (annotation != null) { IdentifierExpression methodIdent = (IdentifierExpression)((InvocationExpression)func).Arguments.Single(); IMethod method = methodIdent.Annotation <IMethod>(); if (method != null) { if (HandleAnonymousMethod(objectCreateExpression, obj, method)) { return(null); } var ilRanges = objectCreateExpression.GetAllRecursiveILRanges(); // Perform the transformation to "new Action(obj.func)". obj.Remove(); methodIdent.Remove(); if (!annotation.IsVirtual && obj is ThisReferenceExpression) { // maybe it's getting the pointer of a base method? if (method.DeclaringType.ResolveTypeDef() != context.CurrentType) { obj = new BaseReferenceExpression().WithAnnotation(method.DeclaringType); } } if (!annotation.IsVirtual && obj is NullReferenceExpression && method.MethodSig != null && !method.MethodSig.HasThis) { // We're loading a static method. // However it is possible to load extension methods with an instance, so we compare the number of arguments: bool isExtensionMethod = false; ITypeDefOrRef delegateType = objectCreateExpression.Type.Annotation <ITypeDefOrRef>(); if (delegateType != null) { TypeDef delegateTypeDef = delegateType.ResolveTypeDef(); if (delegateTypeDef != null) { MethodDef invokeMethod = delegateTypeDef.Methods.FirstOrDefault(m => m.Name == "Invoke"); if (invokeMethod != null) { isExtensionMethod = (invokeMethod.Parameters.GetNumberOfNormalParameters() + 1 == method.MethodSig.GetParameters().Count); } } } if (!isExtensionMethod) { obj = new TypeReferenceExpression { Type = AstBuilder.ConvertType(method.DeclaringType) }; } } // now transform the identifier into a member reference MemberReferenceExpression mre = new MemberReferenceExpression(); mre.Target = obj; mre.MemberNameToken = (Identifier)methodIdent.IdentifierToken.Clone(); methodIdent.TypeArguments.MoveTo(mre.TypeArguments); mre.AddAnnotation(method); objectCreateExpression.Arguments.Clear(); objectCreateExpression.Arguments.Add(mre); objectCreateExpression.AddAnnotation(ilRanges); return(null); } } } return(base.VisitObjectCreateExpression(objectCreateExpression, data)); }
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, IMethod methodRef) { if (!context.Settings.AnonymousMethods) { return(false); // anonymous method decompilation is disabled } if (target != null && !(target is IdentifierExpression || target is ThisReferenceExpression || target is NullReferenceExpression)) { return(false); // don't copy arbitrary expressions, deal with identifiers only } // Anonymous methods are defined in the same assembly MethodDef method = methodRef.ResolveMethodWithinSameModule(); if (!IsAnonymousMethod(context, method)) { return(false); } var ilRanges = objectCreateExpression.GetAllRecursiveILRanges(); // Create AnonymousMethodExpression and prepare parameters AnonymousMethodExpression ame = new AnonymousMethodExpression(); ame.CopyAnnotationsFrom(objectCreateExpression); // copy ILRanges etc. ame.RemoveAnnotations <IMethod>(); // remove reference to delegate ctor ame.AddAnnotation(method); // add reference to anonymous method ame.Parameters.AddRange(AstBuilder.MakeParameters(method, isLambda: true)); ame.HasParameterList = true; // rename variables so that they don't conflict with the parameters: foreach (ParameterDeclaration pd in ame.Parameters) { EnsureVariableNameIsAvailable(objectCreateExpression, pd.Name); } // Decompile the anonymous method: DecompilerContext subContext = context.Clone(); subContext.CurrentMethod = method; subContext.CurrentMethodIsAsync = false; subContext.ReservedVariableNames.AddRange(currentlyUsedVariableNames); MemberMapping mm; BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext, ame.Parameters, out mm); body.AddAnnotation(mm); TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext); body.AcceptVisitor(this, null); bool isLambda = false; if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None)) { isLambda = body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement && body.HiddenStart == null && body.HiddenEnd == null; } // Remove the parameter list from an AnonymousMethodExpression if the original method had no names, // and the parameters are not used in the method body if (!isLambda && method.Parameters.SkipNonNormal().All(p => string.IsNullOrEmpty(p.Name))) { var parameterReferencingIdentifiers = from ident in body.Descendants.OfType <IdentifierExpression>() let v = ident.Annotation <ILVariable>() where v != null && v.IsParameter && method.Parameters.Contains(v.OriginalParameter) select ident; if (!parameterReferencingIdentifiers.Any()) { ame.AddAnnotation(ame.Parameters.GetAllRecursiveILRanges()); ame.Parameters.Clear(); ame.HasParameterList = false; } } // Replace all occurrences of 'this' in the method body with the delegate's target: foreach (AstNode node in body.Descendants) { if (node is ThisReferenceExpression) { var newTarget = target.Clone(); newTarget.RemoveAllILRangesRecursive(); newTarget.AddAnnotation(node.GetAllRecursiveILRanges()); node.ReplaceWith(newTarget); } } Expression replacement; if (isLambda) { LambdaExpression lambda = new LambdaExpression(); lambda.CopyAnnotationsFrom(ame); ame.Parameters.MoveTo(lambda.Parameters); var stmtIlRanges = body.Statements.Single().GetAllILRanges(); Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression; if (stmtIlRanges.Count > 0) { returnExpr.AddAnnotation(stmtIlRanges); } returnExpr.Remove(); lambda.Body = returnExpr; replacement = lambda; } else { ame.Body = body; replacement = ame; } var expectedType = objectCreateExpression.Annotation <TypeInformation>().ExpectedType.Resolve(); if (expectedType != null && !expectedType.IsDelegate()) { var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Clone(); simplifiedDelegateCreation.Arguments.Clear(); simplifiedDelegateCreation.Arguments.Add(replacement); replacement = simplifiedDelegateCreation; } objectCreateExpression.ReplaceWith(replacement); replacement.AddAnnotation(ilRanges); return(true); }