Browse Source

Implemented removal of closures ("display class" introduced by C# compiler for anonymous methods)

pull/37/head
Daniel Grunwald 15 years ago
parent
commit
d4c275410e
  1. 37
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 29
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 21
      ICSharpCode.Decompiler/Ast/DecompilerContext.cs
  4. 69
      ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs
  5. 135
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  6. 12
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  7. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  8. 2
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  9. 25
      ILSpy/CSharpLanguage.cs

37
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -13,10 +13,17 @@ namespace Decompiler @@ -13,10 +13,17 @@ namespace Decompiler
{
public class AstBuilder
{
public CancellationToken CancellationToken { get; set; }
DecompilerContext context = new DecompilerContext();
CompilationUnit astCompileUnit = new CompilationUnit();
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
public AstBuilder(DecompilerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public void GenerateCode(ITextOutput output)
{
GenerateCode(output, null);
@ -24,7 +31,7 @@ namespace Decompiler @@ -24,7 +31,7 @@ namespace Decompiler
public void GenerateCode(ITextOutput output, Predicate<IAstVisitor<object, object>> transformAbortCondition)
{
Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition, this.CancellationToken);
Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition, context);
astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null);
var outputFormatter = new TextOutputFormatter(output);
@ -105,6 +112,7 @@ namespace Decompiler @@ -105,6 +112,7 @@ namespace Decompiler
public TypeDeclaration CreateType(TypeDefinition typeDef)
{
TypeDeclaration astType = new TypeDeclaration();
astType.AddAnnotation(typeDef);
astType.Modifiers = ConvertModifiers(typeDef);
astType.Name = typeDef.Name;
@ -409,12 +417,13 @@ namespace Decompiler @@ -409,12 +417,13 @@ namespace Decompiler
MethodDeclaration CreateMethod(MethodDefinition methodDef)
{
MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.Name = methodDef.Name;
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Parameters = MakeParameters(methodDef.Parameters);
if (!methodDef.DeclaringType.IsInterface) {
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, this.CancellationToken);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
}
return astMethod;
}
@ -422,31 +431,33 @@ namespace Decompiler @@ -422,31 +431,33 @@ namespace Decompiler
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{
ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsStatic) {
// don't show visibility for static ctors
astMethod.Modifiers &= ~Modifiers.VisibilityMask;
}
astMethod.Parameters = MakeParameters(methodDef.Parameters);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, this.CancellationToken);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context);
return astMethod;
}
PropertyDeclaration CreateProperty(PropertyDefinition propDef)
{
PropertyDeclaration astProp = new PropertyDeclaration();
astProp.AddAnnotation(propDef);
astProp.Modifiers = ConvertModifiers(propDef.GetMethod ?? propDef.SetMethod);
astProp.Name = propDef.Name;
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) {
astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, this.CancellationToken)
};
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context)
}.WithAnnotation(propDef.GetMethod);
}
if (propDef.SetMethod != null) {
astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, this.CancellationToken)
};
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context)
}.WithAnnotation(propDef.SetMethod);
}
return astProp;
}
@ -454,18 +465,19 @@ namespace Decompiler @@ -454,18 +465,19 @@ namespace Decompiler
CustomEventDeclaration CreateEvent(EventDefinition eventDef)
{
CustomEventDeclaration astEvent = new CustomEventDeclaration();
astEvent.AddAnnotation(eventDef);
astEvent.Name = eventDef.Name;
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
if (eventDef.AddMethod != null) {
astEvent.AddAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, this.CancellationToken)
};
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, context)
}.WithAnnotation(eventDef.AddMethod);
}
if (eventDef.RemoveMethod != null) {
astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, this.CancellationToken)
};
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, context)
}.WithAnnotation(eventDef.RemoveMethod);
}
return astEvent;
}
@ -473,6 +485,7 @@ namespace Decompiler @@ -473,6 +485,7 @@ namespace Decompiler
FieldDeclaration CreateField(FieldDefinition fieldDef)
{
FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(fieldDef.Name);
astField.AddChild(initializer, FieldDeclaration.Roles.Variable);
astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef);

