Browse Source

Add support for anonymous methods.

pull/10/head
Daniel Grunwald 15 years ago
parent
commit
fb97498d28
  1. 27
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 2
      ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  3. 55
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  4. 2
      ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  5. 28
      ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs
  6. 50
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  7. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

27
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -17,30 +17,7 @@ namespace Decompiler @@ -17,30 +17,7 @@ namespace Decompiler
public void GenerateCode(ITextOutput output)
{
astCompileUnit.AcceptVisitor(new Transforms.DelegateConstruction(), null);
for (int i = 0; i < 4; i++) {
if (Options.ReduceAstJumps) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
}
if (Options.ReduceAstLoops) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
}
if (Options.ReduceAstOther) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null);
}
}
if (Options.ReduceAstOther) {
astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null);
}
if (Options.ReduceAstLoops) {
//astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
}
astCompileUnit.AcceptVisitor(new Transforms.Ast.ConvertConstructorCallIntoInitializer(), null);
astCompileUnit.AcceptVisitor(new Transforms.Ast.ReplaceMethodCallsWithOperators(), null);
Transforms.TransformationPipeline.RunTransformations(astCompileUnit);
astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null);
var outputFormatter = new TextOutputFormatter(output);
@ -489,7 +466,7 @@ namespace Decompiler @@ -489,7 +466,7 @@ namespace Decompiler
return astField;
}
IEnumerable<ParameterDeclaration> MakeParameters(IEnumerable<ParameterDefinition> paramCol)
public static IEnumerable<ParameterDeclaration> MakeParameters(IEnumerable<ParameterDefinition> paramCol)
{
foreach(ParameterDefinition paramDef in paramCol) {
ParameterDeclaration astParam = new ParameterDeclaration();

2
ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -6,7 +6,7 @@ using System.Linq; @@ -6,7 +6,7 @@ using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace Decompiler.Transforms.Ast
namespace Decompiler.Transforms
{
public class ConvertConstructorCallIntoInitializer : DepthFirstAstVisitor<object, object>
{

55
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -10,6 +10,7 @@ namespace Decompiler.Transforms @@ -10,6 +10,7 @@ namespace Decompiler.Transforms
{
/// <summary>
/// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)".
/// For anonymous methods, creates an AnonymousMethodExpression.
/// </summary>
public class DelegateConstruction : DepthFirstAstVisitor<object, object>
{
@ -42,7 +43,9 @@ namespace Decompiler.Transforms @@ -42,7 +43,9 @@ namespace Decompiler.Transforms
IdentifierExpression methodIdent = (IdentifierExpression)((InvocationExpression)func).Arguments.Single();
MethodReference method = methodIdent.Annotation<MethodReference>();
if (method != null) {
// Perform the transformation:
if (HandleAnonymousMethod(objectCreateExpression, obj, method, annotation.ContainingType))
return null;
// Perform the transformation to "new Action(obj.func)".
obj.Remove();
methodIdent.Remove();
if (!annotation.IsVirtual && obj is ThisReferenceExpression) {
@ -83,5 +86,55 @@ namespace Decompiler.Transforms @@ -83,5 +86,55 @@ namespace Decompiler.Transforms
}
return base.VisitObjectCreateExpression(objectCreateExpression, data);
}
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef, TypeDefinition containingType)
{
// Anonymous methods are defined in the same assembly, so there's no need to Resolve().
MethodDefinition method = methodRef as MethodDefinition;
if (method == null || !method.Name.StartsWith("<", StringComparison.Ordinal))
return false;
if (!(IsCompilerGenerated(method) || IsCompilerGenerated(method.DeclaringType)))
return false;
TypeDefinition methodContainingType = method.DeclaringType;
// check that methodContainingType is within containingType
while (methodContainingType != containingType) {
methodContainingType = methodContainingType.DeclaringType;
if (methodContainingType == null)
return false;
}
// Decompile the anonymous method:
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction);
body.AcceptVisitor(this, null);
AnonymousMethodExpression ame = new AnonymousMethodExpression();
if (method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) {
ame.HasParameterList = false;
} else {
ame.HasParameterList = true;
ame.Parameters = AstBuilder.MakeParameters(method.Parameters);
}
ame.Body = body;
// Replace all occurrences of 'this' in the method body with the delegate's target:
foreach (AstNode node in body.Descendants) {
if (node is ThisReferenceExpression)
node.ReplaceWith(target.Clone());
}
objectCreateExpression.ReplaceWith(ame);
return true;
}
bool IsCompilerGenerated(ICustomAttributeProvider provider)
{
if (provider.HasCustomAttributes) {
foreach (CustomAttribute a in provider.CustomAttributes) {
if (a.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")
return true;
}
}
return false;
}
}
}

2
ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs

@ -5,7 +5,7 @@ using Mono.Cecil; @@ -5,7 +5,7 @@ using Mono.Cecil;
using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast
namespace Decompiler.Transforms
{
/// <summary>
/// Replaces method calls with the appropriate operator expressions.

28
ICSharpCode.Decompiler/Ast/Transforms/SimplifyTypeReferences.cs

@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
using System;
using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms.Ast
{
public class SimplifyTypeReferences: DepthFirstAstVisitor<object, object>
{
string currentNamepace = string.Empty;
string currentClass = null;
public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
{
currentNamepace = namespaceDeclaration.Name;
base.VisitNamespaceDeclaration(namespaceDeclaration, data);
currentNamepace = string.Empty;
return null;
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
currentClass = currentNamepace + "." + typeDeclaration.Name;
base.VisitTypeDeclaration(typeDeclaration, data);
currentClass = null;
return null;
}
}
}

50
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// 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 ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms
{
public static class TransformationPipeline
{
static IAstVisitor<object, object>[] CreatePipeline()
{
return new IAstVisitor<object, object>[] {
new DelegateConstruction(),
new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators()
};
}
public static void RunTransformations(AstNode node)
{
RunTransformationsUntil(node, v => false);
}
public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition)
{
if (node == null)
return;
for (int i = 0; i < 4; i++) {
if (Options.ReduceAstJumps) {
node.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
node.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
}
if (Options.ReduceAstLoops) {
node.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null);
}
if (Options.ReduceAstOther) {
node.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null);
node.AcceptVisitor(new Transforms.Ast.PushNegation(), null);
}
}
foreach (var visitor in CreatePipeline()) {
if (abortCondition(visitor))
return;
node.AcceptVisitor(visitor, null);
}
}
}
}

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -62,7 +62,7 @@ @@ -62,7 +62,7 @@
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\SimplifyTypeReferences.cs" />
<Compile Include="Ast\Transforms\TransformationPipeline.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" />

Loading…
Cancel
Save