Browse Source

Set correct InferredType after decompiling operators with nullable values (needed for LogicNot simplification).

pull/205/head
Pent Ploompuu 15 years ago
parent
commit
007549180d
  1. 109
      ICSharpCode.Decompiler/ILAst/NullableOperators.cs

109
ICSharpCode.Decompiler/ILAst/NullableOperators.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
bool SimplifyNullableOperators(List<ILNode> body, ILExpression expr, int pos) bool SimplifyNullableOperators(List<ILNode> body, ILExpression expr, int pos)
{ {
if (!SimplifyNullableOperators(expr)) return false; if (!new PatternMatcher(typeSystem).SimplifyNullableOperators(expr)) return false;
var inlining = new ILInlining(method); var inlining = new ILInlining(method);
while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ; while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ;
@ -36,18 +36,24 @@ namespace ICSharpCode.Decompiler.ILAst
return true; return true;
} }
static bool SimplifyNullableOperators(ILExpression expr) sealed class PatternMatcher
{ {
if (PatternMatcher.Simplify(expr)) return true; readonly TypeSystem typeSystem;
public PatternMatcher(TypeSystem typeSystem)
{
this.typeSystem = typeSystem;
}
bool modified = false; public bool SimplifyNullableOperators(ILExpression expr)
foreach (var a in expr.Arguments) {
modified |= SimplifyNullableOperators(a); if (Simplify(expr)) return true;
return modified;
} bool modified = false;
foreach (var a in expr.Arguments)
modified |= SimplifyNullableOperators(a);
return modified;
}
struct PatternMatcher
{
abstract class Pattern abstract class Pattern
{ {
public readonly Pattern[] Arguments; public readonly Pattern[] Arguments;
@ -57,15 +63,15 @@ namespace ICSharpCode.Decompiler.ILAst
this.Arguments = arguments; this.Arguments = arguments;
} }
public virtual bool Match(ref PatternMatcher pm, ILExpression e) public virtual bool Match(PatternMatcher pm, ILExpression e)
{ {
if (e.Arguments.Count != this.Arguments.Length || e.Prefixes != null) return false; if (e.Arguments.Count != this.Arguments.Length || e.Prefixes != null) return false;
for (int i = 0; i < this.Arguments.Length; i++) for (int i = 0; i < this.Arguments.Length; i++)
if (!this.Arguments[i].Match(ref pm, e.Arguments[i])) return false; if (!this.Arguments[i].Match(pm, e.Arguments[i])) return false;
return true; return true;
} }
public virtual ILExpression BuildNew(ref PatternMatcher pm) public virtual ILExpression BuildNew(PatternMatcher pm)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
@ -96,16 +102,26 @@ namespace ICSharpCode.Decompiler.ILAst
this.code = code; this.code = code;
} }
public override bool Match(ref PatternMatcher pm, ILExpression e) public override bool Match(PatternMatcher pm, ILExpression e)
{ {
return e.Code == this.code && base.Match(ref pm, e); return e.Code == this.code && base.Match(pm, e);
} }
public override ILExpression BuildNew(ref PatternMatcher pm) public override ILExpression BuildNew(PatternMatcher pm)
{ {
var args = new ILExpression[this.Arguments.Length]; var args = new ILExpression[this.Arguments.Length];
for (int i = 0; i < args.Length; i++) args[i] = this.Arguments[i].BuildNew(ref pm); for (int i = 0; i < args.Length; i++) args[i] = this.Arguments[i].BuildNew(pm);
return new ILExpression(code, null, args); TypeReference t = null;
switch (code) {
case ILCode.Ceq:
case ILCode.Cne:
t = pm.typeSystem.Boolean;
break;
case ILCode.NullCoalescing:
t = args[1].InferredType;
break;
}
return new ILExpression(code, null, args) { InferredType = t };
} }
} }
@ -121,13 +137,13 @@ namespace ICSharpCode.Decompiler.ILAst
this.method = method; this.method = method;
} }
public override bool Match(ref PatternMatcher pm, ILExpression e) public override bool Match(PatternMatcher pm, ILExpression e)
{ {
if (e.Code != this.code) return false; if (e.Code != this.code) return false;
var m = e.Operand as MethodReference; var m = e.Operand as MethodReference;
if (m == null || m.Name != this.method) return false; if (m == null || m.Name != this.method) return false;
var t = m.DeclaringType; var t = m.DeclaringType;
return t.Name == "Nullable`1" && t.Namespace == "System" && base.Match(ref pm, e); return t.Name == "Nullable`1" && t.Namespace == "System" && base.Match(pm, e);
} }
} }
@ -150,7 +166,7 @@ namespace ICSharpCode.Decompiler.ILAst
this.simple = simple; this.simple = simple;
} }
public override bool Match(ref PatternMatcher pm, ILExpression e) public override bool Match(PatternMatcher pm, ILExpression e)
{ {
switch (e.Code) { switch (e.Code) {
case ILCode.Ceq: case ILCode.Ceq:
@ -203,14 +219,14 @@ namespace ICSharpCode.Decompiler.ILAst
pm.Operator = e; pm.Operator = e;
var a0 = e.Arguments[0]; var a0 = e.Arguments[0];
if (!simple) return VariableAGetValueOrDefault.Match(ref pm, a0) && VariableBGetValueOrDefault.Match(ref pm, e.Arguments[1]); if (!simple) return VariableAGetValueOrDefault.Match(pm, a0) && VariableBGetValueOrDefault.Match(pm, e.Arguments[1]);
if (e.Arguments.Count == 1) return VariableAGetValueOrDefault.Match(ref pm, a0); if (e.Arguments.Count == 1) return VariableAGetValueOrDefault.Match(pm, a0);
if (VariableAGetValueOrDefault.Match(ref pm, a0)) { if (VariableAGetValueOrDefault.Match(pm, a0)) {
pm.SimpleOperand = e.Arguments[1]; pm.SimpleOperand = e.Arguments[1];
pm.SimpleLeftOperand = false; pm.SimpleLeftOperand = false;
return true; return true;
} }
if (VariableAGetValueOrDefault.Match(ref pm, e.Arguments[1])) { if (VariableAGetValueOrDefault.Match(pm, e.Arguments[1])) {
pm.SimpleOperand = a0; pm.SimpleOperand = a0;
pm.SimpleLeftOperand = true; pm.SimpleLeftOperand = true;
return true; return true;
@ -249,13 +265,13 @@ namespace ICSharpCode.Decompiler.ILAst
} }
} }
public override ILExpression BuildNew(ref PatternMatcher pm) public override ILExpression BuildNew(PatternMatcher pm)
{ {
var res = pm.Operator; var res = pm.Operator;
res.Arguments.Clear(); res.Arguments.Clear();
if (pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand); if (pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand);
res.Arguments.Add(VariableA.BuildNew(ref pm)); res.Arguments.Add(VariableA.BuildNew(pm));
if (pm.B != null) res.Arguments.Add(VariableB.BuildNew(ref pm)); if (pm.B != null) res.Arguments.Add(VariableB.BuildNew(pm));
else if (pm.SimpleOperand != null && !pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand); else if (pm.SimpleOperand != null && !pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand);
return res; return res;
} }
@ -265,14 +281,14 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
public AnyPattern() : base(null) { } public AnyPattern() : base(null) { }
public override bool Match(ref PatternMatcher pm, ILExpression e) public override bool Match(PatternMatcher pm, ILExpression e)
{ {
if (pm.SimpleOperand != null) throw new InvalidOperationException(); if (pm.SimpleOperand != null) throw new InvalidOperationException();
pm.SimpleOperand = e; pm.SimpleOperand = e;
return true; return true;
} }
public override ILExpression BuildNew(ref PatternMatcher pm) public override ILExpression BuildNew(PatternMatcher pm)
{ {
return pm.SimpleOperand; return pm.SimpleOperand;
} }
@ -290,7 +306,7 @@ namespace ICSharpCode.Decompiler.ILAst
this.b = b; this.b = b;
} }
public override bool Match(ref PatternMatcher pm, ILExpression e) public override bool Match(PatternMatcher pm, ILExpression e)
{ {
if (e.Code != this.code) return false; if (e.Code != this.code) return false;
var v = e.Operand as ILVariable; var v = e.Operand as ILVariable;
@ -305,7 +321,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
static readonly ILExpression[] EmptyArguments = new ILExpression[0]; static readonly ILExpression[] EmptyArguments = new ILExpression[0];
public override ILExpression BuildNew(ref PatternMatcher pm) public override ILExpression BuildNew(PatternMatcher pm)
{ {
var v = this.b ? pm.B : pm.A; var v = this.b ? pm.B : pm.A;
var e = new ILExpression(ILCode.Ldloc, v, EmptyArguments); var e = new ILExpression(ILCode.Ldloc, v, EmptyArguments);
@ -323,15 +339,15 @@ namespace ICSharpCode.Decompiler.ILAst
this.value = Convert.ToInt32(value); this.value = Convert.ToInt32(value);
} }
public override bool Match(ref PatternMatcher pm, ILExpression e) public override bool Match(PatternMatcher pm, ILExpression e)
{ {
return e.Code == ILCode.Ldc_I4 && TypeAnalysis.IsBoolean(e.InferredType) && object.Equals(e.Operand, value); return e.Code == ILCode.Ldc_I4 && TypeAnalysis.IsBoolean(e.InferredType) && object.Equals(e.Operand, value);
} }
public override ILExpression BuildNew(ref PatternMatcher pm) public override ILExpression BuildNew(PatternMatcher pm)
{ {
// boolean constants are wrapped inside a container to disable simplyfication of equality comparisons // 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] }); return new ILExpression(ILCode.Wrap, null, new ILExpression(ILCode.Ldc_I4, value));
} }
} }
@ -433,16 +449,25 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression Operator, SimpleOperand; ILExpression Operator, SimpleOperand;
bool SimpleLeftOperand; bool SimpleLeftOperand;
public static bool Simplify(ILExpression expr) void Reset()
{
this.A = null;
this.B = null;
this.Operator = null;
this.SimpleOperand = null;
this.SimpleLeftOperand = false;
}
bool Simplify(ILExpression expr)
{ {
if (expr.Code == ILCode.TernaryOp || expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) { if (expr.Code == ILCode.TernaryOp || expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) {
Pattern[] ps; Pattern[] ps;
if (expr.Code != ILCode.TernaryOp) { if (expr.Code != ILCode.TernaryOp) {
ps = Comparisons; ps = Comparisons;
for (int i = 0; i < ps.Length; i++) { for (int i = 0; i < ps.Length; i++) {
var pm = new PatternMatcher(); this.Reset();
if (!ps[i].Match(ref pm, expr)) continue; if (!ps[i].Match(this, expr)) continue;
var n = OperatorVariableAB.BuildNew(ref pm); var n = OperatorVariableAB.BuildNew(this);
n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges)); n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges));
// the new expression is wrapped in a container so that negations aren't pushed through the comparison operation // the new expression is wrapped in a container so that negations aren't pushed through the comparison operation
expr.Code = ILCode.Wrap; expr.Code = ILCode.Wrap;
@ -456,9 +481,9 @@ namespace ICSharpCode.Decompiler.ILAst
} }
ps = Other; ps = Other;
for (int i = 0; i < ps.Length; i += 2) { for (int i = 0; i < ps.Length; i += 2) {
var pm = new PatternMatcher(); this.Reset();
if (!ps[i].Match(ref pm, expr)) continue; if (!ps[i].Match(this, expr)) continue;
var n = (ps[i + 1] ?? OperatorVariableAB).BuildNew(ref pm); var n = (ps[i + 1] ?? OperatorVariableAB).BuildNew(this);
n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges)); n.ILRanges = ILRange.OrderAndJoint(expr.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(el => el.ILRanges));
// the new expression is wrapped in a container so that negations aren't pushed through the comparison operation // the new expression is wrapped in a container so that negations aren't pushed through the comparison operation
expr.Code = ILCode.Wrap; expr.Code = ILCode.Wrap;

Loading…
Cancel
Save