29
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -17,14 +17,18 @@ namespace Decompiler @@ -17,14 +17,18 @@ namespace Decompiler
{
MethodDefinition methodDef;
TypeSystem typeSystem;
CancellationToken cancellationToken;
DecompilerContext context;
HashSet<ILVariable> definedLocalVars = new HashSet<ILVariable>();
public static BlockStatement CreateMethodBody(MethodDefinition methodDef, CancellationToken cancellationToken)
public static BlockStatement CreateMethodBody(MethodDefinition methodDef, DecompilerContext context)
{
MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
context.CurrentMethod = methodDef;
try {
AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
builder.cancellationToken = cancellationToken;
builder.methodDef = methodDef;
builder.context = context;
builder.typeSystem = methodDef.Module.TypeSystem;
if (Debugger.IsAttached) {
return builder.CreateMethodBody();
@ -37,6 +41,9 @@ namespace Decompiler @@ -37,6 +41,9 @@ namespace Decompiler
throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex);
}
}
} finally {
context.CurrentMethod = oldCurrentMethod;
}
}
static readonly Dictionary<string, string> typeNameToVariableNameDict = new Dictionary<string, string> {
@ -60,15 +67,15 @@ namespace Decompiler @@ -60,15 +67,15 @@ namespace Decompiler
{
if (methodDef.Body == null) return null;
cancellationToken.ThrowIfCancellationRequested();
context.CancellationToken.ThrowIfCancellationRequested();
ILBlock ilMethod = new ILBlock();
ILAstBuilder astBuilder = new ILAstBuilder();
ilMethod.Body = astBuilder.Build(methodDef, true);
cancellationToken.ThrowIfCancellationRequested();
context.CancellationToken.ThrowIfCancellationRequested();
ILAstOptimizer bodyGraph = new ILAstOptimizer();
bodyGraph.Optimize(methodDef, ilMethod);
cancellationToken.ThrowIfCancellationRequested();
context.CancellationToken.ThrowIfCancellationRequested();
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"});
Dictionary<string, int> typeNames = new Dictionary<string, int>();
@ -110,7 +117,7 @@ namespace Decompiler @@ -110,7 +117,7 @@ namespace Decompiler
// astBlock.Children.Add(astLocalVar);
}
cancellationToken.ThrowIfCancellationRequested();
context.CancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod);
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
return astBlock;
@ -528,7 +535,7 @@ namespace Decompiler @@ -528,7 +535,7 @@ namespace Decompiler
expr.TypeArguments = ConvertTypeArguments(cecilMethod);
expr.AddAnnotation(cecilMethod);
return new IdentifierExpression("ldftn").Invoke(expr)
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(false, methodDef.DeclaringType));
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(false));
}
case Code.Ldvirtftn:
{
@ -537,7 +544,7 @@ namespace Decompiler @@ -537,7 +544,7 @@ namespace Decompiler
expr.TypeArguments = ConvertTypeArguments(cecilMethod);
expr.AddAnnotation(cecilMethod);
return new IdentifierExpression("ldvirtftn").Invoke(expr)
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(true, methodDef.DeclaringType));
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(true));
}
case Code.Calli: throw new NotImplementedException();
@ -557,13 +564,13 @@ namespace Decompiler @@ -557,13 +564,13 @@ namespace Decompiler
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
return new Ast.ThisReferenceExpression();
} else {
return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name);
return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand);
}
case Code.Ldarga:
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
return MakeRef(new Ast.ThisReferenceExpression());
} else {
return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name));
return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand));
}
case Code.Ldc_I4:
if (byteCode.InferredType == typeSystem.Boolean && (int)operand == 0)

21
ICSharpCode.Decompiler/Ast/DecompilerContext.cs

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
// 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.Threading;
using Mono.Cecil;
namespace Decompiler
{
public class DecompilerContext
{
public CancellationToken CancellationToken;
public TypeDefinition CurrentType;
public MethodDefinition CurrentMethod;
public DecompilerContext Clone()
{
return (DecompilerContext)MemberwiseClone();
}
}
}

