Browse Source

Implement null propagation transform.

pull/1066/head
Daniel Grunwald 7 years ago
parent
commit
ca0fa55af8
  1. 12
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 2
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  4. 29
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs
  5. 180
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs
  6. 624
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il
  7. 727
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il
  8. 7
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  9. 20
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  10. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  11. 36
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  12. 14
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs
  13. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs
  14. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  15. 40
      ICSharpCode.Decompiler/IL/Instructions.cs
  16. 9
      ICSharpCode.Decompiler/IL/Instructions.tt
  17. 17
      ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs
  18. 2
      ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs
  19. 170
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  20. 13
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

12
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -53,6 +53,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -53,6 +53,12 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn
};
static readonly CompilerOptions[] roslynOnlyOptions =
{
CompilerOptions.UseRoslyn,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn
};
[Test]
public void Comparisons([ValueSource("defaultOptions")] CompilerOptions options)
{
@ -167,6 +173,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -167,6 +173,12 @@ namespace ICSharpCode.Decompiler.Tests
RunCS(options: options);
}
[Test]
public void NullPropagation([ValueSource("roslynOnlyOptions")] CompilerOptions options)
{
RunCS(options: options);
}
[Test]
public void BitNot([Values(false, true)] bool force32Bit)
{

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -62,6 +62,7 @@ @@ -62,6 +62,7 @@
<Compile Include="TestCases\Correctness\LINQRaytracer.cs" />
<Compile Include="TestCases\Correctness\MiniJSON.cs" />
<Compile Include="TestCases\Correctness\FloatingPointArithmetic.cs" />
<Compile Include="TestCases\Correctness\NullPropagation.cs" />
<Compile Include="TestCases\ILPretty\Issue982.cs" />
<Compile Include="TestCases\Pretty\CS72_PrivateProtected.cs" />
<Compile Include="TestCases\Pretty\ExpressionTrees.cs" />

2
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -230,7 +230,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -230,7 +230,7 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions);
}
[Test, Ignore]
[Test]
public void NullPropagation([ValueSource("roslynOnlyOptions")] CompilerOptions cscOptions)
{
Run(cscOptions: cscOptions);

29
ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
class NullPropagation
{
static void Main()
{
new NullPropagation().TestNotCoalescing();
}
class MyClass
{
public string Text;
}
void TestNotCoalescing()
{
Console.WriteLine("TestNotCoalescing:");
Console.WriteLine(NotCoalescing(null));
Console.WriteLine(NotCoalescing(new MyClass()));
}
string NotCoalescing(MyClass c)
{
return c != null ? c.Text : "Hello";
}
}
}

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

