Browse Source

Adjust NullableLiftingTransform to match new patterns due to RemoveInfeasiblePathTransform.

pull/2461/head
Siegfried Pammer 4 years ago
parent
commit
e50d221e06
  1. 2
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.cs
  3. 122
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

2
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -308,6 +308,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -308,6 +308,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
if (flags.HasFlag(CompilerOptions.UseRoslyn2_10_0)
|| flags.HasFlag(CompilerOptions.UseRoslynLatest))
{
preprocessorSymbols.Add("ROSLYN2");
preprocessorSymbols.Add("CS70");
preprocessorSymbols.Add("CS71");
preprocessorSymbols.Add("CS72");
@ -315,6 +316,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -315,6 +316,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
if (flags.HasFlag(CompilerOptions.UseRoslynLatest))
{
preprocessorSymbols.Add("ROSLYN3");
preprocessorSymbols.Add("CS73");
preprocessorSymbols.Add("CS80");
preprocessorSymbols.Add("VB16");

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.cs

@ -367,7 +367,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -367,7 +367,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
Console.WriteLine();
}
#if ROSLYN
#if ROSLYN2
// Roslyn 2.9 started invoking op_Equality even if the source code says 'a != b'
if (!(a == b))
{

122
ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

@ -137,6 +137,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -137,6 +137,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return false;
}
bool AnalyzeNegatedCondition(ILInstruction condition)
{
return condition.MatchLogicNot(out var arg) && AnalyzeCondition(arg);
}
#endregion
#region Main lifting logic
@ -211,11 +216,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -211,11 +216,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// => comp.lifted[C#](lhs, rhs)
return LiftCSharpComparison(comp, comp.Kind);
}
else if (trueInst.MatchLdcI4(0) && AnalyzeCondition(falseInst))
if (trueInst.MatchLdcI4(0) && AnalyzeCondition(falseInst))
{
// comp(lhs, rhs) ? false : (v1 != null && ... && vn != null)
return LiftCSharpComparison(comp, comp.Kind.Negate());
}
if (falseInst.MatchLdcI4(1) && AnalyzeNegatedCondition(trueInst))
{
// comp(lhs, rhs) ? !(v1 != null && ... && vn != null) : true
// => !comp.lifted[C#](lhs, rhs)
ILInstruction result = LiftCSharpComparison(comp, comp.Kind);
if (result == null)
return result;
return Comp.LogicNot(result);
}
if (trueInst.MatchLdcI4(1) && AnalyzeNegatedCondition(falseInst))
{
// comp(lhs, rhs) ? true : !(v1 != null && ... && vn != null)
ILInstruction result = LiftCSharpComparison(comp, comp.Kind.Negate());
if (result == null)
return result;
return Comp.LogicNot(result);
}
}
}
ILVariable v;
@ -544,7 +566,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -544,7 +566,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null;
}
Call LiftCSharpUserEqualityComparison(CompOrDecimal hasValueComp, ComparisonKind newComparisonKind, ILInstruction nestedIfInst)
ILInstruction LiftCSharpUserEqualityComparison(CompOrDecimal hasValueComp, ComparisonKind newComparisonKind, ILInstruction nestedIfInst)
{
// User-defined equality operator:
// if (comp(call get_HasValue(ldloca nullable1) == call get_HasValue(ldloca nullable2)))
@ -576,11 +598,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -576,11 +598,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null;
if (!falseInst.MatchLdcI4(newComparisonKind == ComparisonKind.Equality ? 1 : 0))
return null;
bool trueInstNegated = false;
while (trueInst.MatchLogicNot(out var arg))
{
trueInstNegated = !trueInstNegated;
trueInst = arg;
}
if (!(trueInst is Call call))
return null;
if (!(call.Method.IsOperator && call.Arguments.Count == 2))
return null;
if (call.Method.Name != (newComparisonKind == ComparisonKind.Equality ? "op_Equality" : "op_Inequality"))
bool expectEqualityOperator = (newComparisonKind == ComparisonKind.Equality) ^ trueInstNegated;
if (call.Method.Name != (expectEqualityOperator ? "op_Equality" : "op_Inequality"))
return null;
var liftedOperator = CSharp.Resolver.CSharpOperators.LiftUserDefinedOperator(call.Method);
if (liftedOperator == null)
@ -594,13 +623,66 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -594,13 +623,66 @@ namespace ICSharpCode.Decompiler.IL.Transforms
)
{
context.Step("NullableLiftingTransform: C# user-defined (in)equality comparison", nestedIfInst);
return new Call(liftedOperator) {
ILInstruction replacement = new Call(liftedOperator) {
Arguments = { left, right },
ConstrainedTo = call.ConstrainedTo,
ILStackWasEmpty = call.ILStackWasEmpty,
IsTail = call.IsTail,
}.WithILRange(call);
if (trueInstNegated)
{
replacement = Comp.LogicNot(replacement);
}
return replacement;
}
return null;
}
ILInstruction LiftCSharpUserComparison(ILInstruction trueInst, ILInstruction falseInst)
{
// (v1 != null && ... && vn != null) ? trueInst : falseInst
bool trueInstNegated = false;
while (trueInst.MatchLogicNot(out var arg))
{
trueInstNegated = !trueInstNegated;
trueInst = arg;
}
if (trueInst is Call call && !call.IsLifted
&& CSharp.Resolver.CSharpOperators.IsComparisonOperator(call.Method)
&& falseInst.MatchLdcI4((call.Method.Name == "op_Inequality") ^ trueInstNegated ? 1 : 0))
{
// (v1 != null && ... && vn != null) ? call op_LessThan(lhs, rhs) : ldc.i4(0)
var liftedOperator = CSharp.Resolver.CSharpOperators.LiftUserDefinedOperator(call.Method);
if ((call.Method.Name == "op_Equality" || call.Method.Name == "op_Inequality") && nullableVars.Count != 1)
{
// Equality is special (returns true if both sides are null), only handle it
// in the normal code path if we're dealing with only a single nullable var
// (comparing nullable with non-nullable).
return null;
}
if (liftedOperator == null)
{
return null;
}
context.Step("Lift user-defined comparison operator", trueInst);
var (left, right, bits) = DoLiftBinary(call.Arguments[0], call.Arguments[1],
call.Method.Parameters[0].Type, call.Method.Parameters[1].Type);
if (left != null && right != null && bits.All(0, nullableVars.Count))
{
ILInstruction result = new Call(liftedOperator) {
Arguments = { left, right },
ConstrainedTo = call.ConstrainedTo,
ILStackWasEmpty = call.ILStackWasEmpty,
IsTail = call.IsTail
}.WithILRange(call);
if (trueInstNegated)
{
result = Comp.LogicNot(result);
}
return result;
}
}
return null;
}
#endregion
@ -641,35 +723,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -641,35 +723,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
UnderlyingResultType = NullableType.GetUnderlyingType(nullableVars[0].Type).GetStackType()
};
}
else if (trueInst is Call call && !call.IsLifted
&& CSharp.Resolver.CSharpOperators.IsComparisonOperator(call.Method)
&& falseInst.MatchLdcI4(call.Method.Name == "op_Inequality" ? 1 : 0))
{
// (v1 != null && ... && vn != null) ? call op_LessThan(lhs, rhs) : ldc.i4(0)
var liftedOperator = CSharp.Resolver.CSharpOperators.LiftUserDefinedOperator(call.Method);
if ((call.Method.Name == "op_Equality" || call.Method.Name == "op_Inequality") && nullableVars.Count != 1)
{
// Equality is special (returns true if both sides are null), only handle it
// in the normal code path if we're dealing with only a single nullable var
// (comparing nullable with non-nullable).
liftedOperator = null;
}
if (liftedOperator != null)
{
context.Step("Lift user-defined comparison operator", trueInst);
var (left, right, bits) = DoLiftBinary(call.Arguments[0], call.Arguments[1],
call.Method.Parameters[0].Type, call.Method.Parameters[1].Type);
if (left != null && right != null && bits.All(0, nullableVars.Count))
{
return new Call(liftedOperator) {
Arguments = { left, right },
ConstrainedTo = call.ConstrainedTo,
ILStackWasEmpty = call.ILStackWasEmpty,
IsTail = call.IsTail
}.WithILRange(call);
}
}
}
ILInstruction result = LiftCSharpUserComparison(trueInst, falseInst);
if (result != null)
return result;
}
ILInstruction lifted;
if (nullableVars.Count == 1 && MatchGetValueOrDefault(exprToLift, nullableVars[0]))

Loading…
Cancel
Save