Browse Source

Add idiom for System.Type.GetTypeFromHandle(typeof(...).TypeHandle); don't create body for abstract methods.

pull/10/head
Daniel Grunwald 15 years ago
parent
commit
336412fff9
  1. 60
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 18
      ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs
  3. 53
      ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs
  4. 21
      ILSpy/CSharpLanguage.cs

60
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -99,6 +99,21 @@ namespace Decompiler
astCompileUnit.AddChild(node, CompilationUnit.MemberRole); 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) public TypeDeclaration CreateType(TypeDefinition typeDef)
{ {
TypeDeclaration astType = new TypeDeclaration(); TypeDeclaration astType = new TypeDeclaration();
@ -111,6 +126,7 @@ namespace Decompiler
astType.ClassType = ClassType.Struct; astType.ClassType = ClassType.Struct;
} else if (typeDef.IsInterface) { } else if (typeDef.IsInterface) {
astType.ClassType = ClassType.Interface; astType.ClassType = ClassType.Interface;
astType.Modifiers &= ~Modifiers.Abstract;
} else { } else {
astType.ClassType = ClassType.Class; astType.ClassType = ClassType.Class;
} }
@ -143,10 +159,10 @@ namespace Decompiler
public static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes = null) public static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes = null)
{ {
int typeIndex = 0; int typeIndex = 0;
return CreateType(type, typeAttributes, ref typeIndex); return ConvertType(type, typeAttributes, ref typeIndex);
} }
static AstType CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex) static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex)
{ {
while (type is OptionalModifierType || type is RequiredModifierType) { while (type is OptionalModifierType || type is RequiredModifierType) {
type = ((TypeSpecification)type).ElementType; type = ((TypeSpecification)type).ElementType;
@ -158,27 +174,27 @@ namespace Decompiler
if (type is Mono.Cecil.ByReferenceType) { if (type is Mono.Cecil.ByReferenceType) {
typeIndex++; typeIndex++;
// ignore by reference type (cannot be represented in C#) // ignore by reference type (cannot be represented in C#)
return CreateType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex); return ConvertType((type as Mono.Cecil.ByReferenceType).ElementType, typeAttributes, ref typeIndex);
} else if (type is Mono.Cecil.PointerType) { } else if (type is Mono.Cecil.PointerType) {
typeIndex++; typeIndex++;
return CreateType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex) return ConvertType((type as Mono.Cecil.PointerType).ElementType, typeAttributes, ref typeIndex)
.MakePointerType(); .MakePointerType();
} else if (type is Mono.Cecil.ArrayType) { } else if (type is Mono.Cecil.ArrayType) {
typeIndex++; typeIndex++;
return CreateType((type as Mono.Cecil.ArrayType).ElementType, typeAttributes, ref typeIndex) return ConvertType((type as Mono.Cecil.ArrayType).ElementType, typeAttributes, ref typeIndex)
.MakeArrayType((type as Mono.Cecil.ArrayType).Rank); .MakeArrayType((type as Mono.Cecil.ArrayType).Rank);
} else if (type is GenericInstanceType) { } else if (type is GenericInstanceType) {
GenericInstanceType gType = (GenericInstanceType)type; GenericInstanceType gType = (GenericInstanceType)type;
AstType baseType = CreateType(gType.ElementType, typeAttributes, ref typeIndex); AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex);
foreach (var typeArgument in gType.GenericArguments) { foreach (var typeArgument in gType.GenericArguments) {
typeIndex++; typeIndex++;
baseType.AddChild(CreateType(typeArgument, typeAttributes, ref typeIndex), AstType.Roles.TypeArgument); baseType.AddChild(ConvertType(typeArgument, typeAttributes, ref typeIndex), AstType.Roles.TypeArgument);
} }
return baseType; return baseType;
} else if (type is GenericParameter) { } else if (type is GenericParameter) {
return new SimpleType(type.Name); return new SimpleType(type.Name);
} else if (type.IsNested) { } else if (type.IsNested) {
AstType typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex); AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex);
string namepart = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name); string namepart = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name);
return new MemberType { Target = typeRef, MemberName = namepart }.WithAnnotation(type); return new MemberType { Target = typeRef, MemberName = namepart }.WithAnnotation(type);
} else { } else {
@ -309,7 +325,7 @@ namespace Decompiler
modifiers |= Modifiers.Abstract; modifiers |= Modifiers.Abstract;
else if (methodDef.IsFinal) else if (methodDef.IsFinal)
modifiers |= Modifiers.Sealed; modifiers |= Modifiers.Sealed;
else if (methodDef.IsVirtual) else if (methodDef.IsVirtual && methodDef.IsNewSlot)
modifiers |= Modifiers.Virtual; modifiers |= Modifiers.Virtual;
return modifiers; return modifiers;
} }
@ -352,9 +368,11 @@ namespace Decompiler
MethodDeclaration astMethod = new MethodDeclaration(); MethodDeclaration astMethod = new MethodDeclaration();
astMethod.Name = methodDef.Name; astMethod.Name = methodDef.Name;
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType); astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Parameters = MakeParameters(methodDef.Parameters); astMethod.Parameters = MakeParameters(methodDef.Parameters);
astMethod.Body = AstMethodBodyBuilder.CreateMetodBody(methodDef); if (!methodDef.DeclaringType.IsInterface) {
astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef);
}
return astMethod; return astMethod;
} }
@ -363,7 +381,7 @@ namespace Decompiler
ConstructorDeclaration astMethod = new ConstructorDeclaration(); ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Parameters = MakeParameters(methodDef.Parameters); astMethod.Parameters = MakeParameters(methodDef.Parameters);
astMethod.Body = AstMethodBodyBuilder.CreateMetodBody(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef);
return astMethod; return astMethod;
} }
@ -375,23 +393,33 @@ namespace Decompiler
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
astProp.Getter = new Accessor { astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMetodBody(propDef.GetMethod) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod)
}; };
} }
if (propDef.SetMethod != null) { if (propDef.SetMethod != null) {
astProp.Setter = new Accessor { astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMetodBody(propDef.SetMethod) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod)
}; };
} }
return astProp; return astProp;
} }
EventDeclaration CreateEvent(EventDefinition eventDef) CustomEventDeclaration CreateEvent(EventDefinition eventDef)
{ {
EventDeclaration astEvent = new EventDeclaration(); CustomEventDeclaration astEvent = new CustomEventDeclaration();
astEvent.Name = eventDef.Name; astEvent.Name = eventDef.Name;
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef); astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); 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; return astEvent;
} }