@ -2,16 +2,25 @@ @@ -2,16 +2,25 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
class NullPropagation
internal class NullPropagation
{
class MyClass
private class MyClass
{
public int IntVal;
public string Text;
public MyClass Field;
public MyClass Property { get; set; }
public MyClass Method(int arg) { return null; }
public MyClass Property {
get;
set;
}
public MyClass this[int index] {
get { return null; }
get {
return null;
}
}
public MyClass Method(int arg)
{
return null;
}
public void Done()
@ -19,16 +28,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -19,16 +28,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
struct MyStruct
private struct MyStruct
{
public int IntVal;
public MyClass Field;
public MyStruct? Property1 { get { return null; } }
public MyStruct Property2 { get { return default; } }
public MyStruct? Method1(int arg) { return null; }
public MyStruct Method2(int arg) { return default; }
public MyStruct? Property1 {
get {
return null;
}
}
public MyStruct Property2 {
get {
return default(MyStruct);
}
}
public MyStruct? this[int index] {
get { return null; }
get {
return null;
}
}
public MyStruct? Method1(int arg)
{
return null;
}
public MyStruct Method2(int arg)
{
return default(MyStruct);
}
public void Done()
@ -36,86 +61,123 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -36,86 +61,123 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
int GetInt()
private int GetInt()
{
return 9;
}
string GetString()
private string GetString()
{
return null;
}
MyClass GetMyClass()
private MyClass GetMyClass()
{
return null;
}
MyStruct? GetMyStruct()
private MyStruct? GetMyStruct()
{
return null;
}
string Substring()
public string Substring()
{
return this.GetString()?.Substring(this.GetInt());
}
private void Use<T>(T t)
{
}
#if VOID_SUPPORTED
public void CallDone()
{
this.GetMyClass()?.Done();
this.GetMyClass()?.Field?.Done();
this.GetMyClass()?.Field.Done();
this.GetMyClass()?.Property?.Done();
this.GetMyClass()?.Property.Done();
this.GetMyClass()?.Method(GetInt())?.Done();
this.GetMyClass()?.Method(GetInt()).Done();
this.GetMyClass()?[GetInt()]?.Done();
this.GetMyClass()?[GetInt()].Done();
}
public void CallDoneStruct()
{
this.GetMyStruct()?.Done();
this.GetMyStruct()?.Field?.Done();
this.GetMyStruct()?.Field.Done();
this.GetMyStruct()?.Property1?.Done();
this.GetMyStruct()?.Property2.Done();
this.GetMyStruct()?.Method1(GetInt())?.Done();
this.GetMyStruct()?.Method2(GetInt()).Done();
this.GetMyStruct()?[GetInt()]?.Done();
}
#endif
public void RequiredParentheses()
{
(this.GetMyClass()?.Field).Done();
(this.GetMyClass()?.Method(this.GetInt())).Done();
// (GetMyStruct()?.Property2)?.Done();
}
public int?[] ChainsOnClass()
{
return new int?[9] {
this.GetMyClass()?.IntVal,
this.GetMyClass()?.Field.IntVal,
this.GetMyClass()?.Field?.IntVal,
this.GetMyClass()?.Property.IntVal,
this.GetMyClass()?.Property?.IntVal,
this.GetMyClass()?.Method(this.GetInt()).IntVal,
this.GetMyClass()?.Method(this.GetInt())?.IntVal,
this.GetMyClass()?[this.GetInt()].IntVal,
this.GetMyClass()?[this.GetInt()]?.IntVal
};
}
#if STRUCT_SPLITTING_IMPROVED
public int? SumOfChainsStruct()
{
return GetString()?.Substring(GetInt());
return this.GetMyStruct()?.IntVal
+ this.GetMyStruct()?.Field.IntVal
+ this.GetMyStruct()?.Field?.IntVal
+ this.GetMyStruct()?.Property2.IntVal
+ this.GetMyStruct()?.Property1?.IntVal
+ this.GetMyStruct()?.Method2(this.GetInt()).IntVal
+ this.GetMyStruct()?.Method1(this.GetInt())?.IntVal
+ this.GetMyStruct()?[this.GetInt()]?.IntVal;
}
#endif
void CallDone()
public int CoalescingReturn()
{
GetMyClass()?.Done();
GetMyClass()?.Field?.Done();
GetMyClass()?.Field.Done();
GetMyClass()?.Property?.Done();
GetMyClass()?.Property.Done();
GetMyClass()?.Method(GetInt())?.Done();
GetMyClass()?.Method(GetInt()).Done();
GetMyClass()?[GetInt()]?.Done();
GetMyClass()?[GetInt()].Done();
return this.GetMyClass()?.IntVal ?? 1;
}
void CallDoneStruct()
public void Coalescing()
{
GetMyStruct()?.Done();
GetMyStruct()?.Field?.Done();
GetMyStruct()?.Field.Done();
GetMyStruct()?.Property1?.Done();
GetMyStruct()?.Property2.Done();
GetMyStruct()?.Method1(GetInt())?.Done();
GetMyStruct()?.Method2(GetInt()).Done();
GetMyStruct()?[GetInt()]?.Done();
this.Use(this.GetMyClass()?.IntVal ?? 1);
}
void RequiredParentheses()
public void CoalescingString()
{
(GetMyClass()?.Field).Done();
(GetMyClass()?.Method(GetInt())).Done();
(GetMyStruct()?.Property2)?.Done();
this.Use(this.GetMyClass()?.Text ?? "Hello");
}
int? SumOfChains()
#if VOID_SUPPORTED
public void InvokeDelegate(EventHandler eh)
{
return GetMyClass()?.IntVal
+ GetMyClass()?.Field.IntVal
+ GetMyClass()?.Field?.IntVal
+ GetMyClass()?.Property.IntVal
+ GetMyClass()?.Property?.IntVal
+ GetMyClass()?.Method(GetInt()).IntVal
+ GetMyClass()?.Method(GetInt())?.IntVal
+ GetMyClass()?[GetInt()].IntVal
+ GetMyClass()?[GetInt()]?.IntVal;
eh?.Invoke(null, EventArgs.Empty);
}
#endif
int? SumOfChainsStruct()
public int? InvokeDelegate(Func<int> f)
{
return GetMyStruct()?.IntVal
+ GetMyStruct()?.Field.IntVal
+ GetMyStruct()?.Field?.IntVal
+ GetMyStruct()?.Property2.IntVal
+ GetMyStruct()?.Property1?.IntVal
+ GetMyStruct()?.Method2(GetInt()).IntVal
+ GetMyStruct()?.Method1(GetInt())?.IntVal
+ GetMyStruct()?[GetInt()]?.IntVal;
return f?.Invoke();
}
}
}

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

@ -0,0 +1,624 @@ @@ -0,0 +1,624 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NullPropagation
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NullPropagation.dll
// MVID: {F0EFC1AB-9F50-47C3-A485-667304613B73}
.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
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
extends [mscorlib]System.Object
{
.class auto ansi nested private beforefieldinit MyClass
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6D 00 00 ) // ...Item..
.field public int32 IntVal
.field public string Text
.field public class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass Field
.field private class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass '<Property>k__BackingField'
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.method public hidebysig specialname
instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
get_Property() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::'<Property>k__BackingField'
IL_0006: ret
} // end of method MyClass::get_Property
.method public hidebysig specialname
instance void set_Property(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::'<Property>k__BackingField'
IL_0007: ret
} // end of method MyClass::set_Property
.method public hidebysig specialname
instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
get_Item(int32 index) cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: ret
} // end of method MyClass::get_Item
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
Method(int32 arg) cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: ret
} // end of method MyClass::Method
.method public hidebysig instance void
Done() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method MyClass::Done
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method MyClass::.ctor
.property instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
Property()
{
.get instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::set_Property(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass)
} // end of property MyClass::Property
.property instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
Item(int32)
{
.get instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
} // end of property MyClass::Item
} // end of class MyClass
.class sequential ansi sealed nested private beforefieldinit MyStruct
extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6D 00 00 ) // ...Item..
.field public int32 IntVal
.field public class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass Field
.method public hidebysig specialname
instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
get_Property1() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0008: ldloc.0
IL_0009: ret
} // end of method MyStruct::get_Property1
.method public hidebysig specialname
instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
get_Property2() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
IL_0008: ldloc.0
IL_0009: ret
} // end of method MyStruct::get_Property2
.method public hidebysig specialname
instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
get_Item(int32 index) cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0008: ldloc.0
IL_0009: ret
} // end of method MyStruct::get_Item
.method public hidebysig instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
Method1(int32 arg) cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0008: ldloc.0
IL_0009: ret
} // end of method MyStruct::Method1
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
Method2(int32 arg) cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
IL_0008: ldloc.0
IL_0009: ret
} // end of method MyStruct::Method2
.method public hidebysig instance void
Done() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method MyStruct::Done
.property instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
Property1()
{
.get instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::get_Property1()
} // end of property MyStruct::Property1
.property instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
Property2()
{
.get instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::get_Property2()
} // end of property MyStruct::Property2
.property instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
Item(int32)
{
.get instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::get_Item(int32)
} // end of property MyStruct::Item
} // end of class MyStruct
.method private hidebysig instance int32
GetInt() cil managed
{
// Code size 3 (0x3)
.maxstack 8
IL_0000: ldc.i4.s 9
IL_0002: ret
} // end of method NullPropagation::GetInt
.method private hidebysig instance string
GetString() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: ret
} // end of method NullPropagation::GetString
.method private hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
GetMyClass() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: ldnull
IL_0001: ret
} // end of method NullPropagation::GetMyClass
.method private hidebysig instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
GetMyStruct() cil managed
{
// Code size 10 (0xa)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0)
IL_0000: ldloca.s V_0
IL_0002: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0008: ldloc.0
IL_0009: ret
} // end of method NullPropagation::GetMyStruct
.method public hidebysig instance string
Substring() cil managed
{
// Code size 24 (0x18)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetString()
IL_0006: dup
IL_0007: brtrue.s IL_000c
IL_0009: pop
IL_000a: ldnull
IL_000b: ret
IL_000c: ldarg.0
IL_000d: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0012: call instance string [mscorlib]System.String::Substring(int32)
IL_0017: ret
} // end of method NullPropagation::Substring
.method private hidebysig instance void
Use<T>(!!T t) cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method NullPropagation::Use
.method public hidebysig instance void
RequiredParentheses() cil managed
{
// Code size 53 (0x35)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0006: dup
IL_0007: brtrue.s IL_000d
IL_0009: pop
IL_000a: ldnull
IL_000b: br.s IL_0012
IL_000d: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
IL_0012: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
IL_0017: ldarg.0
IL_0018: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_001d: dup
IL_001e: brtrue.s IL_0024
IL_0020: pop
IL_0021: ldnull
IL_0022: br.s IL_002f
IL_0024: ldarg.0
IL_0025: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_002a: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
IL_002f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
IL_0034: ret
} // end of method NullPropagation::RequiredParentheses
.method public hidebysig instance valuetype [mscorlib]System.Nullable`1<int32>[]
ChainsOnClass() cil managed
{
// Code size 474 (0x1da)
.maxstack 5
.locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0)
IL_0000: ldc.i4.s 9
IL_0002: newarr valuetype [mscorlib]System.Nullable`1<int32>
IL_0007: dup
IL_0008: ldc.i4.0
IL_0009: ldarg.0
IL_000a: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_000f: dup
IL_0010: brtrue.s IL_001e
IL_0012: pop
IL_0013: ldloca.s V_0
IL_0015: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_001b: ldloc.0
IL_001c: br.s IL_0028
IL_001e: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0023: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0028: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_002d: dup
IL_002e: ldc.i4.1
IL_002f: ldarg.0
IL_0030: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0035: dup
IL_0036: brtrue.s IL_0044
IL_0038: pop
IL_0039: ldloca.s V_0
IL_003b: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0041: ldloc.0
IL_0042: br.s IL_0053
IL_0044: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
IL_0049: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_004e: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0053: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0058: dup
IL_0059: ldc.i4.2
IL_005a: ldarg.0
IL_005b: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0060: dup
IL_0061: brtrue.s IL_006f
IL_0063: pop
IL_0064: ldloca.s V_0
IL_0066: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_006c: ldloc.0
IL_006d: br.s IL_008d
IL_006f: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
IL_0074: dup
IL_0075: brtrue.s IL_0083
IL_0077: pop
IL_0078: ldloca.s V_0
IL_007a: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0080: ldloc.0
IL_0081: br.s IL_008d
IL_0083: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0088: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_008d: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0092: dup
IL_0093: ldc.i4.3
IL_0094: ldarg.0
IL_0095: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_009a: dup
IL_009b: brtrue.s IL_00a9
IL_009d: pop
IL_009e: ldloca.s V_0
IL_00a0: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_00a6: ldloc.0
IL_00a7: br.s IL_00b8
IL_00a9: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
IL_00ae: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_00b3: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_00b8: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_00bd: dup
IL_00be: ldc.i4.4
IL_00bf: ldarg.0
IL_00c0: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_00c5: dup
IL_00c6: brtrue.s IL_00d4
IL_00c8: pop
IL_00c9: ldloca.s V_0
IL_00cb: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_00d1: ldloc.0
IL_00d2: br.s IL_00f2
IL_00d4: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
IL_00d9: dup
IL_00da: brtrue.s IL_00e8
IL_00dc: pop
IL_00dd: ldloca.s V_0
IL_00df: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_00e5: ldloc.0
IL_00e6: br.s IL_00f2
IL_00e8: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_00ed: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_00f2: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_00f7: dup
IL_00f8: ldc.i4.5
IL_00f9: ldarg.0
IL_00fa: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_00ff: dup
IL_0100: brtrue.s IL_010e
IL_0102: pop
IL_0103: ldloca.s V_0
IL_0105: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_010b: ldloc.0
IL_010c: br.s IL_0123
IL_010e: ldarg.0
IL_010f: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0114: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
IL_0119: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_011e: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0123: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0128: dup
IL_0129: ldc.i4.6
IL_012a: ldarg.0
IL_012b: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0130: dup
IL_0131: brtrue.s IL_013f
IL_0133: pop
IL_0134: ldloca.s V_0
IL_0136: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_013c: ldloc.0
IL_013d: br.s IL_0163
IL_013f: ldarg.0
IL_0140: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0145: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
IL_014a: dup
IL_014b: brtrue.s IL_0159
IL_014d: pop
IL_014e: ldloca.s V_0
IL_0150: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0156: ldloc.0
IL_0157: br.s IL_0163
IL_0159: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_015e: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0163: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0168: dup
IL_0169: ldc.i4.7
IL_016a: ldarg.0
IL_016b: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0170: dup
IL_0171: brtrue.s IL_017f
IL_0173: pop
IL_0174: ldloca.s V_0
IL_0176: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_017c: ldloc.0
IL_017d: br.s IL_0194
IL_017f: ldarg.0
IL_0180: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0185: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
IL_018a: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_018f: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0194: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0199: dup
IL_019a: ldc.i4.8
IL_019b: ldarg.0
IL_019c: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_01a1: dup
IL_01a2: brtrue.s IL_01b0
IL_01a4: pop
IL_01a5: ldloca.s V_0
IL_01a7: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_01ad: ldloc.0
IL_01ae: br.s IL_01d4
IL_01b0: ldarg.0
IL_01b1: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_01b6: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
IL_01bb: dup
IL_01bc: brtrue.s IL_01ca
IL_01be: pop
IL_01bf: ldloca.s V_0
IL_01c1: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_01c7: ldloc.0
IL_01c8: br.s IL_01d4
IL_01ca: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_01cf: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_01d4: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_01d9: ret
} // end of method NullPropagation::ChainsOnClass
.method public hidebysig instance int32
CoalescingReturn() cil managed
{
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0006: dup
IL_0007: brtrue.s IL_000c
IL_0009: pop
IL_000a: ldc.i4.1
IL_000b: ret
IL_000c: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0011: ret
} // end of method NullPropagation::CoalescingReturn
.method public hidebysig instance void
Coalescing() cil managed
{
// Code size 25 (0x19)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0007: dup
IL_0008: brtrue.s IL_000e
IL_000a: pop
IL_000b: ldc.i4.1
IL_000c: br.s IL_0013
IL_000e: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0013: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::Use<int32>(!!0)
IL_0018: ret
} // end of method NullPropagation::Coalescing
.method public hidebysig instance void
CoalescingString() cil managed
{
// Code size 34 (0x22)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0007: dup
IL_0008: brtrue.s IL_000e
IL_000a: pop
IL_000b: ldnull
IL_000c: br.s IL_0013
IL_000e: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Text
IL_0013: dup
IL_0014: brtrue.s IL_001c
IL_0016: pop
IL_0017: ldstr "Hello"
IL_001c: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::Use<string>(!!0)
IL_0021: ret
} // end of method NullPropagation::CoalescingString
.method public hidebysig instance valuetype [mscorlib]System.Nullable`1<int32>
InvokeDelegate(class [mscorlib]System.Func`1<int32> f) cil managed
{
// Code size 25 (0x19)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0)
IL_0000: ldarg.1
IL_0001: brtrue.s IL_000d
IL_0003: ldloca.s V_0
IL_0005: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_000b: ldloc.0
IL_000c: ret
IL_000d: ldarg.1
IL_000e: callvirt instance !0 class [mscorlib]System.Func`1<int32>::Invoke()
IL_0013: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0018: ret
} // end of method NullPropagation::InvokeDelegate
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method NullPropagation::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

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

@ -0,0 +1,727 @@ @@ -0,0 +1,727 @@
// Microsoft (R) .NET Framework IL Disassembler. Version 4.6.1055.0
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly NullPropagation
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module NullPropagation.dll
// MVID: {9DF0D690-F814-4DC7-985C-0407C3EE435D}
.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
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
extends [mscorlib]System.Object
{
.class auto ansi nested private beforefieldinit MyClass
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6D 00 00 ) // ...Item..
.field public int32 IntVal
.field public string Text
.field public class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass Field
.field private class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass '<Property>k__BackingField'
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 )
.method public hidebysig specialname
instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
get_Property() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::'<Property>k__BackingField'
IL_0006: ret
} // end of method MyClass::get_Property
.method public hidebysig specialname
instance void set_Property(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::'<Property>k__BackingField'
IL_0007: ret
} // end of method MyClass::set_Property
.method public hidebysig specialname
instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
get_Item(int32 index) cil managed
{
// Code size 7 (0x7)
.maxstack 1
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
} // end of method MyClass::get_Item
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
Method(int32 arg) cil managed
{
// Code size 7 (0x7)
.maxstack 1
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
} // end of method MyClass::Method
.method public hidebysig instance void
Done() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method MyClass::Done
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method MyClass::.ctor
.property instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
Property()
{
.get instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::set_Property(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass)
} // end of property MyClass::Property
.property instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
Item(int32)
{
.get instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
} // end of property MyClass::Item
} // end of class MyClass
.class sequential ansi sealed nested private beforefieldinit MyStruct
extends [mscorlib]System.ValueType
{
.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( 01 00 04 49 74 65 6D 00 00 ) // ...Item..
.field public int32 IntVal
.field public class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass Field
.method public hidebysig specialname
instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
get_Property1() cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0,
valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_1)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0009: ldloc.0
IL_000a: stloc.1
IL_000b: br.s IL_000d
IL_000d: ldloc.1
IL_000e: ret
} // end of method MyStruct::get_Property1
.method public hidebysig specialname
instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
get_Property2() cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_1)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
IL_0009: ldloc.0
IL_000a: stloc.1
IL_000b: br.s IL_000d
IL_000d: ldloc.1
IL_000e: ret
} // end of method MyStruct::get_Property2
.method public hidebysig specialname
instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
get_Item(int32 index) cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0,
valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_1)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0009: ldloc.0
IL_000a: stloc.1
IL_000b: br.s IL_000d
IL_000d: ldloc.1
IL_000e: ret
} // end of method MyStruct::get_Item
.method public hidebysig instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
Method1(int32 arg) cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0,
valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_1)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0009: ldloc.0
IL_000a: stloc.1
IL_000b: br.s IL_000d
IL_000d: ldloc.1
IL_000e: ret
} // end of method MyStruct::Method1
.method public hidebysig instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
Method2(int32 arg) cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_1)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
IL_0009: ldloc.0
IL_000a: stloc.1
IL_000b: br.s IL_000d
IL_000d: ldloc.1
IL_000e: ret
} // end of method MyStruct::Method2
.method public hidebysig instance void
Done() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method MyStruct::Done
.property instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
Property1()
{
.get instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::get_Property1()
} // end of property MyStruct::Property1
.property instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct
Property2()
{
.get instance valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::get_Property2()
} // end of property MyStruct::Property2
.property instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
Item(int32)
{
.get instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::get_Item(int32)
} // end of property MyStruct::Item
} // end of class MyStruct
.method private hidebysig instance int32
GetInt() cil managed
{
// Code size 8 (0x8)
.maxstack 1
.locals init (int32 V_0)
IL_0000: nop
IL_0001: ldc.i4.s 9
IL_0003: stloc.0
IL_0004: br.s IL_0006
IL_0006: ldloc.0
IL_0007: ret
} // end of method NullPropagation::GetInt
.method private hidebysig instance string
GetString() cil managed
{
// Code size 7 (0x7)
.maxstack 1
.locals init (string V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
} // end of method NullPropagation::GetString
.method private hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass
GetMyClass() cil managed
{
// Code size 7 (0x7)
.maxstack 1
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
} // end of method NullPropagation::GetMyClass
.method private hidebysig instance valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
GetMyStruct() cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_0,
valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct> V_1)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct>
IL_0009: ldloc.0
IL_000a: stloc.1
IL_000b: br.s IL_000d
IL_000d: ldloc.1
IL_000e: ret
} // end of method NullPropagation::GetMyStruct
.method public hidebysig instance string
Substring() cil managed
{
// Code size 30 (0x1e)
.maxstack 2
.locals init (string V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance string ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetString()
IL_0007: dup
IL_0008: brtrue.s IL_000e
IL_000a: pop
IL_000b: ldnull
IL_000c: br.s IL_0019
IL_000e: ldarg.0
IL_000f: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0014: call instance string [mscorlib]System.String::Substring(int32)
IL_0019: stloc.0
IL_001a: br.s IL_001c
IL_001c: ldloc.0
IL_001d: ret
} // end of method NullPropagation::Substring
.method private hidebysig instance void
Use<T>(!!T t) cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method NullPropagation::Use
.method public hidebysig instance void
RequiredParentheses() cil managed
{
// Code size 56 (0x38)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0007: dup
IL_0008: brtrue.s IL_000e
IL_000a: pop
IL_000b: ldnull
IL_000c: br.s IL_0013
IL_000e: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
IL_0013: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
IL_0018: nop
IL_0019: ldarg.0
IL_001a: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_001f: dup
IL_0020: brtrue.s IL_0026
IL_0022: pop
IL_0023: ldnull
IL_0024: br.s IL_0031
IL_0026: ldarg.0
IL_0027: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_002c: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
IL_0031: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
IL_0036: nop
IL_0037: ret
} // end of method NullPropagation::RequiredParentheses
.method public hidebysig instance valuetype [mscorlib]System.Nullable`1<int32>[]
ChainsOnClass() cil managed
{
// Code size 479 (0x1df)
.maxstack 5
.locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0,
valuetype [mscorlib]System.Nullable`1<int32>[] V_1)
IL_0000: nop
IL_0001: ldc.i4.s 9
IL_0003: newarr valuetype [mscorlib]System.Nullable`1<int32>
IL_0008: dup
IL_0009: ldc.i4.0
IL_000a: ldarg.0
IL_000b: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0010: dup
IL_0011: brtrue.s IL_001f
IL_0013: pop
IL_0014: ldloca.s V_0
IL_0016: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_001c: ldloc.0
IL_001d: br.s IL_0029
IL_001f: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0024: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0029: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_002e: dup
IL_002f: ldc.i4.1
IL_0030: ldarg.0
IL_0031: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0036: dup
IL_0037: brtrue.s IL_0045
IL_0039: pop
IL_003a: ldloca.s V_0
IL_003c: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0042: ldloc.0
IL_0043: br.s IL_0054
IL_0045: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
IL_004a: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_004f: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0054: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0059: dup
IL_005a: ldc.i4.2
IL_005b: ldarg.0
IL_005c: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0061: dup
IL_0062: brtrue.s IL_0070
IL_0064: pop
IL_0065: ldloca.s V_0
IL_0067: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_006d: ldloc.0
IL_006e: br.s IL_008e
IL_0070: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
IL_0075: dup
IL_0076: brtrue.s IL_0084
IL_0078: pop
IL_0079: ldloca.s V_0
IL_007b: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0081: ldloc.0
IL_0082: br.s IL_008e
IL_0084: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0089: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_008e: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0093: dup
IL_0094: ldc.i4.3
IL_0095: ldarg.0
IL_0096: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_009b: dup
IL_009c: brtrue.s IL_00aa
IL_009e: pop
IL_009f: ldloca.s V_0
IL_00a1: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_00a7: ldloc.0
IL_00a8: br.s IL_00b9
IL_00aa: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
IL_00af: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_00b4: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_00b9: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_00be: dup
IL_00bf: ldc.i4.4
IL_00c0: ldarg.0
IL_00c1: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_00c6: dup
IL_00c7: brtrue.s IL_00d5
IL_00c9: pop
IL_00ca: ldloca.s V_0
IL_00cc: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_00d2: ldloc.0
IL_00d3: br.s IL_00f3
IL_00d5: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
IL_00da: dup
IL_00db: brtrue.s IL_00e9
IL_00dd: pop
IL_00de: ldloca.s V_0
IL_00e0: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_00e6: ldloc.0
IL_00e7: br.s IL_00f3
IL_00e9: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_00ee: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_00f3: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_00f8: dup
IL_00f9: ldc.i4.5
IL_00fa: ldarg.0
IL_00fb: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0100: dup
IL_0101: brtrue.s IL_010f
IL_0103: pop
IL_0104: ldloca.s V_0
IL_0106: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_010c: ldloc.0
IL_010d: br.s IL_0124
IL_010f: ldarg.0
IL_0110: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0115: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
IL_011a: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_011f: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0124: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0129: dup
IL_012a: ldc.i4.6
IL_012b: ldarg.0
IL_012c: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0131: dup
IL_0132: brtrue.s IL_0140
IL_0134: pop
IL_0135: ldloca.s V_0
IL_0137: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_013d: ldloc.0
IL_013e: br.s IL_0164
IL_0140: ldarg.0
IL_0141: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0146: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
IL_014b: dup
IL_014c: brtrue.s IL_015a
IL_014e: pop
IL_014f: ldloca.s V_0
IL_0151: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0157: ldloc.0
IL_0158: br.s IL_0164
IL_015a: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_015f: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0164: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_0169: dup
IL_016a: ldc.i4.7
IL_016b: ldarg.0
IL_016c: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0171: dup
IL_0172: brtrue.s IL_0180
IL_0174: pop
IL_0175: ldloca.s V_0
IL_0177: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_017d: ldloc.0
IL_017e: br.s IL_0195
IL_0180: ldarg.0
IL_0181: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_0186: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
IL_018b: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0190: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0195: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_019a: dup
IL_019b: ldc.i4.8
IL_019c: ldarg.0
IL_019d: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_01a2: dup
IL_01a3: brtrue.s IL_01b1
IL_01a5: pop
IL_01a6: ldloca.s V_0
IL_01a8: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_01ae: ldloc.0
IL_01af: br.s IL_01d5
IL_01b1: ldarg.0
IL_01b2: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
IL_01b7: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
IL_01bc: dup
IL_01bd: brtrue.s IL_01cb
IL_01bf: pop
IL_01c0: ldloca.s V_0
IL_01c2: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_01c8: ldloc.0
IL_01c9: br.s IL_01d5
IL_01cb: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_01d0: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_01d5: stelem valuetype [mscorlib]System.Nullable`1<int32>
IL_01da: stloc.1
IL_01db: br.s IL_01dd
IL_01dd: ldloc.1
IL_01de: ret
} // end of method NullPropagation::ChainsOnClass
.method public hidebysig instance int32
CoalescingReturn() cil managed
{
// Code size 24 (0x18)
.maxstack 2
.locals init (int32 V_0)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0007: dup
IL_0008: brtrue.s IL_000e
IL_000a: pop
IL_000b: ldc.i4.1
IL_000c: br.s IL_0013
IL_000e: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0013: stloc.0
IL_0014: br.s IL_0016
IL_0016: ldloc.0
IL_0017: ret
} // end of method NullPropagation::CoalescingReturn
.method public hidebysig instance void
Coalescing() cil managed
{
// Code size 27 (0x1b)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0008: dup
IL_0009: brtrue.s IL_000f
IL_000b: pop
IL_000c: ldc.i4.1
IL_000d: br.s IL_0014
IL_000f: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
IL_0014: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::Use<int32>(!!0)
IL_0019: nop
IL_001a: ret
} // end of method NullPropagation::Coalescing
.method public hidebysig instance void
CoalescingString() cil managed
{
// Code size 36 (0x24)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
IL_0008: dup
IL_0009: brtrue.s IL_000f
IL_000b: pop
IL_000c: ldnull
IL_000d: br.s IL_0014
IL_000f: ldfld string ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Text
IL_0014: dup
IL_0015: brtrue.s IL_001d
IL_0017: pop
IL_0018: ldstr "Hello"
IL_001d: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::Use<string>(!!0)
IL_0022: nop
IL_0023: ret
} // end of method NullPropagation::CoalescingString
.method public hidebysig instance valuetype [mscorlib]System.Nullable`1<int32>
InvokeDelegate(class [mscorlib]System.Func`1<int32> f) cil managed
{
// Code size 31 (0x1f)
.maxstack 1
.locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0,
valuetype [mscorlib]System.Nullable`1<int32> V_1)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: brtrue.s IL_000f
IL_0004: ldloca.s V_0
IL_0006: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_000c: ldloc.0
IL_000d: br.s IL_001a
IL_000f: ldarg.1
IL_0010: callvirt instance !0 class [mscorlib]System.Func`1<int32>::Invoke()
IL_0015: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_001a: stloc.1
IL_001b: br.s IL_001d
IL_001d: ldloc.1
IL_001e: ret
} // end of method NullPropagation::InvokeDelegate
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method NullPropagation::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

7
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -188,7 +188,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -188,7 +188,7 @@ namespace ICSharpCode.Decompiler.CSharp
int allowedParamCount = (method.ReturnType.IsKnownType(KnownTypeCode.Void) ? 1 : 0);
if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || expectedParameters.Count == allowedParamCount)) {
return HandleAccessorCall(expectedTargetDetails, method, target, arguments.ToList());
} else if (method.Name == "Invoke" && method.DeclaringType.Kind == TypeKind.Delegate) {
} else if (method.Name == "Invoke" && method.DeclaringType.Kind == TypeKind.Delegate && !IsNullConditional(target)) {
return new InvocationExpression(target, arguments.Select(arg => arg.Expression)).WithRR(rr);
} else if (IsDelegateEqualityComparison(method, arguments)) {
return HandleDelegateEqualityComparison(method, arguments)
@ -252,6 +252,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -252,6 +252,11 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
static bool IsNullConditional(Expression expr)
{
return expr is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.NullConditional;
}
private void ModifyReturnTypeOfLambda(LambdaExpression lambda)
{
var resolveResult = (DecompiledLambdaResolveResult)lambda.GetResolveResult();

20
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2145,6 +2145,26 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2145,6 +2145,26 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new ResolveResult(inst.GetResultMethod?.ReturnType ?? SpecialType.UnknownType));
}
protected internal override TranslatedExpression VisitNullableRewrap(NullableRewrap inst, TranslationContext context)
{
var arg = Translate(inst.Argument);
IType type = arg.Type;
if (NullableType.IsNonNullableValueType(type)) {
type = NullableType.Create(compilation, type);
}
return new UnaryOperatorExpression(UnaryOperatorType.NullConditionalRewrap, arg)
.WithILInstruction(inst)
.WithRR(new ResolveResult(type));
}
protected internal override TranslatedExpression VisitNullableUnwrap(NullableUnwrap inst, TranslationContext context)
{
var arg = Translate(inst.Argument);
return new UnaryOperatorExpression(UnaryOperatorType.NullConditional, arg)
.WithILInstruction(inst)
.WithRR(new ResolveResult(NullableType.GetUnderlyingType(arg.Type)));
}
protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context)
{
string message = "Error";

2
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -1049,7 +1049,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1049,7 +1049,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType);
if (opType == UnaryOperatorType.Await) {
WriteKeyword(opSymbol);
} else if (!IsPostfixOperator(opType)) {
} else if (!IsPostfixOperator(opType) && opType != UnaryOperatorType.NullConditionalRewrap) {
WriteToken(opSymbol);
}
unaryOperatorExpression.Expression.AcceptVisitor(this);

36
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -36,7 +36,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -36,7 +36,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
/// </summary>
public bool InsertParenthesesForReadability { get; set; }
const int Primary = 16;
const int Primary = 17;
const int NullableRewrap = 16;
const int QueryOrLambda = 15;
const int Unary = 14;
const int RelationalAndTypeTesting = 10;
@ -55,12 +56,17 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -55,12 +56,17 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
// primary expressions get parenthesized.
return QueryOrLambda;
}
UnaryOperatorExpression uoe = expr as UnaryOperatorExpression;
if (uoe != null) {
if (uoe.Operator == UnaryOperatorType.PostDecrement || uoe.Operator == UnaryOperatorType.PostIncrement)
return Primary;
else
return Unary;
if (expr is UnaryOperatorExpression uoe) {
switch (uoe.Operator) {
case UnaryOperatorType.PostDecrement:
case UnaryOperatorType.PostIncrement:
case UnaryOperatorType.NullConditional:
return Primary;
case UnaryOperatorType.NullConditionalRewrap:
return NullableRewrap;
default:
return Unary;
}
}
if (expr is CastExpression)
return Unary;
@ -177,7 +183,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -177,7 +183,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
// Even in readability mode, don't parenthesize casts of casts.
if (!(castExpression.Expression is CastExpression)) {
ParenthesizeIfRequired(castExpression.Expression, InsertParenthesesForReadability ? Primary : Unary);
ParenthesizeIfRequired(castExpression.Expression, InsertParenthesesForReadability ? NullableRewrap : Unary);
}
// There's a nasty issue in the C# grammar: cast expressions including certain operators are ambiguous in some cases
// "(int)-1" is fine, but "(A)-b" is not a cast.
@ -243,11 +249,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -243,11 +249,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
int precedence = GetPrecedence(binaryOperatorExpression);
if (binaryOperatorExpression.Operator == BinaryOperatorType.NullCoalescing) {
if (InsertParenthesesForReadability) {
ParenthesizeIfRequired(binaryOperatorExpression.Left, Primary);
ParenthesizeIfRequired(binaryOperatorExpression.Left, NullableRewrap);
if (GetBinaryOperatorType(binaryOperatorExpression.Right) == BinaryOperatorType.NullCoalescing) {
ParenthesizeIfRequired(binaryOperatorExpression.Right, precedence);
} else {
ParenthesizeIfRequired(binaryOperatorExpression.Right, Primary);
ParenthesizeIfRequired(binaryOperatorExpression.Right, NullableRewrap);
}
} else {
// ?? is right-associative
@ -286,7 +292,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -286,7 +292,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
if (InsertParenthesesForReadability) {
// few people know the precedence of 'is', so always put parentheses in nice-looking mode.
ParenthesizeIfRequired(isExpression.Expression, Primary);
ParenthesizeIfRequired(isExpression.Expression, NullableRewrap);
} else {
ParenthesizeIfRequired(isExpression.Expression, RelationalAndTypeTesting);
}
@ -297,7 +303,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -297,7 +303,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
if (InsertParenthesesForReadability) {
// few people know the precedence of 'as', so always put parentheses in nice-looking mode.
ParenthesizeIfRequired(asExpression.Expression, Primary);
ParenthesizeIfRequired(asExpression.Expression, NullableRewrap);
} else {
ParenthesizeIfRequired(asExpression.Expression, RelationalAndTypeTesting);
}
@ -313,9 +319,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -313,9 +319,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
// Only ((a ? b : c) ? d : e) strictly needs the additional parentheses
if (InsertParenthesesForReadability) {
// Precedence of ?: can be confusing; so always put parentheses in nice-looking mode.
ParenthesizeIfRequired(conditionalExpression.Condition, Primary);
ParenthesizeIfRequired(conditionalExpression.TrueExpression, Primary);
ParenthesizeIfRequired(conditionalExpression.FalseExpression, Primary);
ParenthesizeIfRequired(conditionalExpression.Condition, NullableRewrap);
ParenthesizeIfRequired(conditionalExpression.TrueExpression, NullableRewrap);
ParenthesizeIfRequired(conditionalExpression.FalseExpression, NullableRewrap);
} else {
ParenthesizeIfRequired(conditionalExpression.Condition, Conditional + 1);
ParenthesizeIfRequired(conditionalExpression.TrueExpression, Conditional);

14
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs

@ -116,6 +116,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -116,6 +116,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return AwaitRole;
case UnaryOperatorType.NullConditional:
return NullConditionalRole;
case UnaryOperatorType.NullConditionalRewrap:
return null; // no syntax
default:
throw new NotSupportedException("Invalid value for UnaryOperatorType");
}
@ -181,7 +183,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -181,7 +183,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
Await,
/// <summary>C# 6 null-conditional operator.
/// Occurs as target of member reference or indexer expressions
/// to indicate <c>?.</c> or <c>?[]</c></summary>
NullConditional
/// to indicate <c>?.</c> or <c>?[]</c>.
/// Corresponds to <c>nullable.unwrap</c> in ILAst.
/// </summary>
NullConditional,
/// <summary>
/// Wrapper around a primary expression containing a null conditional operator.
/// Corresponds to <c>nullable.rewrap</c> in ILAst.
/// This has no syntax in C#, but the node is used to ensure parentheses are inserted where necessary.
/// </summary>
NullConditionalRewrap,
}
}

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -133,6 +133,21 @@ namespace ICSharpCode.Decompiler @@ -133,6 +133,21 @@ namespace ICSharpCode.Decompiler
}
}
bool nullPropagation = true;
/// <summary>
/// Decompile C# 6 ?. and ?[] operators.
/// </summary>
public bool NullPropagation {
get { return nullPropagation; }
set {
if (nullPropagation != value) {
nullPropagation = value;
OnPropertyChanged();
}
}
}
bool automaticProperties = true;
/// <summary>

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -294,6 +294,7 @@ @@ -294,6 +294,7 @@
<Compile Include="IL\Transforms\EarlyExpressionTransforms.cs" />
<Compile Include="IL\Transforms\ExpressionTreeCast.cs" />
<Compile Include="IL\Transforms\HighLevelLoopTransform.cs" />
<Compile Include="IL\Transforms\NullPropagationTransform.cs" />
<Compile Include="IL\Transforms\ProxyCallReplacer.cs" />
<Compile Include="IL\Instructions\StringToInt.cs" />
<Compile Include="IL\Instructions\UsingInstruction.cs" />

40
ICSharpCode.Decompiler/IL/Instructions.cs

@ -107,7 +107,7 @@ namespace ICSharpCode.Decompiler.IL @@ -107,7 +107,7 @@ namespace ICSharpCode.Decompiler.IL
/// If the input is null, jumps to the innermost nullable.rewrap instruction that contains this instruction.</summary>
NullableUnwrap,
/// <summary>Serves as jump target for the nullable.unwrap instruction.
/// If the input evaluates normally, evaluates to the input value, wrapped in Nullable<T> if the input is a value type.If a nullable.unwrap encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap evaluates to a null.</summary>
/// If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type).If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap instruction evaluates to null.</summary>
NullableRewrap,
/// <summary>Loads a constant string.</summary>
LdStr,
@ -2523,17 +2523,7 @@ namespace ICSharpCode.Decompiler.IL @@ -2523,17 +2523,7 @@ namespace ICSharpCode.Decompiler.IL
/// If the input is null, jumps to the innermost nullable.rewrap instruction that contains this instruction.</summary>
public sealed partial class NullableUnwrap : UnaryInstruction
{
public NullableUnwrap(ILInstruction argument, IType type) : base(OpCode.NullableUnwrap, argument)
{
this.type = type;
}
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayUnwrapNull;
@ -2543,16 +2533,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2543,16 +2533,6 @@ namespace ICSharpCode.Decompiler.IL
return base.DirectFlags | InstructionFlags.MayUnwrapNull;
}
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
output.Write(OpCode);
output.Write(' ');
type.WriteTo(output);
output.Write('(');
Argument.WriteTo(output, options);
output.Write(')');
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitNullableUnwrap(this);
@ -2568,14 +2548,14 @@ namespace ICSharpCode.Decompiler.IL @@ -2568,14 +2548,14 @@ namespace ICSharpCode.Decompiler.IL
protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
{
var o = other as NullableUnwrap;
return o != null && this.Argument.PerformMatch(o.Argument, ref match) && type.Equals(o.type);
return o != null && this.Argument.PerformMatch(o.Argument, ref match);
}
}
}
namespace ICSharpCode.Decompiler.IL
{
/// <summary>Serves as jump target for the nullable.unwrap instruction.
/// If the input evaluates normally, evaluates to the input value, wrapped in Nullable<T> if the input is a value type.If a nullable.unwrap encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap evaluates to a null.</summary>
/// If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type).If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,the nullable.rewrap instruction evaluates to null.</summary>
public sealed partial class NullableRewrap : UnaryInstruction
{
public NullableRewrap(ILInstruction argument) : base(OpCode.NullableRewrap, argument)
@ -6281,18 +6261,6 @@ namespace ICSharpCode.Decompiler.IL @@ -6281,18 +6261,6 @@ namespace ICSharpCode.Decompiler.IL
right = default(ILInstruction);
return false;
}
public bool MatchNullableUnwrap(out ILInstruction argument, out IType type)
{
var inst = this as NullableUnwrap;
if (inst != null) {
argument = inst.Argument;
type = inst.Type;
return true;
}
argument = default(ILInstruction);
type = default(IType);
return false;
}
public bool MatchNullableRewrap(out ILInstruction argument)
{
var inst = this as NullableRewrap;

9
ICSharpCode.Decompiler/IL/Instructions.tt

@ -163,12 +163,11 @@ @@ -163,12 +163,11 @@
new OpCode("nullable.unwrap", "The input operand must be either a nullable value type or a reference type." + Environment.NewLine
+ "If the input is non-null, evaluates to the (unwrapped) input." + Environment.NewLine
+ "If the input is null, jumps to the innermost nullable.rewrap instruction that contains this instruction.",
Unary, HasTypeOperand, ResultType("type.GetStackType()"),
HasFlag("InstructionFlags.MayUnwrapNull")),
Unary, CustomConstructor, CustomWriteTo, HasFlag("InstructionFlags.MayUnwrapNull")),
new OpCode("nullable.rewrap", "Serves as jump target for the nullable.unwrap instruction." + Environment.NewLine
+ "If the input evaluates normally, evaluates to the input value, wrapped in Nullable<T> if the input is a value type."
+ "If a nullable.unwrap encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,"
+ "the nullable.rewrap evaluates to a null.",
+ "If the input evaluates normally, evaluates to the input value (wrapped in Nullable<T> if the input is a non-nullable value type)."
+ "If a nullable.unwrap instruction encounters a null input and jumps to the (endpoint of the) nullable.rewrap instruction,"
+ "the nullable.rewrap instruction evaluates to null.",
Unary, CustomComputeFlags),
new OpCode("ldstr", "Loads a constant string.",

17
ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs

@ -23,12 +23,29 @@ namespace ICSharpCode.Decompiler.IL @@ -23,12 +23,29 @@ namespace ICSharpCode.Decompiler.IL
{
partial class NullableUnwrap
{
public NullableUnwrap(StackType unwrappedType, ILInstruction argument)
: base(OpCode.NullableUnwrap, argument)
{
this.ResultType = unwrappedType;
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
Debug.Assert(Argument.ResultType == StackType.O, "nullable.unwrap expects nullable type as input");
Debug.Assert(Ancestors.Any(a => a is NullableRewrap));
}
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
output.Write("nullable.unwrap ");
output.Write(ResultType);
output.Write('(');
Argument.WriteTo(output, options);
output.Write(')');
}
public override StackType ResultType { get; }
}
partial class NullableRewrap

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

@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Transform for constructing the NullCoalescingInstruction (if.notnull(a,b), or in C#: ??)
/// Note that this transform only handles the case where a,b are reference types.
///
/// The ?? operator for nullables is handled by NullableLiftingTransform.
/// The ?? operator for nullable value types is handled by NullableLiftingTransform.
/// </summary>
class NullCoalescingTransform : IStatementTransform
{

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

@ -0,0 +1,170 @@ @@ -0,0 +1,170 @@
// Copyright (c) 2018 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Transform that converts code patterns like "v != null ? v.M() : null" to "v?.M()"
/// </summary>
struct NullPropagationTransform
{
readonly ILTransformContext context;
public NullPropagationTransform(ILTransformContext context)
{
this.context = context;
}
/// <summary>
/// Check if "condition ? trueInst : falseInst" can be simplified using the null-conditional operator.
/// Returns the replacement instruction, or null if no replacement is possible.
/// </summary>
internal ILInstruction Run(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst, Interval ilRange)
{
Debug.Assert(context.Settings.NullPropagation);
Debug.Assert(!condition.MatchLogicNot(out _), "Caller should pass in positive condition");
if (condition is Comp comp && comp.Left.MatchLdLoc(out var testedVar) && comp.Right.MatchLdNull()) {
if (comp.LiftingKind != ComparisonLiftingKind.None)
return null;
if (comp.Kind == ComparisonKind.Equality) {
// testedVar == null ? trueInst : falseInst
return TryNullPropagation(testedVar, falseInst, trueInst, true, ilRange);
} else if (comp.Kind == ComparisonKind.Inequality) {
return TryNullPropagation(testedVar, trueInst, falseInst, true, ilRange);
}
} else if (NullableLiftingTransform.MatchHasValueCall(condition, out testedVar)) {
// testedVar.HasValue ? trueInst : falseInst
return TryNullPropagation(testedVar, trueInst, falseInst, false, ilRange);
}
return null;
}
/// <summary>
/// testedVar != null ? nonNullInst : nullInst
/// </summary>
ILInstruction TryNullPropagation(ILVariable testedVar, ILInstruction nonNullInst, ILInstruction nullInst,
bool testedVarHasReferenceType, Interval ilRange)
{
bool removedRewrapOrNullableCtor = false;
if (NullableLiftingTransform.MatchNullableCtor(nonNullInst, out _, out var arg)) {
nonNullInst = arg;
removedRewrapOrNullableCtor = true;
} else if (nonNullInst.MatchNullableRewrap(out arg)) {
nonNullInst = arg;
removedRewrapOrNullableCtor = true;
}
if (!IsValidAccessChain(testedVar, testedVarHasReferenceType, 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();
if (nullInst.MatchLdNull()) {
context.Step("Null propagation (reference type)", nonNullInst);
// testedVar != null ? testedVar.AccessChain : null
// => testedVar?.AccessChain
IntroduceUnwrap(testedVar, varLoad);
return new NullableRewrap(nonNullInst) { ILRange = ilRange };
} else if (nullInst.MatchDefaultValue(out var type) && type.IsKnownType(KnownTypeCode.NullableOfT)) {
context.Step("Null propagation (value type)", nonNullInst);
// testedVar != null ? testedVar.AccessChain : default(T?)
// => testedVar?.AccessChain
IntroduceUnwrap(testedVar, varLoad);
return new NullableRewrap(nonNullInst) { ILRange = ilRange };
} else if (!removedRewrapOrNullableCtor && NullableType.IsNonNullableValueType(returnType)) {
context.Step("Null propagation with null coalescing", nonNullInst);
// testedVar != null ? testedVar.AccessChain : nullInst
// => testedVar?.AccessChain ?? nullInst
// (only valid if AccessChain returns a non-nullable value)
IntroduceUnwrap(testedVar, varLoad);
return new NullCoalescingInstruction(
NullCoalescingKind.NullableWithValueFallback,
new NullableRewrap(nonNullInst),
nullInst
) {
UnderlyingResultType = nullInst.ResultType,
ILRange = ilRange
};
}
return null;
}
bool IsValidAccessChain(ILVariable testedVar, bool testedVarHasReferenceType, ILInstruction inst, out ILInstruction finalLoad)
{
finalLoad = null;
int chainLength = 0;
while (true) {
if (IsValidEndOfChain()) {
// valid end of chain
finalLoad = inst;
return chainLength >= 1;
} else if (inst.MatchLdFld(out var target, out _)) {
inst = target;
} else if (inst is CallInstruction call && call.OpCode != OpCode.NewObj) {
if (call.Arguments.Count == 0) {
return false;
}
if (call.Method.IsStatic && !call.Method.IsExtensionMethod) {
return false; // only instance or extension methods can be called with ?. syntax
}
inst = call.Arguments[0];
// ensure the access chain does not contain any 'nullable.unwrap' that aren't directly part of the chain
for (int i = 1; i < call.Arguments.Count; ++i) {
if (call.Arguments[i].HasFlag(InstructionFlags.MayUnwrapNull)) {
return false;
}
}
} else if (inst is NullableUnwrap unwrap) {
inst = unwrap.Argument;
} else {
// unknown node -> invalid chain
return false;
}
chainLength++;
}
bool IsValidEndOfChain()
{
if (testedVarHasReferenceType) {
return inst.MatchLdLoc(testedVar);
} else {
return NullableLiftingTransform.MatchGetValueOrDefault(inst, testedVar);
}
}
}
private void IntroduceUnwrap(ILVariable testedVar, ILInstruction varLoad)
{
if (NullableLiftingTransform.MatchGetValueOrDefault(varLoad, testedVar)) {
varLoad.ReplaceWith(new NullableUnwrap(
varLoad.ResultType,
new LdLoc(testedVar) { ILRange = varLoad.Children[0].ILRange }
) { ILRange = varLoad.ILRange });
} else {
// Wrap varLoad in nullable.unwrap:
var children = varLoad.Parent.Children;
children[varLoad.ChildIndex] = new NullableUnwrap(testedVar.StackType, varLoad);
}
}
}
}

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

@ -36,6 +36,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -36,6 +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
/// </summary>
struct NullableLiftingTransform
{
@ -55,8 +56,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -55,8 +56,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
public bool Run(IfInstruction ifInst)
{
if (!context.Settings.LiftNullables)
return false;
var lifted = Lift(ifInst, ifInst.TrueInst, ifInst.FalseInst);
if (lifted != null) {
ifInst.ReplaceWith(lifted);
@ -67,8 +66,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -67,8 +66,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public bool RunStatements(Block block, int pos)
{
if (!context.Settings.LiftNullables)
return false;
/// e.g.:
// if (!condition) Block {
// leave IL_0000 (default.value System.Nullable`1[[System.Int64]])
@ -128,6 +125,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -128,6 +125,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
condition = arg;
ExtensionMethods.Swap(ref trueInst, ref falseInst);
}
if (context.Settings.NullPropagation) {
var nullPropagated = new NullPropagationTransform(context)
.Run(condition, trueInst, falseInst, ifInst.ILRange);
if (nullPropagated != null)
return nullPropagated;
}
if (!context.Settings.LiftNullables)
return null;
if (AnalyzeCondition(condition)) {
// (v1 != null && ... && vn != null) ? trueInst : falseInst
// => normal lifting

Loading…
Cancel
Save