.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
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.
 
 
 
 

495 lines
17 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
using Mono.Cecil.Cil;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
namespace Decompiler
{
public class AstBuilder
{
CompilationUnit astCompileUnit = new CompilationUnit();
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
public void GenerateCode(ITextOutput output)
{
GenerateCode(output, null);
}
public void GenerateCode(ITextOutput output, Predicate<IAstVisitor<object, object>> transformAbortCondition)
{
Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition);
astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null);
var outputFormatter = new TextOutputFormatter(output);
var formattingPolicy = new CSharpFormattingPolicy();
// disable whitespace in front of parentheses:
formattingPolicy.BeforeMethodCallParentheses = false;
formattingPolicy.BeforeMethodDeclarationParentheses = false;
formattingPolicy.BeforeConstructorDeclarationParentheses = false;
formattingPolicy.BeforeDelegateDeclarationParentheses = false;
astCompileUnit.AcceptVisitor(new OutputVisitor(outputFormatter, formattingPolicy), null);
}
public void AddAssembly(AssemblyDefinition assemblyDefinition)
{
astCompileUnit.AddChild(
new UsingDeclaration {
Import = new SimpleType("System")
}, CompilationUnit.MemberRole);
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 = name };
astCompileUnit.AddChild(astNamespace, CompilationUnit.MemberRole);
astNamespaces[name] = astNamespace;
return astNamespace;
}
}
public void AddType(TypeDefinition typeDef)
{
TypeDeclaration astType = CreateType(typeDef);
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
if (astNS != null) {
astNS.AddChild(astType, NamespaceDeclaration.MemberRole);
} else {
astCompileUnit.AddChild(astType, CompilationUnit.MemberRole);
}
}
public void AddMethod(MethodDefinition method)
{
AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
astCompileUnit.AddChild(node, CompilationUnit.MemberRole);
}
public void AddProperty(PropertyDefinition property)
{
astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole);
}
public void AddField(FieldDefinition field)
{
astCompileUnit.AddChild(CreateField(field), CompilationUnit.MemberRole);
}
public void AddEvent(EventDefinition ev)
{
astCompileUnit.AddChild(CreateEvent(ev), CompilationUnit.MemberRole);
}
public TypeDeclaration CreateType(TypeDefinition typeDef)
{
TypeDeclaration astType = new TypeDeclaration();
astType.Modifiers = ConvertModifiers(typeDef);
astType.Name = typeDef.Name;
if (typeDef.IsEnum) { // NB: Enum is value type
astType.ClassType = ClassType.Enum;
astType.Modifiers &= ~Modifiers.Sealed;
} else if (typeDef.IsValueType) {
astType.ClassType = ClassType.Struct;
astType.Modifiers &= ~Modifiers.Sealed;
} else if (typeDef.IsInterface) {
astType.ClassType = ClassType.Interface;
astType.Modifiers &= ~Modifiers.Abstract;
} else {
astType.ClassType = ClassType.Class;
}
// Nested types
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) {
astType.AddChild(CreateType(nestedTypeDef), TypeDeclaration.MemberRole);
}
if (typeDef.IsEnum) {
foreach (FieldDefinition field in typeDef.Fields) {
if (field.IsRuntimeSpecialName) {
// the value__ field
astType.AddChild(ConvertType(field.FieldType), TypeDeclaration.BaseTypeRole);
} else {
EnumMemberDeclaration enumMember = new EnumMemberDeclaration();
enumMember.Name = field.Name;
astType.AddChild(enumMember, TypeDeclaration.MemberRole);
}
}
} else {
// Base type
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) {
astType.AddChild(ConvertType(typeDef.BaseType), TypeDeclaration.BaseTypeRole);
}
foreach (var i in typeDef.Interfaces)
astType.AddChild(ConvertType(i), TypeDeclaration.BaseTypeRole);
AddTypeMembers(astType, typeDef);
}
return astType;
}
#region Convert Type Reference
/// <summary>
/// Converts a type reference.
/// </summary>
/// <param name="type">The Cecil type reference that should be converted into
/// a type system type reference.</param>
/// <param name="typeAttributes">Attributes associated with the Cecil type reference.
/// This is used to support the 'dynamic' type.</param>
public static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes = null)
{
int typeIndex = 0;
return ConvertType(type, typeAttributes, ref typeIndex);
}
static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex)
{
while (type is OptionalModifierType || type is RequiredModifierType) {
type = ((TypeSpecification)type).ElementType;
}
if (type == null) {
return AstType.Null;
}
if (type is Mono.Cecil.ByReferenceType) {
typeIndex++;
// ignore by reference type (cannot be represented in C#)
return ConvertType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex);
} else if (type is Mono.Cecil.PointerType) {
typeIndex++;
return ConvertType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex)
.MakePointerType();
} else if (type is Mono.Cecil.ArrayType) {
typeIndex++;
return ConvertType((type as Mono.Cecil.ArrayType).ElementType, typeAttributes, ref typeIndex)
.MakeArrayType((type as Mono.Cecil.ArrayType).Rank);
} else if (type is GenericInstanceType) {
GenericInstanceType gType = (GenericInstanceType)type;
AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex);
foreach (var typeArgument in gType.GenericArguments) {
typeIndex++;
baseType.AddChild(ConvertType(typeArgument, typeAttributes, ref typeIndex), AstType.Roles.TypeArgument);
}
return baseType;
} else if (type is GenericParameter) {
return new SimpleType(type.Name);
} else if (type.IsNested) {
AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex);
string namepart = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name);
return new MemberType { Target = typeRef, MemberName = namepart }.WithAnnotation(type);
} else {
string ns = type.Namespace ?? string.Empty;
string name = type.Name;
if (name == null)
throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString());
if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) {
return new PrimitiveType("dynamic");
} else {
if (ns == "System") {
switch (name) {
case "SByte":
return new PrimitiveType("sbyte");
case "Int16":
return new PrimitiveType("short");
case "Int32":
return new PrimitiveType("int");
case "Int64":
return new PrimitiveType("long");
case "Byte":
return new PrimitiveType("byte");
case "UInt16":
return new PrimitiveType("ushort");
case "UInt32":
return new PrimitiveType("uint");
case "UInt64":
return new PrimitiveType("ulong");
case "String":
return new PrimitiveType("string");
case "Single":
return new PrimitiveType("float");
case "Double":
return new PrimitiveType("double");
case "Decimal":
return new PrimitiveType("decimal");
case "Char":
return new PrimitiveType("char");
case "Boolean":
return new PrimitiveType("bool");
case "Void":
return new PrimitiveType("void");
case "Object":
return new PrimitiveType("object");
}
}
name = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(name);
// TODO: Until we can simplify type with 'using', use just the name without namesapce
return new SimpleType(name).WithAnnotation(type);
// if (ns.Length == 0)
// return new SimpleType(name).WithAnnotation(type);
// string[] parts = ns.Split('.');
// AstType nsType = new SimpleType(parts[0]);
// for (int i = 1; i < parts.Length; i++) {
// nsType = new MemberType { Target = nsType, MemberName = parts[i] };
// }
// return new MemberType { Target = nsType, MemberName = name }.WithAnnotation(type);
}
}
}
const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute";
static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex)
{
if (attributeProvider == null || !attributeProvider.HasCustomAttributes)
return false;
foreach (CustomAttribute a in attributeProvider.CustomAttributes) {
if (a.Constructor.DeclaringType.FullName == DynamicAttributeFullName) {
if (a.ConstructorArguments.Count == 1) {
CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[];
if (values != null && typeIndex < values.Length && values[typeIndex].Value is bool)
return (bool)values[typeIndex].Value;
}
return true;
}
}
return false;
}
#endregion
#region ConvertModifiers
Modifiers ConvertModifiers(TypeDefinition typeDef)
{
Modifiers modifiers = Modifiers.None;
if (typeDef.IsNestedPrivate)
modifiers |= Modifiers.Private;
else if (typeDef.IsNestedAssembly || typeDef.IsNestedFamilyAndAssembly || typeDef.IsNotPublic)
modifiers |= Modifiers.Internal;
else if (typeDef.IsNestedFamily)
modifiers |= Modifiers.Protected;
else if (typeDef.IsNestedFamilyOrAssembly)
modifiers |= Modifiers.Protected | Modifiers.Internal;
else if (typeDef.IsPublic || typeDef.IsNestedPublic)
modifiers |= Modifiers.Public;
if (typeDef.IsAbstract && typeDef.IsSealed)
modifiers |= Modifiers.Static;
else if (typeDef.IsAbstract)
modifiers |= Modifiers.Abstract;
else if (typeDef.IsSealed)
modifiers |= Modifiers.Sealed;
return modifiers;
}
Modifiers ConvertModifiers(FieldDefinition fieldDef)
{
Modifiers modifiers = Modifiers.None;
if (fieldDef.IsPrivate)
modifiers |= Modifiers.Private;
else if (fieldDef.IsAssembly || fieldDef.IsFamilyAndAssembly)
modifiers |= Modifiers.Internal;
else if (fieldDef.IsFamily)
modifiers |= Modifiers.Protected;
else if (fieldDef.IsFamilyOrAssembly)
modifiers |= Modifiers.Protected | Modifiers.Internal;
else if (fieldDef.IsPublic)
modifiers |= Modifiers.Public;
if (fieldDef.IsLiteral) {
modifiers |= Modifiers.Const;
} else {
if (fieldDef.IsStatic)
modifiers |= Modifiers.Static;
if (fieldDef.IsInitOnly)
modifiers |= Modifiers.Readonly;
}
return modifiers;
}
Modifiers ConvertModifiers(MethodDefinition methodDef)
{
if (methodDef == null)
return Modifiers.None;
Modifiers modifiers = Modifiers.None;
if (methodDef.IsPrivate)
modifiers |= Modifiers.Private;
else if (methodDef.IsAssembly || methodDef.IsFamilyAndAssembly)
modifiers |= Modifiers.Internal;
else if (methodDef.IsFamily)
modifiers |= Modifiers.Protected;
else if (methodDef.IsFamilyOrAssembly)
modifiers |= Modifiers.Protected | Modifiers.Internal;
else if (methodDef.IsPublic)
modifiers |= Modifiers.Public;
if (methodDef.IsStatic)
modifiers |= Modifiers.Static;
if (methodDef.IsAbstract) {
modifiers |= Modifiers.Abstract;
if (!methodDef.IsNewSlot)
modifiers |= Modifiers.Override;
} else if (methodDef.IsFinal) {
if (!methodDef.IsNewSlot) {
modifiers |= Modifiers.Sealed | Modifiers.Override;
}
} else if (methodDef.IsVirtual) {
if (methodDef.IsNewSlot)
modifiers |= Modifiers.Virtual;
else
modifiers |= Modifiers.Override;
}
return modifiers;
}
#endregion
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef)
{
// Add fields
foreach(FieldDefinition fieldDef in typeDef.Fields) {
astType.AddChild(CreateField(fieldDef), TypeDeclaration.MemberRole);
}
// Add events
foreach(EventDefinition eventDef in typeDef.Events) {
astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole);
}
// Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) {
astType.AddChild(CreateProperty(propDef), TypeDeclaration.MemberRole);
}
// Add constructors
foreach(MethodDefinition methodDef in typeDef.Methods) {
if (!methodDef.IsConstructor) continue;
astType.AddChild(CreateConstructor(methodDef), TypeDeclaration.MemberRole);
}
// Add methods
foreach(MethodDefinition methodDef in typeDef.Methods) {
if (methodDef.IsSpecialName) continue;
astType.AddChild(CreateMethod(methodDef), TypeDeclaration.MemberRole);
}
}
MethodDeclaration CreateMethod(MethodDefinition methodDef)
{
MethodDeclaration astMethod = new MethodDeclaration();
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);
}
return astMethod;
}
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{
ConstructorDeclaration astMethod = new ConstructorDeclaration();
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);
return astMethod;
}
PropertyDeclaration CreateProperty(PropertyDefinition propDef)
{
PropertyDeclaration astProp = new PropertyDeclaration();
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)
};
}
if (propDef.SetMethod != null) {
astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod)
};
}
return astProp;
}
CustomEventDeclaration CreateEvent(EventDefinition eventDef)
{
CustomEventDeclaration astEvent = new CustomEventDeclaration();
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)
};
}
if (eventDef.RemoveMethod != null) {
astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod)
};
}
return astEvent;
}
FieldDeclaration CreateField(FieldDefinition fieldDef)
{
FieldDeclaration astField = new FieldDeclaration();
astField.AddChild(new VariableInitializer(fieldDef.Name), FieldDeclaration.Roles.Variable);
astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef);
astField.Modifiers = ConvertModifiers(fieldDef);
return astField;
}
public static IEnumerable<ParameterDeclaration> MakeParameters(IEnumerable<ParameterDefinition> paramCol)
{
foreach(ParameterDefinition paramDef in paramCol) {
ParameterDeclaration astParam = new ParameterDeclaration();
astParam.Type = ConvertType(paramDef.ParameterType, paramDef);
astParam.Name = paramDef.Name;
if (!paramDef.IsIn && paramDef.IsOut) astParam.ParameterModifier = ParameterModifier.Out;
if (paramDef.IsIn && paramDef.IsOut) astParam.ParameterModifier = ParameterModifier.Ref;
// TODO: params, this
yield return astParam;
}
}
}
}