69
ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
// 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.Diagnostics;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace Decompiler.Transforms
{
/// <summary>
/// Base class for AST visitors that need the current type/method context info.
/// </summary>
public abstract class ContextTrackingVisitor : DepthFirstAstVisitor<object, object>
{
protected readonly DecompilerContext context;
protected ContextTrackingVisitor(DecompilerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
TypeDefinition oldType = context.CurrentType;
try {
context.CurrentType = typeDeclaration.Annotation<TypeDefinition>();
return base.VisitTypeDeclaration(typeDeclaration, data);
} finally {
context.CurrentType = oldType;
}
}
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
Debug.Assert(context.CurrentMethod == null);
try {
context.CurrentMethod = methodDeclaration.Annotation<MethodDefinition>();
return base.VisitMethodDeclaration(methodDeclaration, data);
} finally {
context.CurrentMethod = null;
}
}
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
Debug.Assert(context.CurrentMethod == null);
try {
context.CurrentMethod = constructorDeclaration.Annotation<MethodDefinition>();
return base.VisitConstructorDeclaration(constructorDeclaration, data);
} finally {
context.CurrentMethod = null;
}
}
public override object VisitAccessor(Accessor accessor, object data)
{
Debug.Assert(context.CurrentMethod == null);
try {
context.CurrentMethod = accessor.Annotation<MethodDefinition>();
return base.VisitAccessor(accessor, data);
} finally {
context.CurrentMethod = null;
}
}
}
}

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

