Browse Source

Fix some bugs in decompilation of ?. operator.

pull/1066/head
Daniel Grunwald 7 years ago
parent
commit
80a717c090
  1. 12
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs
  2. 32
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il
  3. 56
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il
  4. 7
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  5. 9
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  6. 4
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

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

@ -179,5 +179,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -179,5 +179,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return f?.Invoke();
}
private void NotNullPropagation(MyClass c)
{
// don't decompile this to "(c?.IntVal ?? 0) != 0"
if (c != null && c.IntVal != 0) {
Console.WriteLine("non-zero");
}
if (c == null || c.IntVal == 0) {
Console.WriteLine("null or zero");
}
Console.WriteLine("end of method");
}
}
}

32
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module NullPropagation.dll
// MVID: {F0EFC1AB-9F50-47C3-A485-667304613B73}
// MVID: {024CEB8E-C4C6-4326-B706-A762E1916CDA}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00BC0000
// Image base: 0x032C0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -606,6 +606,34 @@ @@ -606,6 +606,34 @@
IL_0018: ret
} // end of method NullPropagation::InvokeDelegate
.method private hidebysig instance void
NotNullPropagation(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass c) cil managed
{
// Code size 53 (0x35)
.maxstack 8
IL_0000: ldarg.1
IL_0001: brfalse.s IL_0015
IL_0003: ldarg.1
IL_0004: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0009: brfalse.s IL_0015
IL_000b: ldstr "non-zero"
IL_0010: call void [mscorlib]System.Console::WriteLine(string)
IL_0015: ldarg.1
IL_0016: brfalse.s IL_0020
IL_0018: ldarg.1
IL_0019: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_001e: brtrue.s IL_002a
IL_0020: ldstr "null or zero"
IL_0025: call void [mscorlib]System.Console::WriteLine(string)
IL_002a: ldstr "end of method"
IL_002f: call void [mscorlib]System.Console::WriteLine(string)
IL_0034: ret
} // end of method NullPropagation::NotNullPropagation
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

56
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module NullPropagation.dll
// MVID: {9DF0D690-F814-4DC7-985C-0407C3EE435D}
// MVID: {AE2302E9-5EE9-4939-BCA6-21C8604BB095}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x047D0000
// Image base: 0x04900000
// =============== CLASS MEMBERS DECLARATION ===================
@ -708,6 +708,58 @@ @@ -708,6 +708,58 @@
IL_001e: ret
} // end of method NullPropagation::InvokeDelegate
.method private hidebysig instance void
NotNullPropagation(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass c) cil managed
{
// Code size 77 (0x4d)
.maxstack 2
.locals init (bool V_0,
bool V_1)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: brfalse.s IL_000f
IL_0004: ldarg.1
IL_0005: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_000a: ldc.i4.0
IL_000b: cgt.un
IL_000d: br.s IL_0010
IL_000f: ldc.i4.0
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: brfalse.s IL_0021
IL_0014: nop
IL_0015: ldstr "non-zero"
IL_001a: call void [mscorlib]System.Console::WriteLine(string)
IL_001f: nop
IL_0020: nop
IL_0021: ldarg.1
IL_0022: brfalse.s IL_002f
IL_0024: ldarg.1
IL_0025: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_002a: ldc.i4.0
IL_002b: ceq
IL_002d: br.s IL_0030
IL_002f: ldc.i4.1
IL_0030: stloc.1
IL_0031: ldloc.1
IL_0032: brfalse.s IL_0041
IL_0034: nop
IL_0035: ldstr "null or zero"
IL_003a: call void [mscorlib]System.Console::WriteLine(string)
IL_003f: nop
IL_0040: nop
IL_0041: ldstr "end of method"
IL_0046: call void [mscorlib]System.Console::WriteLine(string)
IL_004b: nop
IL_004c: ret
} // end of method NullPropagation::NotNullPropagation
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

7
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -201,6 +201,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -201,6 +201,13 @@ namespace ICSharpCode.Decompiler.CSharp
if (targetType.Kind == TypeKind.Unknown) {
return this; // don't attempt to insert cast to '?'
}
if (Expression is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.NullConditional && targetType.IsReferenceType == true) {
// "(T)(x?).AccessChain" is invalid, but "((T)x)?.AccessChain" is valid and equivalent
return new UnaryOperatorExpression(
UnaryOperatorType.NullConditional,
UnwrapChild(uoe.Expression).ConvertTo(targetType, expressionBuilder, checkForOverflow, allowImplicitConversion)
).WithRR(new ResolveResult(targetType)).WithoutILInstruction();
}
var compilation = expressionBuilder.compilation;
bool isLifted = type.IsKnownType(KnownTypeCode.NullableOfT) && targetType.IsKnownType(KnownTypeCode.NullableOfT);
IType utype = isLifted ? NullableType.GetUnderlyingType(type) : type;

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

@ -30,6 +30,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -30,6 +30,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
struct NullPropagationTransform
{
internal static bool IsProtectedIfInst(IfInstruction ifInst)
{
// 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 _))
&& IfInstruction.IsInConditionSlot(ifInst);
}
readonly ILTransformContext context;
public NullPropagationTransform(ILTransformContext context)

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

@ -36,7 +36,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -36,7 +36,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// * lifted unary and binary operators
/// * lifted comparisons
/// * the ?? operator with type Nullable{T} on the left-hand-side
/// * the ?. operator
/// * the ?. operator (via NullPropagationTransform)
/// </summary>
struct NullableLiftingTransform
{
@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
condition = arg;
ExtensionMethods.Swap(ref trueInst, ref falseInst);
}
if (context.Settings.NullPropagation) {
if (context.Settings.NullPropagation && !NullPropagationTransform.IsProtectedIfInst(ifInst)) {
var nullPropagated = new NullPropagationTransform(context)
.Run(condition, trueInst, falseInst, ifInst.ILRange);
if (nullPropagated != null)

Loading…
Cancel
Save