Browse Source

Update to SRM 1.6.0 and Roslyn 2.9. Adjust decompiler to new code pattern used for lifted nullable comparisons.

pull/1305/head
Daniel Grunwald 7 years ago
parent
commit
ef866040b4
  1. 6
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 12
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.cs
  3. 6390
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.opt.roslyn.il
  4. 7088
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.roslyn.il
  5. 203
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  6. 201
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  7. 4
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  8. 16
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  9. 15
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  10. 3
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  11. 30
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
  12. 6
      ILSpy.Tests/ILSpy.Tests.csproj

6
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -37,10 +37,10 @@ @@ -37,10 +37,10 @@
<ItemGroup>
<PackageReference Include="DiffLib" Version="2017.7.26.1241" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.9.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="NUnit" Version="3.9.0" />
</ItemGroup>

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

@ -322,9 +322,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -322,9 +322,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
if (a == b) {
Console.WriteLine();
}
#if ROSLYN
// Roslyn 2.9 started invoking op_Equality even if the source code says 'a != b'
if (!(a == b)) {
Console.WriteLine();
}
#else
if (a != b) {
Console.WriteLine();
}
#endif
if (a > b) {
Console.WriteLine();
}
@ -399,7 +406,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -399,7 +406,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static void NumberValueBasic(decimal? a, decimal? b)
{
Console.WriteLine(a == b);
#if ROSLYN
// Roslyn 2.9 started invoking op_Equality even if the source code says 'a != b'
Console.WriteLine(!(a == b));
#else
Console.WriteLine(a != b);
#endif
Console.WriteLine(a > b);
Console.WriteLine(!(a > b));

6390
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.opt.roslyn.il

File diff suppressed because it is too large Load Diff

7088
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LiftedOperators.roslyn.il

File diff suppressed because it is too large Load Diff

203
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il

@ -2938,7 +2938,7 @@ @@ -2938,7 +2938,7 @@
NestedForeach(class [mscorlib]System.Collections.Generic.List`1<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> items2) cil managed
{
// Code size 150 (0x96)
// Code size 152 (0x98)
.maxstack 2
.locals init (object V_0,
bool V_1,
@ -2953,7 +2953,7 @@ @@ -2953,7 +2953,7 @@
IL_0008: stloc.3
.try
{
IL_0009: br.s IL_006b
IL_0009: br.s IL_006d
IL_000b: ldloca.s V_3
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::get_Current()
@ -3009,47 +3009,49 @@ @@ -3009,47 +3009,49 @@
IL_005c: ldloc.1
IL_005d: stloc.s V_5
IL_005f: ldloc.s V_5
IL_0061: brtrue.s IL_006a
IL_0061: brtrue.s IL_006c
IL_0063: ldloc.0
IL_0064: call void [mscorlib]System.Console::WriteLine(object)
IL_0069: nop
IL_0063: nop
IL_0064: ldloc.0
IL_0065: call void [mscorlib]System.Console::WriteLine(object)
IL_006a: nop
IL_006b: ldloca.s V_3
IL_006d: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::MoveNext()
IL_0072: stloc.s V_5
IL_0074: ldloc.s V_5
IL_0076: brtrue.s IL_000b
IL_006b: nop
IL_006c: nop
IL_006d: ldloca.s V_3
IL_006f: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::MoveNext()
IL_0074: stloc.s V_5
IL_0076: ldloc.s V_5
IL_0078: brtrue.s IL_000b
IL_0078: leave.s IL_0089
IL_007a: leave.s IL_008b
} // end .try
finally
{
IL_007a: ldloca.s V_3
IL_007c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>
IL_0082: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0087: nop
IL_0088: endfinally
IL_007c: ldloca.s V_3
IL_007e: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>
IL_0084: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0089: nop
IL_008a: endfinally
} // end handler
IL_0089: nop
IL_008a: ldstr "end"
IL_008f: call void [mscorlib]System.Console::WriteLine(string)
IL_0094: nop
IL_0095: ret
IL_008b: nop
IL_008c: ldstr "end"
IL_0091: call void [mscorlib]System.Console::WriteLine(string)
IL_0096: nop
IL_0097: ret
} // end of method Loops::NestedForeach
.method public hidebysig instance void
MergeAroundContinue() cil managed
{
// Code size 137 (0x89)
// Code size 140 (0x8c)
.maxstack 2
.locals init (int32 V_0,
bool V_1)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0074
IL_0003: br.s IL_0077
IL_0005: nop
IL_0006: ldloc.0
@ -3061,7 +3063,7 @@ @@ -3061,7 +3063,7 @@
IL_000d: ceq
IL_000f: stloc.1
IL_0010: ldloc.1
IL_0011: brtrue.s IL_0021
IL_0011: brtrue.s IL_0022
IL_0013: nop
IL_0014: ldloc.0
@ -3069,94 +3071,97 @@ @@ -3069,94 +3071,97 @@
IL_0016: ceq
IL_0018: stloc.1
IL_0019: ldloc.1
IL_001a: brtrue.s IL_001e
IL_001a: brtrue.s IL_001f
IL_001c: br.s IL_0070
IL_001c: nop
IL_001d: br.s IL_0073
IL_001e: nop
IL_001f: br.s IL_0068
IL_0021: ldloc.0
IL_0022: ldc.i4.5
IL_0023: rem
IL_0024: ldc.i4.0
IL_0025: ceq
IL_0027: ldc.i4.0
IL_0028: ceq
IL_002a: stloc.1
IL_002b: ldloc.1
IL_002c: brtrue.s IL_003c
IL_002e: nop
IL_002f: ldloc.0
IL_0030: ldc.i4.5
IL_0031: ceq
IL_0033: stloc.1
IL_0034: ldloc.1
IL_0035: brtrue.s IL_0039
IL_001f: nop
IL_0020: br.s IL_006b
IL_0022: ldloc.0
IL_0023: ldc.i4.5
IL_0024: rem
IL_0025: ldc.i4.0
IL_0026: ceq
IL_0028: ldc.i4.0
IL_0029: ceq
IL_002b: stloc.1
IL_002c: ldloc.1
IL_002d: brtrue.s IL_003e
IL_0037: br.s IL_0070
IL_002f: nop
IL_0030: ldloc.0
IL_0031: ldc.i4.5
IL_0032: ceq
IL_0034: stloc.1
IL_0035: ldloc.1
IL_0036: brtrue.s IL_003b
IL_0039: nop
IL_003a: br.s IL_0068
IL_0038: nop
IL_0039: br.s IL_0073
IL_003c: ldloc.0
IL_003d: ldc.i4.7
IL_003e: rem
IL_003f: ldc.i4.0
IL_0040: ceq
IL_0042: ldc.i4.0
IL_0043: ceq
IL_0045: stloc.1
IL_0046: ldloc.1
IL_0047: brtrue.s IL_0057
IL_003b: nop
IL_003c: br.s IL_006b
IL_0049: nop
IL_004a: ldloc.0
IL_004b: ldc.i4.7
IL_004c: ceq
IL_004e: stloc.1
IL_004f: ldloc.1
IL_0050: brtrue.s IL_0054
IL_003e: ldloc.0
IL_003f: ldc.i4.7
IL_0040: rem
IL_0041: ldc.i4.0
IL_0042: ceq
IL_0044: ldc.i4.0
IL_0045: ceq
IL_0047: stloc.1
IL_0048: ldloc.1
IL_0049: brtrue.s IL_005a
IL_0052: br.s IL_0070
IL_004b: nop
IL_004c: ldloc.0
IL_004d: ldc.i4.7
IL_004e: ceq
IL_0050: stloc.1
IL_0051: ldloc.1
IL_0052: brtrue.s IL_0057
IL_0054: nop
IL_0055: br.s IL_0068
IL_0055: br.s IL_0073
IL_0057: nop
IL_0058: br.s IL_006b
IL_0057: ldloc.0
IL_0058: ldc.i4.s 11
IL_005a: rem
IL_005b: ldc.i4.0
IL_005c: ceq
IL_005a: ldloc.0
IL_005b: ldc.i4.s 11
IL_005d: rem
IL_005e: ldc.i4.0
IL_005f: ceq
IL_0061: stloc.1
IL_0062: ldloc.1
IL_0063: brtrue.s IL_0068
IL_0061: ldc.i4.0
IL_0062: ceq
IL_0064: stloc.1
IL_0065: ldloc.1
IL_0066: brtrue.s IL_006b
IL_0065: nop
IL_0066: br.s IL_0070
IL_0068: nop
IL_0069: br.s IL_0073
IL_0068: ldloc.0
IL_0069: call void [mscorlib]System.Console::WriteLine(int32)
IL_006e: nop
IL_006f: nop
IL_0070: ldloc.0
IL_0071: ldc.i4.1
IL_0072: add
IL_0073: stloc.0
IL_0074: ldloc.0
IL_0075: ldc.i4.s 20
IL_0077: clt
IL_0079: stloc.1
IL_007a: ldloc.1
IL_007b: brtrue.s IL_0005
IL_007d: ldstr "end"
IL_0082: call void [mscorlib]System.Console::WriteLine(string)
IL_0087: nop
IL_0088: ret
IL_006b: ldloc.0
IL_006c: call void [mscorlib]System.Console::WriteLine(int32)
IL_0071: nop
IL_0072: nop
IL_0073: ldloc.0
IL_0074: ldc.i4.1
IL_0075: add
IL_0076: stloc.0
IL_0077: ldloc.0
IL_0078: ldc.i4.s 20
IL_007a: clt
IL_007c: stloc.1
IL_007d: ldloc.1
IL_007e: brtrue.s IL_0005
IL_0080: ldstr "end"
IL_0085: call void [mscorlib]System.Console::WriteLine(string)
IL_008a: nop
IL_008b: ret
} // end of method Loops::MergeAroundContinue
.method public hidebysig specialname rtspecialname

201
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il

@ -2756,7 +2756,7 @@ @@ -2756,7 +2756,7 @@
NestedForeach(class [mscorlib]System.Collections.Generic.List`1<object> items1,
class [mscorlib]System.Collections.Generic.List`1<object> items2) cil managed
{
// Code size 141 (0x8d)
// Code size 143 (0x8f)
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_0,
object V_1,
@ -2772,7 +2772,7 @@ @@ -2772,7 +2772,7 @@
IL_0008: stloc.0
.try
{
IL_0009: br.s IL_0067
IL_0009: br.s IL_0069
IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::get_Current()
@ -2825,37 +2825,39 @@ @@ -2825,37 +2825,39 @@
IL_0057: ceq
IL_0059: stloc.s V_6
IL_005b: ldloc.s V_6
IL_005d: brfalse.s IL_0066
IL_005d: brfalse.s IL_0068
IL_005f: ldloc.1
IL_0060: call void [mscorlib]System.Console::WriteLine(object)
IL_0065: nop
IL_005f: nop
IL_0060: ldloc.1
IL_0061: call void [mscorlib]System.Console::WriteLine(object)
IL_0066: nop
IL_0067: ldloca.s V_0
IL_0069: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::MoveNext()
IL_006e: brtrue.s IL_000b
IL_0067: nop
IL_0068: nop
IL_0069: ldloca.s V_0
IL_006b: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::MoveNext()
IL_0070: brtrue.s IL_000b
IL_0070: leave.s IL_0081
IL_0072: leave.s IL_0083
} // end .try
finally
{
IL_0072: ldloca.s V_0
IL_0074: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>
IL_007a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_007f: nop
IL_0080: endfinally
IL_0074: ldloca.s V_0
IL_0076: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>
IL_007c: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0081: nop
IL_0082: endfinally
} // end handler
IL_0081: ldstr "end"
IL_0086: call void [mscorlib]System.Console::WriteLine(string)
IL_008b: nop
IL_008c: ret
IL_0083: ldstr "end"
IL_0088: call void [mscorlib]System.Console::WriteLine(string)
IL_008d: nop
IL_008e: ret
} // end of method Loops::NestedForeach
.method public hidebysig instance void
MergeAroundContinue() cil managed
{
// Code size 144 (0x90)
// Code size 150 (0x96)
.maxstack 2
.locals init (int32 V_0,
bool V_1,
@ -2869,7 +2871,7 @@ @@ -2869,7 +2871,7 @@
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0079
IL_0003: br.s IL_007c
IL_0005: nop
IL_0006: ldloc.0
@ -2879,7 +2881,7 @@ @@ -2879,7 +2881,7 @@
IL_000a: ceq
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: brfalse.s IL_0021
IL_000e: brfalse.s IL_0022
IL_0010: nop
IL_0011: ldloc.0
@ -2889,92 +2891,95 @@ @@ -2889,92 +2891,95 @@
IL_0016: ceq
IL_0018: stloc.2
IL_0019: ldloc.2
IL_001a: brfalse.s IL_001e
IL_001a: brfalse.s IL_001f
IL_001c: br.s IL_0075
IL_001c: nop
IL_001d: br.s IL_0078
IL_001e: nop
IL_001f: br.s IL_006d
IL_001f: nop
IL_0020: br.s IL_0070
IL_0021: ldloc.0
IL_0022: ldc.i4.5
IL_0023: rem
IL_0024: ldc.i4.0
IL_0025: ceq
IL_0027: stloc.3
IL_0028: ldloc.3
IL_0029: brfalse.s IL_003e
IL_0022: ldloc.0
IL_0023: ldc.i4.5
IL_0024: rem
IL_0025: ldc.i4.0
IL_0026: ceq
IL_0028: stloc.3
IL_0029: ldloc.3
IL_002a: brfalse.s IL_0040
IL_002b: nop
IL_002c: ldloc.0
IL_002d: ldc.i4.5
IL_002e: ceq
IL_0030: ldc.i4.0
IL_0031: ceq
IL_0033: stloc.s V_4
IL_0035: ldloc.s V_4
IL_0037: brfalse.s IL_003b
IL_002c: nop
IL_002d: ldloc.0
IL_002e: ldc.i4.5
IL_002f: ceq
IL_0031: ldc.i4.0
IL_0032: ceq
IL_0034: stloc.s V_4
IL_0036: ldloc.s V_4
IL_0038: brfalse.s IL_003d
IL_0039: br.s IL_0075
IL_003a: nop
IL_003b: br.s IL_0078
IL_003b: nop
IL_003c: br.s IL_006d
IL_003e: ldloc.0
IL_003f: ldc.i4.7
IL_0040: rem
IL_0041: ldc.i4.0
IL_0042: ceq
IL_0044: stloc.s V_5
IL_0046: ldloc.s V_5
IL_0048: brfalse.s IL_005d
IL_004a: nop
IL_004b: ldloc.0
IL_004c: ldc.i4.7
IL_004d: ceq
IL_004f: ldc.i4.0
IL_0050: ceq
IL_0052: stloc.s V_6
IL_0054: ldloc.s V_6
IL_0056: brfalse.s IL_005a
IL_0058: br.s IL_0075
IL_003d: nop
IL_003e: br.s IL_0070
IL_0040: ldloc.0
IL_0041: ldc.i4.7
IL_0042: rem
IL_0043: ldc.i4.0
IL_0044: ceq
IL_0046: stloc.s V_5
IL_0048: ldloc.s V_5
IL_004a: brfalse.s IL_0060
IL_004c: nop
IL_004d: ldloc.0
IL_004e: ldc.i4.7
IL_004f: ceq
IL_0051: ldc.i4.0
IL_0052: ceq
IL_0054: stloc.s V_6
IL_0056: ldloc.s V_6
IL_0058: brfalse.s IL_005d
IL_005a: nop
IL_005b: br.s IL_006d
IL_005b: br.s IL_0078
IL_005d: ldloc.0
IL_005e: ldc.i4.s 11
IL_0060: rem
IL_0061: ldc.i4.0
IL_0062: ceq
IL_0064: stloc.s V_7
IL_0066: ldloc.s V_7
IL_0068: brfalse.s IL_006d
IL_005d: nop
IL_005e: br.s IL_0070
IL_006a: nop
IL_006b: br.s IL_0075
IL_006d: ldloc.0
IL_006e: call void [mscorlib]System.Console::WriteLine(int32)
IL_0073: nop
IL_0074: nop
IL_0075: ldloc.0
IL_0076: ldc.i4.1
IL_0077: add
IL_0078: stloc.0
IL_0079: ldloc.0
IL_007a: ldc.i4.s 20
IL_007c: clt
IL_007e: stloc.s V_8
IL_0080: ldloc.s V_8
IL_0082: brtrue.s IL_0005
IL_0084: ldstr "end"
IL_0089: call void [mscorlib]System.Console::WriteLine(string)
IL_008e: nop
IL_008f: ret
IL_0060: ldloc.0
IL_0061: ldc.i4.s 11
IL_0063: rem
IL_0064: ldc.i4.0
IL_0065: ceq
IL_0067: stloc.s V_7
IL_0069: ldloc.s V_7
IL_006b: brfalse.s IL_0070
IL_006d: nop
IL_006e: br.s IL_0078
IL_0070: ldloc.0
IL_0071: call void [mscorlib]System.Console::WriteLine(int32)
IL_0076: nop
IL_0077: nop
IL_0078: ldloc.0
IL_0079: ldc.i4.1
IL_007a: add
IL_007b: stloc.0
IL_007c: ldloc.0
IL_007d: ldc.i4.s 20
IL_007f: clt
IL_0081: stloc.s V_8
IL_0083: ldloc.s V_8
IL_0085: brtrue IL_0005
IL_008a: ldstr "end"
IL_008f: call void [mscorlib]System.Console::WriteLine(string)
IL_0094: nop
IL_0095: ret
} // end of method Loops::MergeAroundContinue
.method public hidebysig specialname rtspecialname

4
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -51,8 +51,8 @@ @@ -51,8 +51,8 @@
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.2.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
<PackageReference Include="System.Reflection.Metadata" Version="1.4.2" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="System.Reflection.Metadata" Version="1.6.0" />
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
</ItemGroup>

16
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -177,6 +177,22 @@ namespace ICSharpCode.Decompiler.IL @@ -177,6 +177,22 @@ namespace ICSharpCode.Decompiler.IL
default:
return SpecialType.UnknownType;
}
case BinaryNumericInstruction bni:
if (bni.IsLifted)
return SpecialType.UnknownType;
switch (bni.Operator) {
case BinaryNumericOperator.BitAnd:
case BinaryNumericOperator.BitOr:
case BinaryNumericOperator.BitXor:
var left = bni.Left.InferType(compilation);
var right = bni.Right.InferType(compilation);
if (left.Equals(right) && (left.IsCSharpPrimitiveIntegerType() || left.IsKnownType(KnownTypeCode.Boolean)))
return left;
else
return SpecialType.UnknownType;
default:
return SpecialType.UnknownType;
}
default:
return SpecialType.UnknownType;
}

15
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -499,13 +499,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -499,13 +499,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
break;
case BinaryNumericOperator.BitAnd:
if (inst.Left.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)
&& inst.Right.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)
&& SemanticHelper.IsPure(inst.Right.Flags))
&& inst.Right.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean))
{
context.Step("Replace bit.and with logic.and", inst);
var expr = IfInstruction.LogicAnd(inst.Left, inst.Right);
inst.ReplaceWith(expr);
expr.AcceptVisitor(this);
if (new NullableLiftingTransform(context).Run(inst)) {
// e.g. "(a.GetValueOrDefault() == b.GetValueOrDefault()) & (a.HasValue & b.HasValue)"
} else if (SemanticHelper.IsPure(inst.Right.Flags)) {
context.Step("Replace bit.and with logic.and", inst);
var expr = IfInstruction.LogicAnd(inst.Left, inst.Right);
inst.ReplaceWith(expr);
expr.AcceptVisitor(this);
}
}
break;
}

3
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -39,7 +39,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -39,7 +39,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// We exclude logic.and to avoid turning
// "logic.and(comp(interfaces != ldnull), call get_Count(interfaces))"
// into "if ((interfaces?.Count ?? 0) != 0)".
return (ifInst.MatchLogicAnd(out _, out _) || ifInst.MatchLogicOr(out _, out _))
return ifInst != null
&& (ifInst.MatchLogicAnd(out _, out _) || ifInst.MatchLogicOr(out _, out _))
&& IfInstruction.IsInConditionSlot(ifInst);
}

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

@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
public bool Run(IfInstruction ifInst)
{
var lifted = Lift(ifInst, ifInst.TrueInst, ifInst.FalseInst);
var lifted = Lift(ifInst, ifInst.Condition, ifInst.TrueInst, ifInst.FalseInst);
if (lifted != null) {
ifInst.ReplaceWith(lifted);
return true;
@ -64,6 +64,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -64,6 +64,25 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
/// <summary>
/// VS2017.8 / Roslyn 2.9 started optimizing some cases of
/// "a.GetValueOrDefault() == b.GetValueOrDefault() && (a.HasValue & b.HasValue)"
/// to
/// "(a.GetValueOrDefault() == b.GetValueOrDefault()) & (a.HasValue & b.HasValue)"
/// so this secondary entry point analyses logic.and as-if it was a short-circuting &&.
/// </summary>
public bool Run(BinaryNumericInstruction bni)
{
Debug.Assert(!bni.IsLifted && bni.Operator == BinaryNumericOperator.BitAnd);
// caller ensures that bni.Left/bni.Right are booleans
var lifted = Lift(bni, bni.Left, bni.Right, new LdcI4(0));
if (lifted != null) {
bni.ReplaceWith(lifted);
return true;
}
return false;
}
public bool RunStatements(Block block, int pos)
{
/// e.g.:
@ -85,7 +104,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -85,7 +104,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (elseLeave.TargetContainer != thenLeave.TargetContainer)
return false;
var lifted = Lift(ifInst, thenLeave.Value, elseLeave.Value);
var lifted = Lift(ifInst, ifInst.Condition, thenLeave.Value, elseLeave.Value);
if (lifted != null) {
thenLeave.Value = lifted;
ifInst.ReplaceWith(thenLeave);
@ -118,14 +137,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -118,14 +137,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Main entry point for lifting; called by both the expression-transform
/// and the block transform.
/// </summary>
ILInstruction Lift(IfInstruction ifInst, ILInstruction trueInst, ILInstruction falseInst)
ILInstruction Lift(ILInstruction ifInst, ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst)
{
ILInstruction condition = ifInst.Condition;
// ifInst is usually the IfInstruction to which condition belongs;
// but can also be a BinaryNumericInstruction.
while (condition.MatchLogicNot(out var arg)) {
condition = arg;
ExtensionMethods.Swap(ref trueInst, ref falseInst);
}
if (context.Settings.NullPropagation && !NullPropagationTransform.IsProtectedIfInst(ifInst)) {
if (context.Settings.NullPropagation && !NullPropagationTransform.IsProtectedIfInst(ifInst as IfInstruction)) {
var nullPropagated = new NullPropagationTransform(context)
.Run(condition, trueInst, falseInst, ifInst.ILRange);
if (nullPropagated != null)

6
ILSpy.Tests/ILSpy.Tests.csproj

@ -42,10 +42,10 @@ @@ -42,10 +42,10 @@
<ItemGroup>
<PackageReference Include="DiffLib" Version="2017.7.26.1241" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.9.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="2.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="NUnit" Version="3.9.0" />
</ItemGroup>

Loading…
Cancel
Save