@ -2,9 +2,9 @@ @@ -2,9 +2,9 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -15,10 +15,8 @@ namespace Decompiler.Transforms @@ -15,10 +15,8 @@ namespace Decompiler.Transforms
/// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)".
/// For anonymous methods, creates an AnonymousMethodExpression.
/// </summary>
public class DelegateConstruction : DepthFirstAstVisitor<object, object>
public class DelegateConstruction : ContextTrackingVisitor
{
public CancellationToken CancellationToken { get; set; }
internal sealed class Annotation
{
/// <summary>
@ -26,18 +24,16 @@ namespace Decompiler.Transforms @@ -26,18 +24,16 @@ namespace Decompiler.Transforms
/// </summary>
public readonly bool IsVirtual;
/// <summary>
/// The method being decompiled.
/// </summary>
public readonly TypeDefinition ContainingType;
public Annotation(bool isVirtual, TypeDefinition containingType)
public Annotation(bool isVirtual)
{
this.IsVirtual = isVirtual;
this.ContainingType = containingType;
}
}
public DelegateConstruction(DecompilerContext context) : base(context)
{
}
public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
{
if (objectCreateExpression.Arguments.Count() == 2) {
@ -48,14 +44,14 @@ namespace Decompiler.Transforms @@ -48,14 +44,14 @@ namespace Decompiler.Transforms
IdentifierExpression methodIdent = (IdentifierExpression)((InvocationExpression)func).Arguments.Single();
MethodReference method = methodIdent.Annotation<MethodReference>();
if (method != null) {
if (HandleAnonymousMethod(objectCreateExpression, obj, method, annotation.ContainingType))
if (HandleAnonymousMethod(objectCreateExpression, obj, method))
return null;
// 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 != annotation.ContainingType) {
if (method.DeclaringType != context.CurrentType) {
obj = new BaseReferenceExpression();
}
}
@ -94,25 +90,21 @@ namespace Decompiler.Transforms @@ -94,25 +90,21 @@ namespace Decompiler.Transforms
return base.VisitObjectCreateExpression(objectCreateExpression, data);
}
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef, TypeDefinition containingType)
bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef)
{
// 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 (!(method.IsCompilerGenerated() || method.DeclaringType.IsCompilerGenerated()))
return false;
TypeDefinition methodContainingType = method.DeclaringType;
// check that methodContainingType is within containingType
while (methodContainingType != containingType) {
methodContainingType = methodContainingType.DeclaringType;
if (methodContainingType == null)
if (!(method.IsCompilerGenerated() || IsPotentialClosure(method.DeclaringType)))
return false;
}
// Decompile the anonymous method:
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, this.CancellationToken);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, this.CancellationToken);
DecompilerContext subContext = context.Clone();
subContext.CurrentMethod = method;
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext);
body.AcceptVisitor(this, null);
AnonymousMethodExpression ame = new AnonymousMethodExpression();
@ -132,5 +124,100 @@ namespace Decompiler.Transforms @@ -132,5 +124,100 @@ namespace Decompiler.Transforms
objectCreateExpression.ReplaceWith(ame);
return true;
}
bool IsPotentialClosure(TypeDefinition potentialDisplayClass)
{
if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGenerated())
return false;
// check that methodContainingType is within containingType
while (potentialDisplayClass != context.CurrentType) {
potentialDisplayClass = potentialDisplayClass.DeclaringType;
if (potentialDisplayClass == null)
return false;
}
return true;
}
public override object VisitBlockStatement(BlockStatement blockStatement, object data)
{
base.VisitBlockStatement(blockStatement, data);
foreach (VariableDeclarationStatement stmt in blockStatement.Statements.OfType<VariableDeclarationStatement>()) {
if (stmt.Variables.Count() != 1)
continue;
var variable = stmt.Variables.Single();
TypeDefinition type = stmt.Type.Annotation<TypeDefinition>();
if (!IsPotentialClosure(type))
continue;
ObjectCreateExpression oce = variable.Initializer as ObjectCreateExpression;
if (oce == null || oce.Type.Annotation<TypeReference>() != type || oce.Arguments.Any() || !oce.Initializer.IsNull)
continue;
// Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
bool ok = true;
foreach (var identExpr in blockStatement.Descendants.OfType<IdentifierExpression>()) {
if (identExpr.Identifier == variable.Name) {
if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation<FieldReference>() != null))
ok = false;
}
}
if (!ok)
continue;
Dictionary<string, Expression> dict = new Dictionary<string, Expression>();
// Delete the variable declaration statement:
AstNode cur;
AstNode next = stmt.NextSibling;
stmt.Remove();
for (cur = next; cur != null; cur = next) {
next = cur.NextSibling;
// Delete any following statements as long as they assign simple variables to the display class:
// Test for the pattern:
// "variableName.MemberName = right;"
ExpressionStatement es = cur as ExpressionStatement;
if (es == null)
break;
AssignmentExpression ae = es.Expression as AssignmentExpression;
if (ae == null || ae.Operator != AssignmentOperatorType.Assign)
break;
MemberReferenceExpression left = ae.Left as MemberReferenceExpression;
if (left == null || !IsParameter(ae.Right))
break;
if (!(left.Target is IdentifierExpression) || (left.Target as IdentifierExpression).Identifier != variable.Name)
break;
dict[left.MemberName] = ae.Right;
es.Remove();
}
// Now create variables for all fields of the display class (except for those that we already handled)
foreach (FieldDefinition field in type.Fields) {
if (dict.ContainsKey(field.Name))
continue;
VariableDeclarationStatement newVarDecl = new VariableDeclarationStatement();
newVarDecl.Type = AstBuilder.ConvertType(field.FieldType, field);
newVarDecl.Variables = new [] { new VariableInitializer(field.Name) };
blockStatement.InsertChildBefore(cur, newVarDecl, BlockStatement.StatementRole);
dict[field.Name] = new IdentifierExpression(field.Name);
}
// Now figure out where the closure was accessed and use the simpler replacement expression there:
foreach (var identExpr in blockStatement.Descendants.OfType<IdentifierExpression>()) {
if (identExpr.Identifier == variable.Name) {
MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
Expression replacement;
if (dict.TryGetValue(mre.MemberName, out replacement)) {
mre.ReplaceWith(replacement.Clone());
}
}
}
}
return null;
}
bool IsParameter(Expression expr)
{
if (expr is ThisReferenceExpression)
return true;
IdentifierExpression ident = expr as IdentifierExpression;
return ident != null && ident.Annotation<ParameterReference>() != null;
}
}
}

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