18
ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs

@ -17,7 +17,7 @@ namespace Decompiler
static Dictionary<string, Cecil.TypeReference> localVarTypes = new Dictionary<string, Cecil.TypeReference>(); static Dictionary<string, Cecil.TypeReference> localVarTypes = new Dictionary<string, Cecil.TypeReference>();
static Dictionary<string, bool> localVarDefined = new Dictionary<string, bool>(); static Dictionary<string, bool> localVarDefined = new Dictionary<string, bool>();
public static BlockStatement CreateMetodBody(MethodDefinition methodDef) public static BlockStatement CreateMethodBody(MethodDefinition methodDef)
{ {
AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
builder.methodDef = methodDef; builder.methodDef = methodDef;
@ -53,7 +53,7 @@ namespace Decompiler
public BlockStatement CreateMethodBody() public BlockStatement CreateMethodBody()
{ {
if (methodDef.Body == null) return new Ast.BlockStatement(); if (methodDef.Body == null) return null;
List<ILNode> body = new ILAstBuilder().Build(methodDef, true); List<ILNode> body = new ILAstBuilder().Build(methodDef, true);
@ -122,7 +122,7 @@ namespace Decompiler
IEnumerable<Statement> TransformNode(Node node) IEnumerable<Statement> TransformNode(Node node)
{ {
if (Options.NodeComments) { if (Options.NodeComments) {
yield return new CommentStatement("// " + node.Description); yield return new CommentStatement(node.Description);
} }
yield return new Ast.LabelStatement { Label = node.Label }; yield return new Ast.LabelStatement { Label = node.Label };
@ -547,7 +547,7 @@ namespace Decompiler
// TODO: Constructors are ignored // TODO: Constructors are ignored
if (cecilMethod.Name == ".ctor") { if (cecilMethod.Name == ".ctor") {
return new CommentStatement("// Constructor"); return new CommentStatement("Constructor");
} }
// TODO: Hack, detect properties properly // TODO: Hack, detect properties properly
@ -602,14 +602,16 @@ namespace Decompiler
case Code.Ldc_R8: case Code.Ldc_R8:
return new Ast.PrimitiveExpression(operand); return new Ast.PrimitiveExpression(operand);
case Code.Ldfld: case Code.Ldfld:
return arg1.Member(((FieldReference) operand).Name); return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand);
case Code.Ldsfld: case Code.Ldsfld:
return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType).Member(((FieldReference)operand).Name); return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand);
case Code.Stfld: case Code.Stfld:
return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name), arg2); return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2);
case Code.Stsfld: case Code.Stsfld:
return new AssignmentExpression( return new AssignmentExpression(
AstBuilder.ConvertType(((FieldReference)operand).DeclaringType).Member(((FieldReference)operand).Name), AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
.Member(((FieldReference)operand).Name).WithAnnotation(operand),
arg2); arg2);
case Code.Ldflda: case Code.Ldflda:
case Code.Ldsflda: throw new NotImplementedException(); case Code.Ldsflda: throw new NotImplementedException();

