|
|
@ -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; |
|
|
|