Browse Source

Improve decompilation of operations with nullable booleans.

pull/205/head
Pent Ploompuu 15 years ago
parent
commit
0abae7a2ad
  1. 71
      ICSharpCode.Decompiler/ILAst/NullableOperators.cs

71
ICSharpCode.Decompiler/ILAst/NullableOperators.cs

@ -314,21 +314,24 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
sealed class PrimitivePattern : Pattern sealed class BooleanPattern : Pattern
{ {
readonly ILCode code; readonly object value;
readonly object operand; public BooleanPattern(bool value)
public PrimitivePattern(ILCode code, object operand)
: base(null) : base(null)
{ {
this.code = code; this.value = Convert.ToInt32(value);
this.operand = operand;
} }
public override bool Match(ref PatternMatcher pm, ILExpression e) public override bool Match(ref PatternMatcher pm, ILExpression e)
{ {
return e.Code == code && object.Equals(e.Operand, this.operand); return e.Code == ILCode.Ldc_I4 && TypeAnalysis.IsBoolean(e.InferredType) && object.Equals(e.Operand, value);
}
public override ILExpression BuildNew(ref PatternMatcher pm)
{
// boolean constants are wrapped inside a container to disable simplyfication of equality comparisons
return new ILExpression(ILCode.Wrap, null, new ILExpression(ILCode.Ldc_I4, value) { InferredType = ((GenericInstanceType)pm.A.Type).GenericArguments[0] });
} }
} }
@ -401,11 +404,23 @@ namespace ICSharpCode.Decompiler.ILAst
/* only one operand nullable */ /* only one operand nullable */
// & (bool) // & (bool)
new ILPattern(ILCode.TernaryOp, Any, VariableA, new MethodPattern(ILCode.Newobj, ".ctor", new PrimitivePattern(ILCode.Ldc_I4, 0))), new ILPattern(ILCode.TernaryOp, Any, VariableA, new MethodPattern(ILCode.Newobj, ".ctor", new BooleanPattern(false))),
new ILPattern(ILCode.And, VariableA, Any), new ILPattern(ILCode.And, VariableA, Any),
// | (bool) // | (bool)
new ILPattern(ILCode.TernaryOp, Any, new MethodPattern(ILCode.Newobj, ".ctor", new PrimitivePattern(ILCode.Ldc_I4, 1)), VariableA), new ILPattern(ILCode.TernaryOp, Any, new MethodPattern(ILCode.Newobj, ".ctor", new BooleanPattern(true)), VariableA),
new ILPattern(ILCode.Or, VariableA, Any), new ILPattern(ILCode.Or, VariableA, Any),
// == true
VariableAGetValueOrDefault & VariableAHasValue,
new ILPattern(ILCode.Ceq, VariableA, new BooleanPattern(true)),
// != true
!VariableAGetValueOrDefault | !VariableAHasValue,
new ILPattern(ILCode.Cne, VariableA, new BooleanPattern(true)),
// == false
!VariableAGetValueOrDefault & VariableAHasValue,
new ILPattern(ILCode.Ceq, VariableA, new BooleanPattern(false)),
// != false
VariableAGetValueOrDefault | !VariableAHasValue,
new ILPattern(ILCode.Cne, VariableA, new BooleanPattern(false)),
// null coalescing // null coalescing
new ILPattern(ILCode.TernaryOp, VariableAHasValue, VariableAGetValueOrDefault, Any), new ILPattern(ILCode.TernaryOp, VariableAHasValue, VariableAGetValueOrDefault, Any),
new ILPattern(ILCode.NullCoalescing, VariableA, Any), new ILPattern(ILCode.NullCoalescing, VariableA, Any),
@ -420,24 +435,26 @@ namespace ICSharpCode.Decompiler.ILAst
public static bool Simplify(ILExpression expr) public static bool Simplify(ILExpression expr)
{ {
if (expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) { if (expr.Code == ILCode.TernaryOp || expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) {
var ps = Comparisons; Pattern[] ps;
for (int i = 0; i < ps.Length; i++) { if (expr.Code != ILCode.TernaryOp) {
var pm = new PatternMatcher(); ps = Comparisons;
if (!ps[i].Match(ref pm, expr)) continue; for (int i = 0; i < ps.Length; i++) {
var n = OperatorVariableAB.BuildNew(ref pm); var pm = new PatternMatcher();
n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges)); if (!ps[i].Match(ref pm, expr)) continue;
// the new expression is wrapped in a container so that negations aren't pushed through the comparison operation var n = OperatorVariableAB.BuildNew(ref pm);
expr.Code = ILCode.Wrap; n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges));
expr.Operand = null; // the new expression is wrapped in a container so that negations aren't pushed through the comparison operation
expr.Arguments.Clear(); expr.Code = ILCode.Wrap;
expr.Arguments.Add(n); expr.Operand = null;
expr.ILRanges.Clear(); expr.Arguments.Clear();
expr.InferredType = n.InferredType; expr.Arguments.Add(n);
return true; expr.ILRanges.Clear();
expr.InferredType = n.InferredType;
return true;
}
} }
} else if (expr.Code == ILCode.TernaryOp) { ps = Other;
var ps = Other;
for (int i = 0; i < ps.Length; i += 2) { for (int i = 0; i < ps.Length; i += 2) {
var pm = new PatternMatcher(); var pm = new PatternMatcher();
if (!ps[i].Match(ref pm, expr)) continue; if (!ps[i].Match(ref pm, expr)) continue;

Loading…
Cancel
Save