mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
11 KiB
316 lines
11 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Xml.Linq; |
|
|
|
using ICSharpCode.NRefactory.Ast; |
|
using ICSharpCode.NRefactory.PrettyPrinter; |
|
using Mono.Cecil; |
|
using Mono.Cecil.Cil; |
|
using Ast = ICSharpCode.NRefactory.Ast; |
|
|
|
namespace Decompiler |
|
{ |
|
public class AstBuilder |
|
{ |
|
CompilationUnit astCompileUnit = new CompilationUnit(); |
|
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); |
|
|
|
public string GenerateCode() |
|
{ |
|
CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor(); |
|
|
|
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.Idioms(), null); |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
|
} |
|
} |
|
if (Options.ReduceAstOther) { |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null); |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); |
|
} |
|
if (Options.ReduceAstLoops) { |
|
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); |
|
} |
|
|
|
astCompileUnit.AcceptVisitor(csOutVisitor, null); |
|
|
|
string code = csOutVisitor.Text; |
|
for(int i = 10; i >= 0; i--) { |
|
code = code.Replace("\r\n" + new string('\t', i) + "else {", " else {"); |
|
} |
|
code = code.Replace("\t", " "); |
|
code = code.Replace("\"/***", ""); |
|
code = code.Replace("***/\";", ""); |
|
|
|
// Post processing commands |
|
while(true) { |
|
int endIndex = code.IndexOf("[JoinLine]") + "[JoinLine]".Length; |
|
if (endIndex != -1) { |
|
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); |
|
if (startIndex != -1) { |
|
code = code.Remove(startIndex, endIndex - startIndex); |
|
continue; |
|
} |
|
} |
|
break; |
|
} |
|
while(true) { |
|
int endIndex = code.IndexOf("[Tab]"); |
|
if (endIndex != -1) { |
|
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); |
|
if (startIndex != -1) { |
|
code = code.Remove(endIndex, "[Tab]".Length); |
|
code = code.Insert(endIndex, new string(' ', Math.Max(0, 40 - endIndex + startIndex))); |
|
continue; |
|
} |
|
} |
|
break; |
|
} |
|
|
|
return code; |
|
} |
|
|
|
public void AddAssembly(AssemblyDefinition assemblyDefinition) |
|
{ |
|
Ast.UsingDeclaration astUsing = new Ast.UsingDeclaration("System"); |
|
astCompileUnit.Children.Add(astUsing); |
|
|
|
foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { |
|
// Skip nested types - they will be added by the parent type |
|
if (typeDef.DeclaringType != null) continue; |
|
// Skip the <Module> class |
|
if (typeDef.Name == "<Module>") continue; |
|
|
|
AddType(typeDef); |
|
} |
|
} |
|
|
|
NamespaceDeclaration GetCodeNamespace(string name) |
|
{ |
|
if (string.IsNullOrEmpty(name)) { |
|
return null; |
|
} |
|
if (astNamespaces.ContainsKey(name)) { |
|
return astNamespaces[name]; |
|
} else { |
|
// Create the namespace |
|
NamespaceDeclaration astNamespace = new NamespaceDeclaration(name); |
|
astCompileUnit.Children.Add(astNamespace); |
|
astNamespaces[name] = astNamespace; |
|
return astNamespace; |
|
} |
|
} |
|
|
|
public void AddType(TypeDefinition typeDef) |
|
{ |
|
TypeDeclaration astType = CreateType(typeDef); |
|
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); |
|
if (astNS != null) { |
|
astNS.Children.Add(astType); |
|
} else { |
|
astCompileUnit.Children.Add(astType); |
|
} |
|
} |
|
|
|
public TypeDeclaration CreateType(TypeDefinition typeDef) |
|
{ |
|
TypeDeclaration astType = new TypeDeclaration(ConvertModifiers(typeDef), new List<AttributeSection>()); |
|
astType.Name = typeDef.Name; |
|
|
|
if (typeDef.IsEnum) { // NB: Enum is value type |
|
astType.Type = ClassType.Enum; |
|
} else if (typeDef.IsValueType) { |
|
astType.Type = ClassType.Struct; |
|
} else if (typeDef.IsInterface) { |
|
astType.Type = ClassType.Interface; |
|
} else { |
|
astType.Type = ClassType.Class; |
|
} |
|
|
|
// Nested types |
|
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) { |
|
astType.Children.Add(CreateType(nestedTypeDef)); |
|
} |
|
|
|
// Base type |
|
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { |
|
astType.BaseTypes.Add(new Ast.TypeReference(typeDef.BaseType.FullName)); |
|
} |
|
|
|
AddTypeMembers(astType, typeDef); |
|
|
|
return astType; |
|
} |
|
|
|
Modifiers ConvertModifiers(TypeDefinition typeDef) |
|
{ |
|
return |
|
(typeDef.IsNestedPrivate ? Modifiers.Private : Modifiers.None) | |
|
(typeDef.IsNestedFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access |
|
(typeDef.IsNestedAssembly ? Modifiers.Internal : Modifiers.None) | |
|
(typeDef.IsNestedFamily ? Modifiers.Protected : Modifiers.None) | |
|
(typeDef.IsNestedFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
|
(typeDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
|
(typeDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); |
|
} |
|
|
|
Modifiers ConvertModifiers(FieldDefinition fieldDef) |
|
{ |
|
return |
|
(fieldDef.IsPrivate ? Modifiers.Private : Modifiers.None) | |
|
(fieldDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access |
|
(fieldDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | |
|
(fieldDef.IsFamily ? Modifiers.Protected : Modifiers.None) | |
|
(fieldDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
|
(fieldDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
|
(fieldDef.IsLiteral ? Modifiers.Const : Modifiers.None) | |
|
(fieldDef.IsStatic ? Modifiers.Static : Modifiers.None); |
|
} |
|
|
|
Modifiers ConvertModifiers(MethodDefinition methodDef) |
|
{ |
|
return |
|
(methodDef.IsCompilerControlled ? Modifiers.None : Modifiers.None) | |
|
(methodDef.IsPrivate ? Modifiers.Private : Modifiers.None) | |
|
(methodDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access |
|
(methodDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | |
|
(methodDef.IsFamily ? Modifiers.Protected : Modifiers.None) | |
|
(methodDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
|
(methodDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
|
(methodDef.IsStatic ? Modifiers.Static : Modifiers.None) | |
|
(methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) | |
|
(methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); |
|
} |
|
|
|
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) |
|
{ |
|
// Add fields |
|
foreach(FieldDefinition fieldDef in typeDef.Fields) { |
|
Ast.FieldDeclaration astField = new Ast.FieldDeclaration(new List<AttributeSection>()); |
|
astField.Fields.Add(new Ast.VariableDeclaration(fieldDef.Name)); |
|
astField.TypeReference = new Ast.TypeReference(fieldDef.FieldType.FullName); |
|
astField.Modifier = ConvertModifiers(fieldDef); |
|
|
|
astType.Children.Add(astField); |
|
} |
|
|
|
if (typeDef.Fields.Count > 0) { |
|
astType.Children.Add(new IdentifierExpression("\r\n")); |
|
} |
|
|
|
// Add events |
|
foreach(EventDefinition eventDef in typeDef.Events) { |
|
Ast.EventDeclaration astEvent = new Ast.EventDeclaration(); |
|
astEvent.Name = eventDef.Name; |
|
astEvent.TypeReference = new Ast.TypeReference(eventDef.EventType.FullName); |
|
astEvent.Modifier = ConvertModifiers(eventDef.AddMethod); |
|
|
|
astType.Children.Add(astEvent); |
|
} |
|
|
|
if (typeDef.Events.Count > 0) { |
|
astType.Children.Add(new IdentifierExpression("\r\n")); |
|
} |
|
|
|
// Add properties |
|
foreach(PropertyDefinition propDef in typeDef.Properties) { |
|
Ast.PropertyDeclaration astProp = new Ast.PropertyDeclaration( |
|
ConvertModifiers(propDef.GetMethod), |
|
new List<AttributeSection>(), |
|
propDef.Name, |
|
new List<ParameterDeclarationExpression>() |
|
); |
|
astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName); |
|
|
|
if (propDef.GetMethod != null) { |
|
astProp.GetRegion = new PropertyGetRegion( |
|
AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod), |
|
new List<AttributeSection>() |
|
); |
|
} |
|
if (propDef.SetMethod != null) { |
|
astProp.SetRegion = new PropertySetRegion( |
|
AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod), |
|
new List<AttributeSection>() |
|
); |
|
} |
|
|
|
astType.Children.Add(astProp); |
|
} |
|
|
|
if (typeDef.Properties.Count > 0) { |
|
astType.Children.Add(new IdentifierExpression("\r\n")); |
|
} |
|
|
|
// Add constructors |
|
foreach(MethodDefinition methodDef in typeDef.Methods) { |
|
if (!methodDef.IsConstructor) continue; |
|
|
|
Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration( |
|
methodDef.Name, |
|
ConvertModifiers(methodDef), |
|
new List<ParameterDeclarationExpression>(MakeParameters(methodDef.Parameters)), |
|
new List<AttributeSection>() |
|
); |
|
|
|
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); |
|
|
|
astType.Children.Add(astMethod); |
|
astType.Children.Add(new IdentifierExpression("\r\n")); |
|
} |
|
|
|
// Add methods |
|
foreach(MethodDefinition methodDef in typeDef.Methods) { |
|
if (methodDef.IsSpecialName) continue; |
|
|
|
Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration(); |
|
astMethod.Name = methodDef.Name; |
|
astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.FullName); |
|
astMethod.Modifier = ConvertModifiers(methodDef); |
|
|
|
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); |
|
|
|
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); |
|
|
|
astType.Children.Add(astMethod); |
|
|
|
astType.Children.Add(new IdentifierExpression("\r\n")); |
|
} |
|
|
|
if (astType.Children.LastOrDefault() is IdentifierExpression) { |
|
astType.Children.Remove(astType.Children.Last()); |
|
} |
|
} |
|
|
|
IEnumerable<Ast.ParameterDeclarationExpression> MakeParameters(IEnumerable<ParameterDefinition> paramCol) |
|
{ |
|
foreach(ParameterDefinition paramDef in paramCol) { |
|
Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression( |
|
new Ast.TypeReference(paramDef.ParameterType.FullName), |
|
paramDef.Name |
|
); |
|
|
|
if (paramDef.IsIn && !paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.In; |
|
if (!paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Out; |
|
if (paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Ref; |
|
|
|
yield return astParam; |
|
} |
|
} |
|
} |
|
}
|
|
|