53
ICSharpCode.Decompiler/Ast/Transforms/Idioms.cs

@ -14,36 +14,49 @@ namespace Decompiler.Transforms.Ast
base.VisitInvocationExpression(invocationExpression, data); base.VisitInvocationExpression(invocationExpression, data);
MethodReference methodRef = invocationExpression.Annotation<MethodReference>(); MethodReference methodRef = invocationExpression.Annotation<MethodReference>();
if (methodRef == null)
return null;
var arguments = invocationExpression.Arguments.ToArray();
// Reduce "String.Concat(a, b)" to "a + b" // Reduce "String.Concat(a, b)" to "a + b"
if (methodRef != null && methodRef.FullName == "System.String.Concat" if (methodRef != null && methodRef.Name == "Concat" && methodRef.DeclaringType.FullName == "System.String" && arguments.Length >= 2)
&& invocationExpression.Arguments.Count() >= 2)
{ {
var arguments = invocationExpression.Arguments.ToArray();
invocationExpression.Arguments = null; // detach arguments from invocationExpression invocationExpression.Arguments = null; // detach arguments from invocationExpression
Expression expr = arguments[0]; Expression expr = arguments[0];
for (int i = 1; i < arguments.Length; i++) { for (int i = 1; i < arguments.Length; i++) {
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]); expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]);
} }
invocationExpression.ReplaceWith(expr); invocationExpression.ReplaceWith(expr);
return null;
} }
if (methodRef != null) { switch (methodRef.FullName) {
BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(methodRef.Name); case "System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)":
if (bop != null && invocationExpression.Arguments.Count() == 2) { if (arguments.Length == 1) {
var arguments = invocationExpression.Arguments.ToArray(); MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression;
invocationExpression.Arguments = null; // detach arguments from invocationExpression if (mre != null && mre.Target is TypeOfExpression && mre.MemberName == "TypeHandle") {
invocationExpression.ReplaceWith( invocationExpression.ReplaceWith(mre.Target);
new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef) return null;
); }
} }
UnaryOperatorType? uop = GetUnaryOperatorTypeFromMetadataName(methodRef.Name); break;
if (uop != null && invocationExpression.Arguments.Count() == 1) { }
var arg = invocationExpression.Arguments.Single();
arg.Remove(); // detach argument BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(methodRef.Name);
invocationExpression.ReplaceWith( if (bop != null && arguments.Length == 2) {
new UnaryOperatorExpression(uop.Value, arg).WithAnnotation(methodRef) invocationExpression.Arguments = null; // detach arguments from invocationExpression
); invocationExpression.ReplaceWith(
} new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef)
);
return null;
}
UnaryOperatorType? uop = GetUnaryOperatorTypeFromMetadataName(methodRef.Name);
if (uop != null && arguments.Length == 1) {
arguments[0].Remove(); // detach argument
invocationExpression.ReplaceWith(
new UnaryOperatorExpression(uop.Value, arguments[0]).WithAnnotation(methodRef)
);
return null;
} }
return null; return null;

21
ILSpy/CSharpLanguage.cs

@ -43,6 +43,27 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
} }
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = new AstBuilder();
codeDomBuilder.AddProperty(property);
codeDomBuilder.GenerateCode(output);
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = new AstBuilder();
codeDomBuilder.AddField(field);
codeDomBuilder.GenerateCode(output);
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = new AstBuilder();
codeDomBuilder.AddEvent(ev);
codeDomBuilder.GenerateCode(output);
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = new AstBuilder();

Loading…
Cancel
Save