Browse Source

Decompile as project: when multiple types end up in the same file, decompile them in a single pass.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
81830f5b04
  1. 103
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 8
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  3. 6
      ILSpy/Languages/CSharpLanguage.cs

103
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -36,6 +36,12 @@ using ICSharpCode.Decompiler.IL.Transforms;
namespace ICSharpCode.Decompiler.CSharp namespace ICSharpCode.Decompiler.CSharp
{ {
/// <summary>
/// Main class of the C# decompiler engine.
/// </summary>
/// <remarks>
/// Instances of this class are not thread-safe. Use separate instances to decompile multiple members in parallel.
/// </remarks>
public class CSharpDecompiler public class CSharpDecompiler
{ {
readonly DecompilerTypeSystem typeSystem; readonly DecompilerTypeSystem typeSystem;
@ -136,23 +142,19 @@ namespace ICSharpCode.Decompiler.CSharp
syntaxTree.AddChild(attrSection, SyntaxTree.MemberRole); syntaxTree.AddChild(attrSection, SyntaxTree.MemberRole);
} }
} }
public SyntaxTree DecompileWholeModuleAsSingleFile() void DoDecompileTypes(IEnumerable<TypeDefinition> types, ITypeResolveContext decompilationContext, SyntaxTree syntaxTree)
{ {
var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainAssembly);
SyntaxTree syntaxTree = new SyntaxTree();
DoDecompileModuleAndAssemblyAttributes(decompilationContext, syntaxTree);
string currentNamespace = null; string currentNamespace = null;
AstNode groupNode = null; AstNode groupNode = null;
foreach (var cecilType in typeSystem.ModuleDefinition.Types) { foreach (var cecilType in types) {
var typeDef = typeSystem.Resolve(cecilType).GetDefinition(); var typeDef = typeSystem.Resolve(cecilType).GetDefinition();
if (typeDef.Name == "<Module>" && typeDef.Members.Count == 0) if (typeDef.Name == "<Module>" && typeDef.Members.Count == 0)
continue; continue;
if(string.IsNullOrEmpty(cecilType.Namespace)) { if (string.IsNullOrEmpty(cecilType.Namespace)) {
groupNode = syntaxTree; groupNode = syntaxTree;
} else { } else {
if (currentNamespace != cecilType.Namespace) if (currentNamespace != cecilType.Namespace) {
{
groupNode = new NamespaceDeclaration(cecilType.Namespace); groupNode = new NamespaceDeclaration(cecilType.Namespace);
syntaxTree.AddChild(groupNode, SyntaxTree.MemberRole); syntaxTree.AddChild(groupNode, SyntaxTree.MemberRole);
} }
@ -161,24 +163,75 @@ namespace ICSharpCode.Decompiler.CSharp
var typeDecl = DoDecompile(typeDef, decompilationContext.WithCurrentTypeDefinition(typeDef)); var typeDecl = DoDecompile(typeDef, decompilationContext.WithCurrentTypeDefinition(typeDef));
groupNode.AddChild(typeDecl, SyntaxTree.MemberRole); groupNode.AddChild(typeDecl, SyntaxTree.MemberRole);
} }
}
/// <summary>
/// Decompiles the whole module into a single syntax tree.
/// </summary>
public SyntaxTree DecompileWholeModuleAsSingleFile()
{
var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainAssembly);
SyntaxTree syntaxTree = new SyntaxTree();
DoDecompileModuleAndAssemblyAttributes(decompilationContext, syntaxTree);
DoDecompileTypes(typeSystem.ModuleDefinition.Types, decompilationContext, syntaxTree);
RunTransforms(syntaxTree, decompilationContext); RunTransforms(syntaxTree, decompilationContext);
return syntaxTree; return syntaxTree;
} }
public SyntaxTree Decompile(TypeDefinition typeDefinition) /// <summary>
/// Decompile the given types.
/// </summary>
/// <remarks>
/// Unlike Decompile(IMemberDefinition[]), this method will add namespace declarations around the type definitions.
/// </remarks>
public SyntaxTree DecompileTypes(IEnumerable<TypeDefinition> types)
{ {
if (typeDefinition == null) if (types == null)
throw new ArgumentNullException("typeDefinition"); throw new ArgumentNullException("types");
ITypeDefinition typeDef = typeSystem.Resolve(typeDefinition).GetDefinition(); var decompilationContext = new SimpleTypeResolveContext(typeSystem.MainAssembly);
if (typeDef == null) SyntaxTree syntaxTree = new SyntaxTree();
throw new InvalidOperationException("Could not find type definition in NR type system"); DoDecompileTypes(types, decompilationContext, syntaxTree);
var decompilationContext = new SimpleTypeResolveContext(typeDef);
var syntaxTree = new SyntaxTree();
syntaxTree.Members.Add(DoDecompile(typeDef, decompilationContext));
RunTransforms(syntaxTree, decompilationContext); RunTransforms(syntaxTree, decompilationContext);
return syntaxTree; return syntaxTree;
} }
/// <summary>
/// Decompile the specified types and/or members.
/// </summary>
public SyntaxTree Decompile(params IMemberDefinition[] definitions)
{
if (definitions == null)
throw new ArgumentNullException("definitions");
var syntaxTree = new SyntaxTree();
foreach (var def in definitions) {
if (def == null)
throw new ArgumentException("definitions contains null element");
var typeDefinition = def as TypeDefinition;
var methodDefinition = def as MethodDefinition;
var fieldDefinition = def as FieldDefinition;
if (typeDefinition != null) {
ITypeDefinition typeDef = typeSystem.Resolve(typeDefinition).GetDefinition();
if (typeDef == null)
throw new InvalidOperationException("Could not find type definition in NR type system");
syntaxTree.Members.Add(DoDecompile(typeDef, new SimpleTypeResolveContext(typeDef)));
} else if (methodDefinition != null) {
IMethod method = typeSystem.Resolve(methodDefinition);
if (method == null)
throw new InvalidOperationException("Could not find method definition in NR type system");
syntaxTree.Members.Add(DoDecompile(methodDefinition, method, new SimpleTypeResolveContext(method)));
} else if (fieldDefinition != null) {
IField field = typeSystem.Resolve(fieldDefinition);
if (field == null)
throw new InvalidOperationException("Could not find field definition in NR type system");
syntaxTree.Members.Add(DoDecompile(fieldDefinition, field, new SimpleTypeResolveContext(field)));
} else {
throw new NotImplementedException();
}
}
RunTransforms(syntaxTree, new SimpleTypeResolveContext(typeSystem.MainAssembly));
return syntaxTree;
}
EntityDeclaration DoDecompile(ITypeDefinition typeDef, ITypeResolveContext decompilationContext) EntityDeclaration DoDecompile(ITypeDefinition typeDef, ITypeResolveContext decompilationContext)
{ {
Debug.Assert(decompilationContext.CurrentTypeDefinition == typeDef); Debug.Assert(decompilationContext.CurrentTypeDefinition == typeDef);
@ -237,20 +290,6 @@ namespace ICSharpCode.Decompiler.CSharp
return typeDecl; return typeDecl;
} }
public SyntaxTree Decompile(MethodDefinition methodDefinition)
{
if (methodDefinition == null)
throw new ArgumentNullException("methodDefinition");
var method = typeSystem.Resolve(methodDefinition);
if (method == null)
throw new InvalidOperationException("Could not find method in NR type system");
var decompilationContext = new SimpleTypeResolveContext(method);
var syntaxTree = new SyntaxTree();
syntaxTree.Members.Add(DoDecompile(methodDefinition, method, decompilationContext));
RunTransforms(syntaxTree, decompilationContext);
return syntaxTree;
}
EntityDeclaration DoDecompile(MethodDefinition methodDefinition, IMethod method, ITypeResolveContext decompilationContext) EntityDeclaration DoDecompile(MethodDefinition methodDefinition, IMethod method, ITypeResolveContext decompilationContext)
{ {
Debug.Assert(decompilationContext.CurrentMember == method); Debug.Assert(decompilationContext.CurrentMember == method);

8
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -14,8 +14,10 @@ namespace ICSharpCode.Decompiler
{ {
/// <summary> /// <summary>
/// Manages the NRefactory type system for the decompiler. /// Manages the NRefactory type system for the decompiler.
/// This class is thread-safe.
/// </summary> /// </summary>
/// <remarks>
/// This class is thread-safe.
/// </remarks>
public class DecompilerTypeSystem : IDecompilerTypeSystem public class DecompilerTypeSystem : IDecompilerTypeSystem
{ {
readonly ModuleDefinition moduleDefinition; readonly ModuleDefinition moduleDefinition;
@ -24,9 +26,9 @@ namespace ICSharpCode.Decompiler
/// <summary> /// <summary>
/// CecilLoader used for converting cecil type references to ITypeReference. /// CecilLoader used for converting cecil type references to ITypeReference.
/// May only be accessed within lock(cecilLoader). /// May only be accessed within lock(typeReferenceCecilLoader).
/// </summary> /// </summary>
CecilLoader typeReferenceCecilLoader = new CecilLoader(); readonly CecilLoader typeReferenceCecilLoader = new CecilLoader();
/// <summary> /// <summary>
/// Dictionary for NRefactory->Cecil lookup. Only contains entities from the main module. /// Dictionary for NRefactory->Cecil lookup. Only contains entities from the main module.

6
ILSpy/Languages/CSharpLanguage.cs

@ -516,10 +516,8 @@ namespace ICSharpCode.ILSpy
using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) { using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) {
CSharpDecompiler decompiler = new CSharpDecompiler(ts); CSharpDecompiler decompiler = new CSharpDecompiler(ts);
decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers());
foreach (TypeDefinition type in file) { var syntaxTree = decompiler.DecompileTypes(file.ToArray());
var syntaxTree = decompiler.Decompile(type); syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, options.DecompilerSettings.CSharpFormattingOptions));
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(w, options.DecompilerSettings.CSharpFormattingOptions));
}
} }
}); });
return files.Select(f => Tuple.Create("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, options, directories)); return files.Select(f => Tuple.Create("Compile", f.Key)).Concat(WriteAssemblyInfo(ts, options, directories));

Loading…
Cancel
Save