@ -9,22 +9,22 @@ namespace Decompiler.Transforms @@ -9,22 +9,22 @@ namespace Decompiler.Transforms
{
public static class TransformationPipeline
{
public static IAstVisitor<object, object>[] CreatePipeline(CancellationToken cancellationToken)
public static IAstVisitor<object, object>[] CreatePipeline(DecompilerContext context)
{
return new IAstVisitor<object, object>[] {
new PushNegation(),
new DelegateConstruction() { CancellationToken = cancellationToken },
new DelegateConstruction(context),
new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators(),
};
}
public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition, CancellationToken cancellationToken)
public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition, DecompilerContext context)
{
if (node == null)
return;
for (int i = 0; i < 4; i++) {
cancellationToken.ThrowIfCancellationRequested();
context.CancellationToken.ThrowIfCancellationRequested();
if (Options.ReduceAstJumps) {
node.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
node.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
@ -37,8 +37,8 @@ namespace Decompiler.Transforms @@ -37,8 +37,8 @@ namespace Decompiler.Transforms
}
}
foreach (var visitor in CreatePipeline(cancellationToken)) {
cancellationToken.ThrowIfCancellationRequested();
foreach (var visitor in CreatePipeline(context)) {
context.CancellationToken.ThrowIfCancellationRequested();
if (abortCondition != null && abortCondition(visitor))
return;
node.AcceptVisitor(visitor, null);

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -52,8 +52,10 @@ @@ -52,8 +52,10 @@
<Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMethodBodyBuilder.cs" />
<Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />

2
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.Tests
{
string code = File.ReadAllText(fileName);
AssemblyDefinition assembly = Compile(code);
AstBuilder decompiler = new AstBuilder();
AstBuilder decompiler = new AstBuilder(new DecompilerContext());
decompiler.AddAssembly(assembly);
StringWriter output = new StringWriter();
decompiler.GenerateCode(new PlainTextOutput(output));

25
ILSpy/CSharpLanguage.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy @@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy
internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{
string lastTransformName = "no transforms";
foreach (Type _transformType in TransformationPipeline.CreatePipeline(CancellationToken.None).Select(v => v.GetType()).Distinct()) {
foreach (Type _transformType in TransformationPipeline.CreatePipeline(new DecompilerContext()).Select(v => v.GetType()).Distinct()) {
Type transformType = _transformType; // copy for lambda
yield return new CSharpLanguage {
transformAbortCondition = v => transformType.IsInstanceOfType(v),
@ -69,35 +69,35 @@ namespace ICSharpCode.ILSpy @@ -69,35 +69,35 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, method.DeclaringType);
codeDomBuilder.AddMethod(method);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
}
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, property.DeclaringType);
codeDomBuilder.AddProperty(property);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, field.DeclaringType);
codeDomBuilder.AddField(field);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, ev.DeclaringType);
codeDomBuilder.AddEvent(ev);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, type);
codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
}
@ -106,7 +106,7 @@ namespace ICSharpCode.ILSpy @@ -106,7 +106,7 @@ namespace ICSharpCode.ILSpy
{
if (options.FullDecompilation) {
foreach (TypeDefinition type in assembly.MainModule.Types) {
AstBuilder codeDomBuilder = CreateAstBuilder(options);
AstBuilder codeDomBuilder = CreateAstBuilder(options, type);
codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
output.WriteLine();
@ -116,9 +116,13 @@ namespace ICSharpCode.ILSpy @@ -116,9 +116,13 @@ namespace ICSharpCode.ILSpy
}
}
AstBuilder CreateAstBuilder(DecompilationOptions options)
AstBuilder CreateAstBuilder(DecompilationOptions options, TypeDefinition currentType)
{
return new AstBuilder { CancellationToken = options.CancellationToken };
return new AstBuilder(
new DecompilerContext {
CancellationToken = options.CancellationToken,
CurrentType = currentType
});
}
public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes)
@ -163,6 +167,9 @@ namespace ICSharpCode.ILSpy @@ -163,6 +167,9 @@ namespace ICSharpCode.ILSpy
MethodDefinition method = member as MethodDefinition;
if (method != null && (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn))
return false;
TypeDefinition type = member as TypeDefinition;
if (type != null && type.Name.StartsWith("<>c__DisplayClass", StringComparison.Ordinal) && type.IsCompilerGenerated())
return false;
return true;
}
}

Loading…
Cancel
Save