Esempio n. 1
0
 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));
 }
Esempio n. 2
0
        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);
        }