Browse Source

Fixed enum boxing decompilation bug. Enum in attributes better printing.

pull/52/head
Artur Zgodziski 15 years ago
parent
commit
679d525806
  1. 71
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 38
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 9
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  4. 8
      ICSharpCode.Decompiler/Tests/CustomAttributes.cs

71
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -6,8 +6,10 @@ using System.Threading; @@ -6,8 +6,10 @@ using System.Threading;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Ast = ICSharpCode.NRefactory.CSharp;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
@ -583,7 +585,17 @@ namespace Decompiler @@ -583,7 +585,17 @@ namespace Decompiler
foreach (var parameter in customAttribute.ConstructorArguments)
{
attribute.Arguments.Add(new PrimitiveExpression(parameter.Value));
var isEnum = parameter.Type.IsValueType && !parameter.Type.IsPrimitive;
Expression parameterValue;
if (isEnum)
{
parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), parameter.Type);
}
else
{
parameterValue = new PrimitiveExpression(parameter.Value);
}
attribute.Arguments.Add(parameterValue);
}
}
@ -591,5 +603,62 @@ namespace Decompiler @@ -591,5 +603,62 @@ namespace Decompiler
attributedNode.Attributes.Add(section);
}
}
internal static Expression MakePrimitive(long val, TypeReference type)
{
if (TypeAnalysis.IsBoolean(type) && val == 0)
return new Ast.PrimitiveExpression(false);
else if (TypeAnalysis.IsBoolean(type) && val == 1)
return new Ast.PrimitiveExpression(true);
if (type != null)
{ // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs)
TypeDefinition enumDefinition = type.Resolve();
if (enumDefinition != null && enumDefinition.IsEnum)
{
foreach (FieldDefinition field in enumDefinition.Fields)
{
if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val))
return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
else if (!field.IsStatic && field.IsRuntimeSpecialName)
type = field.FieldType; // use primitive type of the enum
}
if (IsFlagsEnum(enumDefinition))
{
Expression expr = null;
foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic))
{
long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false);
if (fieldValue == 0)
continue; // skip None enum value
if ((fieldValue & val) == fieldValue)
{
var fieldExpression = AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
if (expr == null)
expr = fieldExpression;
else
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression);
}
}
if (expr != null)
return expr;
}
}
}
TypeCode code = TypeAnalysis.GetTypeCode(type);
if (code == TypeCode.Object)
return new Ast.PrimitiveExpression((int)val);
else
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
}
static bool IsFlagsEnum(TypeDefinition type)
{
if (!type.HasCustomAttributes)
return false;
return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute");
}
}
}

38
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -514,7 +514,7 @@ namespace Decompiler @@ -514,7 +514,7 @@ namespace Decompiler
return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand));
}
case Code.Ldc_I4:
return MakePrimitive((int)operand, byteCode.InferredType);
return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case Code.Ldc_I8:
case Code.Ldc_R4:
case Code.Ldc_R8:
@ -763,7 +763,7 @@ namespace Decompiler @@ -763,7 +763,7 @@ namespace Decompiler
if (TypeAnalysis.IsBoolean(actualType))
return expr;
if (actualIsIntegerOrEnum) {
return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, MakePrimitive(0, actualType));
return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, AstBuilder.MakePrimitive(0, actualType));
} else {
return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression());
}
@ -771,39 +771,21 @@ namespace Decompiler @@ -771,39 +771,21 @@ namespace Decompiler
if (TypeAnalysis.IsBoolean(actualType) && requiredIsIntegerOrEnum) {
return new ConditionalExpression {
Condition = expr,
TrueExpression = MakePrimitive(1, reqType),
FalseExpression = MakePrimitive(0, reqType)
TrueExpression = AstBuilder.MakePrimitive(1, reqType),
FalseExpression = AstBuilder.MakePrimitive(0, reqType)
};
}
if (expr is PrimitiveExpression && !requiredIsIntegerOrEnum && TypeAnalysis.IsEnum(actualType))
{
return expr.CastTo(AstBuilder.ConvertType(actualType));
}
if (actualIsIntegerOrEnum && requiredIsIntegerOrEnum) {
return expr.CastTo(AstBuilder.ConvertType(reqType));
}
return expr;
}
}
Expression MakePrimitive(long val, TypeReference type)
{
if (TypeAnalysis.IsBoolean(type) && val == 0)
return new Ast.PrimitiveExpression(false);
else if (TypeAnalysis.IsBoolean(type) && val == 1)
return new Ast.PrimitiveExpression(true);
if (type != null) { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs)
TypeDefinition enumDefinition = type.Resolve();
if (enumDefinition != null && enumDefinition.IsEnum) {
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val))
return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
else if (!field.IsStatic && field.IsRuntimeSpecialName)
type = field.FieldType; // use primitive type of the enum
}
}
}
TypeCode code = TypeAnalysis.GetTypeCode(type);
if (code == TypeCode.Object)
return new Ast.PrimitiveExpression((int)val);
else
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
}
}
}

9
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -627,6 +627,15 @@ namespace Decompiler @@ -627,6 +627,15 @@ namespace Decompiler
{
return IsSigned(type) != null;
}
public static bool IsEnum(TypeReference type)
{
if (type == null)
return false;
// unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec)
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
return typeDef != null && typeDef.IsEnum;
}
static bool? IsSigned(TypeReference type)
{

8
ICSharpCode.Decompiler/Tests/CustomAttributes.cs

@ -12,8 +12,16 @@ public static class CustomAtributes @@ -12,8 +12,16 @@ public static class CustomAtributes
// Item1,
Item2
}
[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : Attribute
{
}
[Obsolete("some message")]
public static void ObsoletedMethod()
{
//Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field));
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field);
AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field;
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets);
}
}

Loading…
Cancel
Save