Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy

pull/1299/head
MysticBoy 7 years ago
parent
commit
b44b36b216
  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. 201
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  6. 201
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  7. 2
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  8. 4
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  9. 32
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  10. 2
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  11. 21
      ICSharpCode.Decompiler/IL/SemanticHelper.cs
  12. 2
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  13. 11
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  14. 5
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  15. 30
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
  16. 2
      ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs
  17. 34
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  18. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs
  19. 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

201
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
} // end handler
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: ldstr "end"
IL_008f: call void [mscorlib]System.Console::WriteLine(string)
IL_0094: nop
IL_0095: ret
IL_008a: endfinally
} // end handler
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_001c: br.s IL_0070
IL_001a: brtrue.s IL_001f
IL_001e: nop
IL_001f: br.s IL_0068
IL_001c: nop
IL_001d: br.s IL_0073
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_001f: nop
IL_0020: br.s IL_006b
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_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

2
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -666,7 +666,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -666,7 +666,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
break;
default:
output.Write(value.ToString());
DisassemblerHelpers.WriteOperand(output, value);
break;
}
}

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>

32
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.IL @@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.IL
///
/// Returns SpecialType.UnknownType for unsupported instructions.
/// </summary>
public static IType InferType(this ILInstruction inst)
public static IType InferType(this ILInstruction inst, ICompilation compilation)
{
switch (inst) {
case NewObj newObj:
@ -159,12 +159,40 @@ namespace ICSharpCode.Decompiler.IL @@ -159,12 +159,40 @@ namespace ICSharpCode.Decompiler.IL
case LdsFlda ldsflda:
return new ByReferenceType(ldsflda.Field.Type);
case LdElema ldelema:
if (ldelema.Array.InferType() is ArrayType arrayType) {
if (ldelema.Array.InferType(compilation) is ArrayType arrayType) {
if (TypeUtils.IsCompatibleTypeForMemoryAccess(arrayType.ElementType, ldelema.Type)) {
return new ByReferenceType(arrayType.ElementType);
}
}
return new ByReferenceType(ldelema.Type);
case Comp comp:
if (compilation == null)
return SpecialType.UnknownType;
switch (comp.LiftingKind) {
case ComparisonLiftingKind.None:
case ComparisonLiftingKind.CSharp:
return compilation.FindType(KnownTypeCode.Boolean);
case ComparisonLiftingKind.ThreeValuedLogic:
return NullableType.Create(compilation, compilation.FindType(KnownTypeCode.Boolean));
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;
}

2
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.IL @@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.IL
}
}
// Can't transform if the RHS value would be need to be truncated for the LHS type.
if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, binary.IsLifted))
if (Transforms.TransformAssignment.IsImplicitTruncation(binary.Right, type, null, binary.IsLifted))
return false;
return true;
}

21
ICSharpCode.Decompiler/IL/SemanticHelper.cs

@ -44,27 +44,6 @@ namespace ICSharpCode.Decompiler.IL @@ -44,27 +44,6 @@ namespace ICSharpCode.Decompiler.IL
return (inst & ~pureFlags) == 0;
}
/// <summary>
/// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;'
/// </summary>
internal static bool MayReorder(InstructionFlags inst1, InstructionFlags inst2)
{
// If both instructions perform an impure action, we cannot reorder them
if (!IsPure(inst1) && !IsPure(inst2))
return false;
// We cannot reorder if inst2 might write what inst1 looks at
if (ConflictingPair(inst1, inst2, InstructionFlags.MayReadLocals, InstructionFlags.MayWriteLocals | InstructionFlags.SideEffect))
return false;
return true;
}
private static bool ConflictingPair(InstructionFlags inst1, InstructionFlags inst2, InstructionFlags readFlag, InstructionFlags writeFlag)
{
// if one instruction has the read flag and the other the write flag, that's a conflict
return (inst1 & readFlag) != 0 && (inst2 & writeFlag) != 0
|| (inst2 & readFlag) != 0 && (inst1 & writeFlag) != 0;
}
/// <summary>
/// Gets whether the instruction sequence 'inst1; inst2;' may be ordered to 'inst2; inst1;'
/// </summary>

