mirror of https://github.com/icsharpcode/ILSpy.git
4 changed files with 182 additions and 80 deletions
@ -0,0 +1,87 @@
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Linq; |
||||
using ICSharpCode.NRefactory.CSharp; |
||||
using Mono.Cecil; |
||||
|
||||
namespace Decompiler.Transforms |
||||
{ |
||||
/// <summary>
|
||||
/// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)".
|
||||
/// </summary>
|
||||
public class DelegateConstruction : DepthFirstAstVisitor<object, object> |
||||
{ |
||||
internal sealed class Annotation |
||||
{ |
||||
/// <summary>
|
||||
/// ldftn or ldvirtftn?
|
||||
/// </summary>
|
||||
public readonly bool IsVirtual; |
||||
|
||||
/// <summary>
|
||||
/// The method being decompiled.
|
||||
/// </summary>
|
||||
public readonly TypeDefinition ContainingType; |
||||
|
||||
public Annotation(bool isVirtual, TypeDefinition containingType) |
||||
{ |
||||
this.IsVirtual = isVirtual; |
||||
this.ContainingType = containingType; |
||||
} |
||||
} |
||||
|
||||
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(); |
||||
MethodReference method = methodIdent.Annotation<MethodReference>(); |
||||
if (method != null) { |
||||
// Perform the transformation:
|
||||
obj.Remove(); |
||||
methodIdent.Remove(); |
||||
if (!annotation.IsVirtual && obj is ThisReferenceExpression) { |
||||
// maybe it's getting the pointer of a base method?
|
||||
if (method.DeclaringType != annotation.ContainingType) { |
||||
obj = new BaseReferenceExpression(); |
||||
} |
||||
} |
||||
if (!annotation.IsVirtual && obj is NullReferenceExpression && !method.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; |
||||
TypeReference delegateType = objectCreateExpression.Type.Annotation<TypeReference>(); |
||||
if (delegateType != null) { |
||||
TypeDefinition delegateTypeDef = delegateType.Resolve(); |
||||
if (delegateTypeDef != null) { |
||||
MethodDefinition invokeMethod = delegateTypeDef.Methods.FirstOrDefault(m => m.Name == "Invoke"); |
||||
if (invokeMethod != null) { |
||||
isExtensionMethod = (invokeMethod.Parameters.Count + 1 == method.Parameters.Count); |
||||
} |
||||
} |
||||
} |
||||
if (!isExtensionMethod) { |
||||
obj = new TypeReferenceExpression { Type = AstBuilder.ConvertType(method.DeclaringType) }; |
||||
} |
||||
} |
||||
// now transform the identifier into a member reference
|
||||
MemberReferenceExpression mre = new MemberReferenceExpression { |
||||
Target = obj, |
||||
MemberName = methodIdent.Identifier, |
||||
TypeArguments = methodIdent.TypeArguments |
||||
}; |
||||
mre.AddAnnotation(method); |
||||
objectCreateExpression.Arguments = new [] { mre }; |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
return base.VisitObjectCreateExpression(objectCreateExpression, data); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue