Browse Source

Add support for negated enum constants (e.g. "v &= ~Enum.Flag;"). Closes #114.

pull/124/head
Daniel Grunwald 15 years ago
parent
commit
33a7120555
  1. 70
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 8
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 22
      ICSharpCode.Decompiler/Tests/IncrementDecrement.cs

70
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -742,11 +742,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -742,11 +742,11 @@ namespace ICSharpCode.Decompiler.Ast
if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null))
foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef))
if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) {
var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
break;
} else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot)
break;
var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod);
astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask));
break;
} else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot)
break;
if (accessor.IsVirtual ^ !accessor.IsNewSlot) {
if (TypesHierarchyHelpers.FindBaseProperties(propDef).Any())
astProp.Modifiers |= Modifiers.New;
@ -1229,27 +1229,40 @@ namespace ICSharpCode.Decompiler.Ast @@ -1229,27 +1229,40 @@ namespace ICSharpCode.Decompiler.Ast
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 (enumDefinition != null && enumDefinition.IsEnum) {
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val))
return 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))
{
TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type);
if (IsFlagsEnum(enumDefinition)) {
long enumValue = val;
Expression expr = null;
foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic))
{
long negatedEnumValue = ~val;
// limit negatedEnumValue to the appropriate range
switch (enumBaseTypeCode) {
case TypeCode.Byte:
case TypeCode.SByte:
negatedEnumValue &= byte.MaxValue;
break;
case TypeCode.Int16:
case TypeCode.UInt16:
negatedEnumValue &= ushort.MaxValue;
break;
case TypeCode.Int32:
case TypeCode.UInt32:
negatedEnumValue &= uint.MaxValue;
break;
}
Expression negatedExpr = 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 & enumValue) == fieldValue)
{
if ((fieldValue & enumValue) == fieldValue) {
var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
if (expr == null)
expr = fieldExpression;
@ -1257,22 +1270,33 @@ namespace ICSharpCode.Decompiler.Ast @@ -1257,22 +1270,33 @@ namespace ICSharpCode.Decompiler.Ast
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression);
enumValue &= ~fieldValue;
if (enumValue == 0)
break;
}
if ((fieldValue & negatedEnumValue) == fieldValue) {
var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field);
if (negatedExpr == null)
negatedExpr = fieldExpression;
else
negatedExpr = new BinaryOperatorExpression(negatedExpr, BinaryOperatorType.BitwiseOr, fieldExpression);
negatedEnumValue &= ~fieldValue;
}
}
if(enumValue == 0 && expr != null)
return expr;
if (enumValue == 0 && expr != null) {
if (!(negatedEnumValue == 0 && negatedExpr != null && negatedExpr.Descendants.Count() < expr.Descendants.Count())) {
return expr;
}
}
if (negatedEnumValue == 0 && negatedExpr != null) {
return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr);
}
}
TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type);
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(enumDefinition));
}
}
TypeCode code = TypeAnalysis.GetTypeCode(type);
if (code == TypeCode.Object || code == TypeCode.Empty)
return new Ast.PrimitiveExpression((int)val);
else
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
code = TypeCode.Int32;
return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false));
}
static bool IsFlagsEnum(TypeDefinition type)

8
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -160,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -160,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast
var tryCatchStmt = new Ast.TryCatchStatement();
tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock);
foreach (var catchClause in tryCatchNode.CatchBlocks) {
if (catchClause.ExceptionVariable == null
if (catchClause.ExceptionVariable == null
&& (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object))
{
tryCatchStmt.CatchClauses.Add(new Ast.CatchClause { Body = TransformBlock(catchClause) });
@ -509,8 +509,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -509,8 +509,10 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.DefaultValue:
return MakeDefaultValue((TypeReference)operand);
case ILCode.Jmp: return InlineAssembly(byteCode, args);
case ILCode.Ldc_I4: return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case ILCode.Ldc_I8: return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType);
case ILCode.Ldc_I4:
return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType);
case ILCode.Ldc_I8:
return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType);
case ILCode.Ldc_R4:
case ILCode.Ldc_R8:
case ILCode.Ldc_Decimal:

22
ICSharpCode.Decompiler/Tests/IncrementDecrement.cs

@ -5,11 +5,20 @@ using System; @@ -5,11 +5,20 @@ using System;
public class IncrementDecrement
{
[Flags]
private enum MyEnum
{
None = 0,
One = 1,
Two = 2,
Four = 4
}
public class MutableClass
{
public int Field;
public int Property
public int Property
{
get;
set;
@ -27,11 +36,12 @@ public class IncrementDecrement @@ -27,11 +36,12 @@ public class IncrementDecrement
}
}
MyEnum enumField;
public static int StaticField;
public static int StaticProperty
{
get;
{
get;
set;
}
@ -155,6 +165,12 @@ public class IncrementDecrement @@ -155,6 +165,12 @@ public class IncrementDecrement
return *ptr /= 1.5;
}
public void CompoundAssignEnum()
{
enumField |= IncrementDecrement.MyEnum.Two;
enumField &= ~IncrementDecrement.MyEnum.Four;
}
public int PostIncrementInAddition(int i, int j)
{
return i++ + j;

Loading…
Cancel
Save