2
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -448,7 +448,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -448,7 +448,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!variableType.IsKnownType(KnownTypeCode.Object))
return variableType;
IType inferredType = inst.InferType();
IType inferredType = inst.InferType(context.TypeSystem);
if (inferredType.Kind != TypeKind.Unknown)
return inferredType;
else

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

@ -498,21 +498,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -498,21 +498,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
break;
case BinaryNumericOperator.BitAnd:
if (IsBoolean(inst.Left) && IsBoolean(inst.Right) && SemanticHelper.IsPure(inst.Right.Flags))
if (inst.Left.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean)
&& inst.Right.InferType(context.TypeSystem).IsKnownType(KnownTypeCode.Boolean))
{
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;
}
}
private static bool IsBoolean(ILInstruction inst) =>
inst is Comp c && c.ResultType == StackType.I4 ||
inst.InferType().IsKnownType(KnownTypeCode.Boolean);
protected internal override void VisitTryCatchHandler(TryCatchHandler inst)
{
base.VisitTryCatchHandler(inst);

5
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);
}
@ -111,7 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -111,7 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!IsValidAccessChain(testedVar, mode, nonNullInst, out var varLoad))
return null;
// note: InferType will be accurate in this case because the access chain consists of calls and field accesses
IType returnType = nonNullInst.InferType();
IType returnType = nonNullInst.InferType(context.TypeSystem);
if (nullInst.MatchLdNull()) {
context.Step($"Null propagation (mode={mode}, output=reference type)", nonNullInst);
// testedVar != null ? testedVar.AccessChain : null

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)

2
ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs

@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IType newType = null;
// Multiple store are possible in case of (c ? ref a : ref b) += 1, for example.
foreach (var stloc in v.StoreInstructions.OfType<StLoc>()) {
var inferredType = stloc.Value.InferType();
var inferredType = stloc.Value.InferType(context.TypeSystem);
// cancel, if types of values do not match exactly
if (newType != null && !newType.Equals(inferredType)) {
newType = SpecialType.UnknownType;

34
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -88,7 +88,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -88,7 +88,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// in some cases it can be a compiler-generated local
if (inst == null || (inst.Variable.Kind != VariableKind.StackSlot && inst.Variable.Kind != VariableKind.Local))
return false;
if (IsImplicitTruncation(inst.Value, inst.Variable.Type)) {
if (IsImplicitTruncation(inst.Value, inst.Variable.Type, context.TypeSystem)) {
// 'stloc s' is implicitly truncating the value
return false;
}
@ -112,7 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -112,7 +112,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!SemanticHelper.IsPure(stobj.Target.Flags) || inst.Variable.IsUsedWithin(stobj.Target))
return false;
var pointerType = stobj.Target.InferType();
var pointerType = stobj.Target.InferType(context.TypeSystem);
IType newType = stobj.Type;
if (TypeUtils.IsCompatiblePointerTypeForMemoryAccess(pointerType, stobj.Type)) {
if (pointerType is ByReferenceType byref)
@ -120,7 +120,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -120,7 +120,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
else if (pointerType is PointerType pointer)
newType = pointer.ElementType;
}
if (IsImplicitTruncation(inst.Value, newType)) {
if (IsImplicitTruncation(inst.Value, newType, context.TypeSystem)) {
// 'stobj' is implicitly truncating the value
return false;
}
@ -146,7 +146,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -146,7 +146,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!SemanticHelper.IsPure(arg.Flags) || inst.Variable.IsUsedWithin(arg))
return false;
}
if (IsImplicitTruncation(inst.Value, call.Method.Parameters.Last().Type)) {
if (IsImplicitTruncation(inst.Value, call.Method.Parameters.Last().Type, context.TypeSystem)) {
// setter call is implicitly truncating the value
return false;
}
@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -242,7 +242,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// changes the return value of the expression, so this is only valid on block-level.
return false;
}
if (!IsCompoundStore(compoundStore, out var targetType, out var setterValue))
if (!IsCompoundStore(compoundStore, out var targetType, out var setterValue, context.TypeSystem))
return false;
// targetType = The type of the property/field/etc. being stored to.
// setterValue = The value being stored.
@ -342,11 +342,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -342,11 +342,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!nextInst.Value.MatchLdLoc(inst.Variable))
return false;
if (IsImplicitTruncation(inst.Value, inst.Variable.Type)) {
if (IsImplicitTruncation(inst.Value, inst.Variable.Type, context.TypeSystem)) {
// 'stloc s' is implicitly truncating the stack value
return false;
}
if (IsImplicitTruncation(inst.Value, nextInst.Variable.Type)) {
if (IsImplicitTruncation(inst.Value, nextInst.Variable.Type, context.TypeSystem)) {
// 'stloc l' is implicitly truncating the stack value
return false;
}
@ -371,7 +371,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -371,7 +371,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Gets whether 'stobj type(..., value)' would evaluate to a different value than 'value'
/// due to implicit truncation.
/// </summary>
static internal bool IsImplicitTruncation(ILInstruction value, IType type, bool allowNullableValue = false)
static internal bool IsImplicitTruncation(ILInstruction value, IType type, ICompilation compilation, bool allowNullableValue = false)
{
if (!type.IsSmallIntegerType()) {
// Implicit truncation in ILAst only happens for small integer types;
@ -401,10 +401,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -401,10 +401,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else if (value is Comp) {
return false; // comp returns 0 or 1, which always fits
} else if (value is IfInstruction ifInst) {
return IsImplicitTruncation(ifInst.TrueInst, type, allowNullableValue)
|| IsImplicitTruncation(ifInst.FalseInst, type, allowNullableValue);
return IsImplicitTruncation(ifInst.TrueInst, type, compilation, allowNullableValue)
|| IsImplicitTruncation(ifInst.FalseInst, type, compilation, allowNullableValue);
} else {
IType inferredType = value.InferType();
IType inferredType = value.InferType(compilation);
if (allowNullableValue) {
inferredType = NullableType.GetUnderlyingType(inferredType);
}
@ -456,14 +456,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -456,14 +456,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary>
/// Gets whether 'inst' is a possible store for use as a compound store.
/// </summary>
static bool IsCompoundStore(ILInstruction inst, out IType storeType, out ILInstruction value)
static bool IsCompoundStore(ILInstruction inst, out IType storeType, out ILInstruction value, ICompilation compilation)
{
value = null;
storeType = null;
if (inst is StObj stobj) {
// stobj.Type may just be 'int' (due to stind.i4) when we're actually operating on a 'ref MyEnum'.
// Try to determine the real type of the object we're modifying:
storeType = stobj.Target.InferType();
storeType = stobj.Target.InferType(compilation);
if (storeType is ByReferenceType refType) {
storeType = refType.ElementType;
} else if (storeType is PointerType pointerType) {
@ -530,7 +530,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -530,7 +530,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool TransformPostIncDecOperatorWithInlineStore(Block block, int pos)
{
var store = block.Instructions[pos];
if (!IsCompoundStore(store, out var targetType, out var value))
if (!IsCompoundStore(store, out var targetType, out var value, context.TypeSystem))
return false;
StLoc stloc;
var binary = UnwrapSmallIntegerConv(value, out var conv) as BinaryNumericInstruction;
@ -555,7 +555,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -555,7 +555,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!IsMatchingCompoundLoad(stloc.Value, store, stloc.Variable))
return false;
if (IsImplicitTruncation(stloc.Value, stloc.Variable.Type))
if (IsImplicitTruncation(stloc.Value, stloc.Variable.Type, context.TypeSystem))
return false;
context.Step("TransformPostIncDecOperatorWithInlineStore", store);
if (binary != null) {
@ -585,9 +585,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -585,9 +585,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var store = block.Instructions.ElementAtOrDefault(i + 1);
if (inst == null || store == null)
return false;
if (!IsCompoundStore(store, out var targetType, out var value))
if (!IsCompoundStore(store, out var targetType, out var value, context.TypeSystem))
return false;
if (IsImplicitTruncation(inst.Value, targetType)) {
if (IsImplicitTruncation(inst.Value, targetType, context.TypeSystem)) {
// 'stloc l' is implicitly truncating the value
return false;
}

2
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -1065,7 +1065,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1065,7 +1065,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
value = call.Arguments[0];
if (call.Arguments.Count == 2)
return MatchGetTypeFromHandle(call.Arguments[1], out type);
type = value.InferType();
type = value.InferType(context.TypeSystem);
return true;
}
return false;

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