diff --git a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
index 27e42e795..4dbda353a 100644
--- a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
@@ -54,6 +54,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)
{
@@ -168,6 +174,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)
{
@@ -255,7 +267,7 @@ namespace ICSharpCode.Decompiler.Tests
try {
outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options,
outputFileName: Path.Combine(TestCasePath, testOutputFileName));
- string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, GetSettings(options));
+ string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options));
decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options);
Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile);
@@ -277,7 +289,7 @@ namespace ICSharpCode.Decompiler.Tests
try {
outputFile = Tester.AssembleIL(Path.Combine(TestCasePath, testFileName), asmOptions);
- string decompiledCodeFile = Tester.DecompileCSharp(outputFile, GetSettings(options));
+ string decompiledCodeFile = Tester.DecompileCSharp(outputFile, Tester.GetSettings(options));
decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options);
Tester.RunAndCompareOutput(testFileName, outputFile, decompiledOutputFile.PathToAssembly, decompiledCodeFile);
@@ -289,15 +301,5 @@ namespace ICSharpCode.Decompiler.Tests
decompiledOutputFile.TempFiles.Delete();
}
}
-
- DecompilerSettings GetSettings(CompilerOptions options)
- {
- if (!options.HasFlag(CompilerOptions.UseRoslyn)) {
- return new DecompilerSettings {
- StringInterpolation = false
- };
- }
- return new DecompilerSettings();
- }
}
}
diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
index feef9b6e3..3d06cbbad 100644
--- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
+++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
@@ -238,6 +238,17 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
}
+ internal static DecompilerSettings GetSettings(CompilerOptions cscOptions)
+ {
+ var settings = new DecompilerSettings();
+ if ((cscOptions & CompilerOptions.UseRoslyn) == 0) {
+ // disable C# features not available in legacy compiler
+ settings.NullPropagation = false;
+ settings.StringInterpolation = false;
+ }
+ return settings;
+ }
+
public static CSharpDecompiler GetDecompilerForSnippet(string csharpText)
{
var syntaxTree = SyntaxFactory.ParseSyntaxTree(csharpText);
diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index b845f188c..6c34c8efb 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -68,11 +68,13 @@
+
+
diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
index 2ee622d48..190924d9d 100644
--- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
@@ -94,7 +94,9 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void ExceptionHandling([ValueSource("defaultOptions")] CompilerOptions cscOptions)
{
- RunForLibrary(cscOptions: cscOptions);
+ RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
+ NullPropagation = false
+ });
}
[Test]
@@ -236,6 +238,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions);
}
+ [Test]
+ public void NullPropagation([ValueSource("roslynOnlyOptions")] CompilerOptions cscOptions)
+ {
+ RunForLibrary(cscOptions: cscOptions);
+ }
+
void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null)
{
Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings);
@@ -265,7 +273,7 @@ namespace ICSharpCode.Decompiler.Tests
}
var executable = Tester.AssembleIL(ilFile, asmOptions);
- var decompiled = Tester.DecompileCSharp(executable, decompilerSettings);
+ var decompiled = Tester.DecompileCSharp(executable, decompilerSettings ?? Tester.GetSettings(cscOptions));
CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray());
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs
new file mode 100644
index 000000000..62e7875ab
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/NullPropagation.cs
@@ -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";
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs
new file mode 100644
index 000000000..17606500d
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs
@@ -0,0 +1,213 @@
+using System;
+
+namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
+{
+ internal class NullPropagation
+ {
+ private class MyClass
+ {
+ public int IntVal;
+ public string Text;
+ public MyClass Field;
+ public MyClass Property {
+ get;
+ set;
+ }
+ public MyClass this[int index] {
+ get {
+ return null;
+ }
+ }
+ public MyClass Method(int arg)
+ {
+ return null;
+ }
+
+ public void Done()
+ {
+ }
+ }
+
+ private struct MyStruct
+ {
+ public int IntVal;
+ public MyClass Field;
+ public MyStruct? Property1 {
+ get {
+ return null;
+ }
+ }
+ public MyStruct Property2 {
+ get {
+ return default(MyStruct);
+ }
+ }
+ public MyStruct? this[int index] {
+ get {
+ return null;
+ }
+ }
+ public MyStruct? Method1(int arg)
+ {
+ return null;
+ }
+ public MyStruct Method2(int arg)
+ {
+ return default(MyStruct);
+ }
+
+ public void Done()
+ {
+ }
+ }
+
+ private int GetInt()
+ {
+ return 9;
+ }
+
+ private string GetString()
+ {
+ return null;
+ }
+
+ private MyClass GetMyClass()
+ {
+ return null;
+ }
+
+ private MyStruct? GetMyStruct()
+ {
+ return null;
+ }
+
+ public string Substring()
+ {
+ return this.GetString()?.Substring(this.GetInt());
+ }
+
+ public void CallSubstringAndIgnoreResult()
+ {
+ this.GetString()?.Substring(this.GetInt());
+ }
+
+ private void Use(T t)
+ {
+ }
+
+ 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(this.GetInt())?.Done();
+ this.GetMyClass()?.Method(this.GetInt()).Done();
+ this.GetMyClass()?[this.GetInt()]?.Done();
+ this.GetMyClass()?[this.GetInt()].Done();
+ }
+
+ public void CallDoneStruct()
+ {
+ this.GetMyStruct()?.Done();
+#if STRUCT_SPLITTING_IMPROVED
+ this.GetMyStruct()?.Field?.Done();
+ this.GetMyStruct()?.Field.Done();
+ this.GetMyStruct()?.Property1?.Done();
+ this.GetMyStruct()?.Property2.Done();
+ this.GetMyStruct()?.Method1(this.GetInt())?.Done();
+ this.GetMyStruct()?.Method2(this.GetInt()).Done();
+ this.GetMyStruct()?[this.GetInt()]?.Done();
+#endif
+ }
+
+ public void RequiredParentheses()
+ {
+ (this.GetMyClass()?.Field).Done();
+ (this.GetMyClass()?.Method(this.GetInt())).Done();
+#if STRUCT_SPLITTING_IMPROVED
+ (GetMyStruct()?.Property2)?.Done();
+#endif
+ }
+
+ 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?[] ChainsStruct()
+ {
+ return new int?[8] {
+ 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
+
+ public int CoalescingReturn()
+ {
+ return this.GetMyClass()?.IntVal ?? 1;
+ }
+
+ public void Coalescing()
+ {
+ this.Use(this.GetMyClass()?.IntVal ?? 1);
+ }
+
+ public void CoalescingString()
+ {
+ this.Use(this.GetMyClass()?.Text ?? "Hello");
+ }
+
+ public void InvokeDelegate(EventHandler eh)
+ {
+ eh?.Invoke(null, EventArgs.Empty);
+ }
+
+ public int? InvokeDelegate(Func f)
+ {
+ 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");
+ }
+
+ private void Setter(MyClass c)
+ {
+ if (c != null) {
+ c.IntVal = 1;
+ }
+ Console.WriteLine();
+ if (c != null) {
+ c.Property = null;
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il
new file mode 100644
index 000000000..38bb4cd34
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.opt.roslyn.il
@@ -0,0 +1,863 @@
+
+// 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: {DDAB2C82-C901-450A-B55D-2D0D7BC34C48}
+.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: 0x003E0000
+
+
+// =============== 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 '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::'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::'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
+ get_Property1() cil managed
+ {
+ // Code size 10 (0xa)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0)
+ IL_0000: ldloca.s V_0
+ IL_0002: initobj valuetype [mscorlib]System.Nullable`1
+ 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
+ get_Item(int32 index) cil managed
+ {
+ // Code size 10 (0xa)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0)
+ IL_0000: ldloca.s V_0
+ IL_0002: initobj valuetype [mscorlib]System.Nullable`1
+ IL_0008: ldloc.0
+ IL_0009: ret
+ } // end of method MyStruct::get_Item
+
+ .method public hidebysig instance valuetype [mscorlib]System.Nullable`1
+ Method1(int32 arg) cil managed
+ {
+ // Code size 10 (0xa)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0)
+ IL_0000: ldloca.s V_0
+ IL_0002: initobj valuetype [mscorlib]System.Nullable`1
+ 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
+ Property1()
+ {
+ .get instance valuetype [mscorlib]System.Nullable`1 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
+ Item(int32)
+ {
+ .get instance valuetype [mscorlib]System.Nullable`1 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
+ GetMyStruct() cil managed
+ {
+ // Code size 10 (0xa)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0)
+ IL_0000: ldloca.s V_0
+ IL_0002: initobj valuetype [mscorlib]System.Nullable`1
+ 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 public hidebysig instance void
+ CallSubstringAndIgnoreResult() 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_000b
+
+ IL_0009: pop
+ IL_000a: ret
+
+ IL_000b: ldarg.0
+ IL_000c: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_0011: call instance string [mscorlib]System.String::Substring(int32)
+ IL_0016: pop
+ IL_0017: ret
+ } // end of method NullPropagation::CallSubstringAndIgnoreResult
+
+ .method private hidebysig instance void
+ Use(!!T t) cil managed
+ {
+ // Code size 1 (0x1)
+ .maxstack 8
+ IL_0000: ret
+ } // end of method NullPropagation::Use
+
+ .method public hidebysig instance void
+ CallDone() cil managed
+ {
+ // Code size 241 (0xf1)
+ .maxstack 2
+ 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: br.s IL_0011
+
+ IL_000c: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_0011: ldarg.0
+ IL_0012: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_0017: dup
+ IL_0018: brtrue.s IL_001d
+
+ IL_001a: pop
+ IL_001b: br.s IL_002d
+
+ IL_001d: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
+ IL_0022: dup
+ IL_0023: brtrue.s IL_0028
+
+ IL_0025: pop
+ IL_0026: br.s IL_002d
+
+ IL_0028: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_002d: ldarg.0
+ IL_002e: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_0033: dup
+ IL_0034: brtrue.s IL_0039
+
+ IL_0036: pop
+ IL_0037: br.s IL_0043
+
+ IL_0039: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
+ IL_003e: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_0043: ldarg.0
+ IL_0044: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_0049: dup
+ IL_004a: brtrue.s IL_004f
+
+ IL_004c: pop
+ IL_004d: br.s IL_005f
+
+ IL_004f: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
+ IL_0054: dup
+ IL_0055: brtrue.s IL_005a
+
+ IL_0057: pop
+ IL_0058: br.s IL_005f
+
+ IL_005a: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_005f: ldarg.0
+ IL_0060: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_0065: dup
+ IL_0066: brtrue.s IL_006b
+
+ IL_0068: pop
+ IL_0069: br.s IL_0075
+
+ IL_006b: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
+ IL_0070: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_0075: ldarg.0
+ IL_0076: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_007b: dup
+ IL_007c: brtrue.s IL_0081
+
+ IL_007e: pop
+ IL_007f: br.s IL_0097
+
+ IL_0081: ldarg.0
+ IL_0082: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_0087: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
+ IL_008c: dup
+ IL_008d: brtrue.s IL_0092
+
+ IL_008f: pop
+ IL_0090: br.s IL_0097
+
+ IL_0092: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_0097: ldarg.0
+ IL_0098: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_009d: dup
+ IL_009e: brtrue.s IL_00a3
+
+ IL_00a0: pop
+ IL_00a1: br.s IL_00b3
+
+ IL_00a3: ldarg.0
+ IL_00a4: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_00a9: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
+ IL_00ae: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_00b3: ldarg.0
+ IL_00b4: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_00b9: dup
+ IL_00ba: brtrue.s IL_00bf
+
+ IL_00bc: pop
+ IL_00bd: br.s IL_00d5
+
+ IL_00bf: ldarg.0
+ IL_00c0: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_00c5: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
+ IL_00ca: dup
+ IL_00cb: brtrue.s IL_00d0
+
+ IL_00cd: pop
+ IL_00ce: br.s IL_00d5
+
+ IL_00d0: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_00d5: ldarg.0
+ IL_00d6: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_00db: dup
+ IL_00dc: brtrue.s IL_00e0
+
+ IL_00de: pop
+ IL_00df: ret
+
+ IL_00e0: ldarg.0
+ IL_00e1: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_00e6: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
+ IL_00eb: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_00f0: ret
+ } // end of method NullPropagation::CallDone
+
+ .method public hidebysig instance void
+ CallDoneStruct() cil managed
+ {
+ // Code size 33 (0x21)
+ .maxstack 2
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_1)
+ IL_0000: ldarg.0
+ IL_0001: call instance valuetype [mscorlib]System.Nullable`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyStruct()
+ IL_0006: stloc.0
+ IL_0007: ldloca.s V_0
+ IL_0009: dup
+ IL_000a: call instance bool valuetype [mscorlib]System.Nullable`1::get_HasValue()
+ IL_000f: brtrue.s IL_0013
+
+ IL_0011: pop
+ IL_0012: ret
+
+ IL_0013: call instance !0 valuetype [mscorlib]System.Nullable`1::GetValueOrDefault()
+ IL_0018: stloc.1
+ IL_0019: ldloca.s V_1
+ IL_001b: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::Done()
+ IL_0020: ret
+ } // end of method NullPropagation::CallDoneStruct
+
+ .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[]
+ ChainsOnClass() cil managed
+ {
+ // Code size 474 (0x1da)
+ .maxstack 5
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0)
+ IL_0000: ldc.i4.s 9
+ IL_0002: newarr valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0028: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0053: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_008d: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_00b8: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_00f2: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0123: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_0163: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0194: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_01d4: stelem valuetype [mscorlib]System.Nullable`1
+ 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(!!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(!!0)
+ IL_0021: ret
+ } // end of method NullPropagation::CoalescingString
+
+ .method public hidebysig instance void
+ InvokeDelegate(class [mscorlib]System.EventHandler eh) cil managed
+ {
+ // Code size 16 (0x10)
+ .maxstack 8
+ IL_0000: ldarg.1
+ IL_0001: brfalse.s IL_000f
+
+ IL_0003: ldarg.1
+ IL_0004: ldnull
+ IL_0005: ldsfld class [mscorlib]System.EventArgs [mscorlib]System.EventArgs::Empty
+ IL_000a: callvirt instance void [mscorlib]System.EventHandler::Invoke(object,
+ class [mscorlib]System.EventArgs)
+ IL_000f: ret
+ } // end of method NullPropagation::InvokeDelegate
+
+ .method public hidebysig instance valuetype [mscorlib]System.Nullable`1
+ InvokeDelegate(class [mscorlib]System.Func`1 f) cil managed
+ {
+ // Code size 25 (0x19)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 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
+ IL_000b: ldloc.0
+ IL_000c: ret
+
+ IL_000d: ldarg.1
+ IL_000e: callvirt instance !0 class [mscorlib]System.Func`1::Invoke()
+ IL_0013: newobj instance void valuetype [mscorlib]System.Nullable`1::.ctor(!0)
+ 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 private hidebysig instance void
+ Setter(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass c) cil managed
+ {
+ // Code size 26 (0x1a)
+ .maxstack 8
+ IL_0000: ldarg.1
+ IL_0001: brfalse.s IL_000a
+
+ IL_0003: ldarg.1
+ IL_0004: ldc.i4.1
+ IL_0005: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
+ IL_000a: call void [mscorlib]System.Console::WriteLine()
+ IL_000f: ldarg.1
+ IL_0010: brfalse.s IL_0019
+
+ IL_0012: ldarg.1
+ IL_0013: ldnull
+ IL_0014: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::set_Property(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass)
+ IL_0019: ret
+ } // end of method NullPropagation::Setter
+
+ .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 ***********************
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il
new file mode 100644
index 000000000..1d717edd7
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.roslyn.il
@@ -0,0 +1,1024 @@
+
+// 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: {252A7D2B-A310-4825-9B38-400B4B7D3296}
+.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: 0x03130000
+
+
+// =============== 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 '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::'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::'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
+ get_Property1() cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype [mscorlib]System.Nullable`1 V_1)
+ IL_0000: nop
+ IL_0001: ldloca.s V_0
+ IL_0003: initobj valuetype [mscorlib]System.Nullable`1
+ 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
+ get_Item(int32 index) cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype [mscorlib]System.Nullable`1 V_1)
+ IL_0000: nop
+ IL_0001: ldloca.s V_0
+ IL_0003: initobj valuetype [mscorlib]System.Nullable`1
+ 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
+ Method1(int32 arg) cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype [mscorlib]System.Nullable`1 V_1)
+ IL_0000: nop
+ IL_0001: ldloca.s V_0
+ IL_0003: initobj valuetype [mscorlib]System.Nullable`1
+ 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
+ Property1()
+ {
+ .get instance valuetype [mscorlib]System.Nullable`1 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
+ Item(int32)
+ {
+ .get instance valuetype [mscorlib]System.Nullable`1 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
+ GetMyStruct() cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype [mscorlib]System.Nullable`1 V_1)
+ IL_0000: nop
+ IL_0001: ldloca.s V_0
+ IL_0003: initobj valuetype [mscorlib]System.Nullable`1
+ 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 public hidebysig instance void
+ CallSubstringAndIgnoreResult() cil managed
+ {
+ // Code size 26 (0x1a)
+ .maxstack 8
+ 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_000d
+
+ IL_000a: pop
+ IL_000b: br.s IL_0019
+
+ IL_000d: ldarg.0
+ IL_000e: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_0013: call instance string [mscorlib]System.String::Substring(int32)
+ IL_0018: pop
+ IL_0019: ret
+ } // end of method NullPropagation::CallSubstringAndIgnoreResult
+
+ .method private hidebysig instance void
+ Use(!!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
+ CallDone() cil managed
+ {
+ // Code size 252 (0xfc)
+ .maxstack 2
+ 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_000d
+
+ IL_000a: pop
+ IL_000b: br.s IL_0013
+
+ IL_000d: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_0012: nop
+ IL_0013: ldarg.0
+ IL_0014: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_0019: dup
+ IL_001a: brtrue.s IL_001f
+
+ IL_001c: pop
+ IL_001d: br.s IL_0030
+
+ IL_001f: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
+ IL_0024: dup
+ IL_0025: brtrue.s IL_002a
+
+ IL_0027: pop
+ IL_0028: br.s IL_0030
+
+ IL_002a: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_002f: nop
+ 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_003c
+
+ IL_0039: pop
+ IL_003a: br.s IL_0047
+
+ IL_003c: ldfld class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Field
+ IL_0041: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_0046: nop
+ IL_0047: ldarg.0
+ IL_0048: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_004d: dup
+ IL_004e: brtrue.s IL_0053
+
+ IL_0050: pop
+ IL_0051: br.s IL_0064
+
+ IL_0053: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
+ IL_0058: dup
+ IL_0059: brtrue.s IL_005e
+
+ IL_005b: pop
+ IL_005c: br.s IL_0064
+
+ IL_005e: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_0063: nop
+ IL_0064: ldarg.0
+ IL_0065: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_006a: dup
+ IL_006b: brtrue.s IL_0070
+
+ IL_006d: pop
+ IL_006e: br.s IL_007b
+
+ IL_0070: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Property()
+ IL_0075: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_007a: nop
+ IL_007b: ldarg.0
+ IL_007c: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_0081: dup
+ IL_0082: brtrue.s IL_0087
+
+ IL_0084: pop
+ IL_0085: br.s IL_009e
+
+ IL_0087: ldarg.0
+ IL_0088: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_008d: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
+ IL_0092: dup
+ IL_0093: brtrue.s IL_0098
+
+ IL_0095: pop
+ IL_0096: br.s IL_009e
+
+ IL_0098: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_009d: nop
+ IL_009e: ldarg.0
+ IL_009f: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_00a4: dup
+ IL_00a5: brtrue.s IL_00aa
+
+ IL_00a7: pop
+ IL_00a8: br.s IL_00bb
+
+ IL_00aa: ldarg.0
+ IL_00ab: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_00b0: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Method(int32)
+ IL_00b5: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_00ba: nop
+ IL_00bb: ldarg.0
+ IL_00bc: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_00c1: dup
+ IL_00c2: brtrue.s IL_00c7
+
+ IL_00c4: pop
+ IL_00c5: br.s IL_00de
+
+ IL_00c7: ldarg.0
+ IL_00c8: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_00cd: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
+ IL_00d2: dup
+ IL_00d3: brtrue.s IL_00d8
+
+ IL_00d5: pop
+ IL_00d6: br.s IL_00de
+
+ IL_00d8: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_00dd: nop
+ IL_00de: ldarg.0
+ IL_00df: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyClass()
+ IL_00e4: dup
+ IL_00e5: brtrue.s IL_00ea
+
+ IL_00e7: pop
+ IL_00e8: br.s IL_00fb
+
+ IL_00ea: ldarg.0
+ IL_00eb: call instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetInt()
+ IL_00f0: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::get_Item(int32)
+ IL_00f5: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::Done()
+ IL_00fa: nop
+ IL_00fb: ret
+ } // end of method NullPropagation::CallDone
+
+ .method public hidebysig instance void
+ CallDoneStruct() cil managed
+ {
+ // Code size 36 (0x24)
+ .maxstack 2
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct V_1)
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: call instance valuetype [mscorlib]System.Nullable`1 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation::GetMyStruct()
+ IL_0007: stloc.0
+ IL_0008: ldloca.s V_0
+ IL_000a: dup
+ IL_000b: call instance bool valuetype [mscorlib]System.Nullable`1::get_HasValue()
+ IL_0010: brtrue.s IL_0015
+
+ IL_0012: pop
+ IL_0013: br.s IL_0023
+
+ IL_0015: call instance !0 valuetype [mscorlib]System.Nullable`1::GetValueOrDefault()
+ IL_001a: stloc.1
+ IL_001b: ldloca.s V_1
+ IL_001d: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyStruct::Done()
+ IL_0022: nop
+ IL_0023: ret
+ } // end of method NullPropagation::CallDoneStruct
+
+ .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[]
+ ChainsOnClass() cil managed
+ {
+ // Code size 479 (0x1df)
+ .maxstack 5
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype [mscorlib]System.Nullable`1[] V_1)
+ IL_0000: nop
+ IL_0001: ldc.i4.s 9
+ IL_0003: newarr valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0029: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0054: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_008e: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_00b9: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_00f3: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0124: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_0164: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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::.ctor(!0)
+ IL_0195: stelem valuetype [mscorlib]System.Nullable`1
+ 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
+ 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
+ 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::.ctor(!0)
+ IL_01d5: stelem valuetype [mscorlib]System.Nullable`1
+ 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(!!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(!!0)
+ IL_0022: nop
+ IL_0023: ret
+ } // end of method NullPropagation::CoalescingString
+
+ .method public hidebysig instance void
+ InvokeDelegate(class [mscorlib]System.EventHandler eh) cil managed
+ {
+ // Code size 20 (0x14)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: brtrue.s IL_0006
+
+ IL_0004: br.s IL_0013
+
+ IL_0006: ldarg.1
+ IL_0007: ldnull
+ IL_0008: ldsfld class [mscorlib]System.EventArgs [mscorlib]System.EventArgs::Empty
+ IL_000d: callvirt instance void [mscorlib]System.EventHandler::Invoke(object,
+ class [mscorlib]System.EventArgs)
+ IL_0012: nop
+ IL_0013: ret
+ } // end of method NullPropagation::InvokeDelegate
+
+ .method public hidebysig instance valuetype [mscorlib]System.Nullable`1
+ InvokeDelegate(class [mscorlib]System.Func`1 f) cil managed
+ {
+ // Code size 31 (0x1f)
+ .maxstack 1
+ .locals init (valuetype [mscorlib]System.Nullable`1 V_0,
+ valuetype [mscorlib]System.Nullable`1 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
+ IL_000c: ldloc.0
+ IL_000d: br.s IL_001a
+
+ IL_000f: ldarg.1
+ IL_0010: callvirt instance !0 class [mscorlib]System.Func`1::Invoke()
+ IL_0015: newobj instance void valuetype [mscorlib]System.Nullable`1::.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 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 private hidebysig instance void
+ Setter(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass c) cil managed
+ {
+ // Code size 43 (0x2b)
+ .maxstack 2
+ .locals init (bool V_0,
+ bool V_1)
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: ldnull
+ IL_0003: cgt.un
+ IL_0005: stloc.0
+ IL_0006: ldloc.0
+ IL_0007: brfalse.s IL_0012
+
+ IL_0009: nop
+ IL_000a: ldarg.1
+ IL_000b: ldc.i4.1
+ IL_000c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::IntVal
+ IL_0011: nop
+ IL_0012: call void [mscorlib]System.Console::WriteLine()
+ IL_0017: nop
+ IL_0018: ldarg.1
+ IL_0019: ldnull
+ IL_001a: cgt.un
+ IL_001c: stloc.1
+ IL_001d: ldloc.1
+ IL_001e: brfalse.s IL_002a
+
+ IL_0020: nop
+ IL_0021: ldarg.1
+ IL_0022: ldnull
+ IL_0023: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass::set_Property(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.NullPropagation/MyClass)
+ IL_0028: nop
+ IL_0029: nop
+ IL_002a: ret
+ } // end of method NullPropagation::Setter
+
+ .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 ***********************
diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index 85327455d..94355e7e2 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -127,6 +127,7 @@ namespace ICSharpCode.Decompiler.CSharp
new TransformAssignment(), // inline and compound assignments
new NullCoalescingTransform(),
new NullableLiftingStatementTransform(),
+ new NullPropagationStatementTransform(),
new TransformArrayInitializers(),
new TransformCollectionAndObjectInitializers(),
new TransformExpressionTrees()
diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
index 88417af5f..e9fd4f5ec 100644
--- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
@@ -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
}
}
+ static bool IsNullConditional(Expression expr)
+ {
+ return expr is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.NullConditional;
+ }
+
private void ModifyReturnTypeOfLambda(LambdaExpression lambda)
{
var resolveResult = (DecompiledLambdaResolveResult)lambda.GetResolveResult();
diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
index 035859733..08399a7e3 100644
--- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
@@ -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";
diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
index f3f08646b..f6e7cf54b 100644
--- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
+++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
@@ -1085,16 +1085,23 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
var opSymbol = UnaryOperatorExpression.GetOperatorRole(opType);
if (opType == UnaryOperatorType.Await) {
WriteKeyword(opSymbol);
- } else if (!(opType == UnaryOperatorType.PostIncrement || opType == UnaryOperatorType.PostDecrement)) {
+ } else if (!IsPostfixOperator(opType) && opType != UnaryOperatorType.NullConditionalRewrap) {
WriteToken(opSymbol);
}
unaryOperatorExpression.Expression.AcceptVisitor(this);
- if (opType == UnaryOperatorType.PostIncrement || opType == UnaryOperatorType.PostDecrement) {
+ if (IsPostfixOperator(opType)) {
WriteToken(opSymbol);
}
EndNode(unaryOperatorExpression);
}
+ static bool IsPostfixOperator(UnaryOperatorType op)
+ {
+ return op == UnaryOperatorType.PostIncrement
+ || op == UnaryOperatorType.PostDecrement
+ || op == UnaryOperatorType.NullConditional;
+ }
+
public virtual void VisitUncheckedExpression(UncheckedExpression uncheckedExpression)
{
StartNode(uncheckedExpression);
diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
index 0e4068958..7d2345283 100644
--- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
+++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
@@ -36,7 +36,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
///
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
// 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
{
// 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
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
{
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
{
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
// 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);
diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs
index 5bc91eb76..551ba610c 100644
--- a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs
+++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UnaryOperatorExpression.cs
@@ -43,6 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public readonly static TokenRole DereferenceRole = new TokenRole ("*");
public readonly static TokenRole AddressOfRole = new TokenRole ("&");
public readonly static TokenRole AwaitRole = new TokenRole ("await");
+ public readonly static TokenRole NullConditionalRole = new TokenRole ("?");
public UnaryOperatorExpression()
{
@@ -63,9 +64,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return GetChildByRole (GetOperatorRole (Operator)); }
}
- static Expression NoUnaryExpressionError = new ErrorExpression ("No unary expression");
public Expression Expression {
- get { return GetChildByRole (Roles.Expression) ?? NoUnaryExpressionError; }
+ get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); }
}
@@ -114,6 +114,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return AddressOfRole;
case UnaryOperatorType.Await:
return AwaitRole;
+ case UnaryOperatorType.NullConditional:
+ return NullConditionalRole;
+ case UnaryOperatorType.NullConditionalRewrap:
+ return null; // no syntax
default:
throw new NotSupportedException("Invalid value for UnaryOperatorType");
}
@@ -176,6 +180,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Get address (&a)
AddressOf,
/// C# 5.0 await
- Await
+ Await,
+ /// C# 6 null-conditional operator.
+ /// Occurs as target of member reference or indexer expressions
+ /// to indicate ?. or ?[].
+ /// Corresponds to nullable.unwrap in ILAst.
+ ///
+ NullConditional,
+ ///
+ /// Wrapper around a primary expression containing a null conditional operator.
+ /// Corresponds to nullable.rewrap in ILAst.
+ /// This has no syntax in C#, but the node is used to ensure parentheses are inserted where necessary.
+ ///
+ NullConditionalRewrap,
}
}
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
index 355447889..d2c6462b5 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
@@ -186,6 +186,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
case UnaryOperatorType.Decrement:
case UnaryOperatorType.Await:
return true;
+ case UnaryOperatorType.NullConditionalRewrap:
+ return IsValidInStatementExpression(uoe.Expression);
default:
return false;
}
diff --git a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
index 0f10a46ed..429f9fc89 100644
--- a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
+++ b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
@@ -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;
diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs
index 990c4b7a9..cc729a824 100644
--- a/ICSharpCode.Decompiler/DecompilerSettings.cs
+++ b/ICSharpCode.Decompiler/DecompilerSettings.cs
@@ -133,6 +133,21 @@ namespace ICSharpCode.Decompiler
}
}
+ bool nullPropagation = true;
+
+ ///
+ /// Decompile C# 6 ?. and ?[] operators.
+ ///
+ public bool NullPropagation {
+ get { return nullPropagation; }
+ set {
+ if (nullPropagation != value) {
+ nullPropagation = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+
bool automaticProperties = true;
///
diff --git a/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs b/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs
index 034e33798..24075c83d 100644
--- a/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs
+++ b/ICSharpCode.Decompiler/FlowAnalysis/DataFlowVisitor.cs
@@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
///
/// Derived classes may add to this set of flags to ensure they don't forget to override an interesting method.
///
- protected InstructionFlags flagsRequiringManualImpl = InstructionFlags.ControlFlow | InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
+ protected InstructionFlags flagsRequiringManualImpl = InstructionFlags.ControlFlow | InstructionFlags.MayBranch | InstructionFlags.MayUnwrapNull | InstructionFlags.EndPointUnreachable;
protected sealed override void Default(ILInstruction inst)
{
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index f292e443e..c9c769e62 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -287,6 +287,7 @@
+
@@ -294,6 +295,7 @@
+
diff --git a/ICSharpCode.Decompiler/IL/InstructionFlags.cs b/ICSharpCode.Decompiler/IL/InstructionFlags.cs
index 6c0894643..1fcd6ee6d 100644
--- a/ICSharpCode.Decompiler/IL/InstructionFlags.cs
+++ b/ICSharpCode.Decompiler/IL/InstructionFlags.cs
@@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.IL
///
/// The instruction may read from local variables.
///
- MayReadLocals = 0x10,
+ MayReadLocals = 0x10,
///
/// The instruction may write to local variables.
///
@@ -51,17 +51,21 @@ namespace ICSharpCode.Decompiler.IL
///
MayThrow = 0x100,
///
- /// The instruction may exit with a branch or return.
+ /// The instruction may exit with a branch or leave.
///
MayBranch = 0x200,
///
+ /// The instruction may jump to the closest containing nullable.rewrap instruction.
+ ///
+ MayUnwrapNull = 0x400,
+ ///
/// The instruction performs unconditional control flow, so that its endpoint is unreachable.
///
///
/// If EndPointUnreachable is set, either MayThrow or MayBranch should also be set
/// (unless the instruction represents an infinite loop).
///
- EndPointUnreachable = 0x400,
+ EndPointUnreachable = 0x800,
///
/// The instruction contains some kind of internal control flow.
///
@@ -72,6 +76,6 @@ namespace ICSharpCode.Decompiler.IL
/// Note that branch instructions don't have this flag set, because their control flow is not internal
/// (and they don't have any unusual argument evaluation rules).
///
- ControlFlow = 0x800,
+ ControlFlow = 0x1000,
}
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs
index 92e43d040..126b4db66 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions.cs
@@ -102,6 +102,13 @@ namespace ICSharpCode.Decompiler.IL
ThreeValuedLogicAnd,
/// Three valued logic or. Inputs are of type bool? or I4, output is of type bool?. Unlike logic.or(), does not have short-circuiting behavior.
ThreeValuedLogicOr,
+ /// The input operand must be either a nullable value type or a reference type.
+ /// If the input is non-null, evaluates to the (unwrapped) input.
+ /// If the input is null, jumps to the innermost nullable.rewrap instruction that contains this instruction.
+ NullableUnwrap,
+ /// Serves as jump target for the nullable.unwrap instruction.
+ /// If the input evaluates normally, evaluates to the input value (wrapped in Nullable 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.
+ NullableRewrap,
/// Loads a constant string.
LdStr,
/// Loads a constant 32-bit integer.
@@ -2510,6 +2517,71 @@ namespace ICSharpCode.Decompiler.IL
}
}
namespace ICSharpCode.Decompiler.IL
+{
+ /// The input operand must be either a nullable value type or a reference type.
+ /// If the input is non-null, evaluates to the (unwrapped) input.
+ /// If the input is null, jumps to the innermost nullable.rewrap instruction that contains this instruction.
+ public sealed partial class NullableUnwrap : UnaryInstruction
+ {
+
+ protected override InstructionFlags ComputeFlags()
+ {
+ return base.ComputeFlags() | InstructionFlags.MayUnwrapNull;
+ }
+ public override InstructionFlags DirectFlags {
+ get {
+ return base.DirectFlags | InstructionFlags.MayUnwrapNull;
+ }
+ }
+ public override void AcceptVisitor(ILVisitor visitor)
+ {
+ visitor.VisitNullableUnwrap(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor)
+ {
+ return visitor.VisitNullableUnwrap(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor, C context)
+ {
+ return visitor.VisitNullableUnwrap(this, context);
+ }
+ 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);
+ }
+ }
+}
+namespace ICSharpCode.Decompiler.IL
+{
+ /// Serves as jump target for the nullable.unwrap instruction.
+ /// If the input evaluates normally, evaluates to the input value (wrapped in Nullable 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.
+ public sealed partial class NullableRewrap : UnaryInstruction
+ {
+ public NullableRewrap(ILInstruction argument) : base(OpCode.NullableRewrap, argument)
+ {
+ }
+
+ public override void AcceptVisitor(ILVisitor visitor)
+ {
+ visitor.VisitNullableRewrap(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor)
+ {
+ return visitor.VisitNullableRewrap(this);
+ }
+ public override T AcceptVisitor(ILVisitor visitor, C context)
+ {
+ return visitor.VisitNullableRewrap(this, context);
+ }
+ protected internal override bool PerformMatch(ILInstruction other, ref Patterns.Match match)
+ {
+ var o = other as NullableRewrap;
+ return o != null && this.Argument.PerformMatch(o.Argument, ref match);
+ }
+ }
+}
+namespace ICSharpCode.Decompiler.IL
{
/// Loads a constant string.
public sealed partial class LdStr : SimpleInstruction
@@ -5131,6 +5203,14 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
+ protected internal virtual void VisitNullableUnwrap(NullableUnwrap inst)
+ {
+ Default(inst);
+ }
+ protected internal virtual void VisitNullableRewrap(NullableRewrap inst)
+ {
+ Default(inst);
+ }
protected internal virtual void VisitLdStr(LdStr inst)
{
Default(inst);
@@ -5441,6 +5521,14 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
+ protected internal virtual T VisitNullableUnwrap(NullableUnwrap inst)
+ {
+ return Default(inst);
+ }
+ protected internal virtual T VisitNullableRewrap(NullableRewrap inst)
+ {
+ return Default(inst);
+ }
protected internal virtual T VisitLdStr(LdStr inst)
{
return Default(inst);
@@ -5751,6 +5839,14 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst, context);
}
+ protected internal virtual T VisitNullableUnwrap(NullableUnwrap inst, C context)
+ {
+ return Default(inst, context);
+ }
+ protected internal virtual T VisitNullableRewrap(NullableRewrap inst, C context)
+ {
+ return Default(inst, context);
+ }
protected internal virtual T VisitLdStr(LdStr inst, C context)
{
return Default(inst, context);
@@ -5948,6 +6044,8 @@ namespace ICSharpCode.Decompiler.IL
"addressof",
"3vl.logic.and",
"3vl.logic.or",
+ "nullable.unwrap",
+ "nullable.rewrap",
"ldstr",
"ldc.i4",
"ldc.i8",
@@ -6163,6 +6261,16 @@ namespace ICSharpCode.Decompiler.IL
right = default(ILInstruction);
return false;
}
+ public bool MatchNullableRewrap(out ILInstruction argument)
+ {
+ var inst = this as NullableRewrap;
+ if (inst != null) {
+ argument = inst.Argument;
+ return true;
+ }
+ argument = default(ILInstruction);
+ return false;
+ }
public bool MatchLdStr(out string value)
{
var inst = this as LdStr;
diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt
index c02784833..0362a1e91 100644
--- a/ICSharpCode.Decompiler/IL/Instructions.tt
+++ b/ICSharpCode.Decompiler/IL/Instructions.tt
@@ -160,6 +160,15 @@
CustomClassName("ThreeValuedLogicAnd"), Binary, ResultType("O")),
new OpCode("3vl.logic.or", "Three valued logic or. Inputs are of type bool? or I4, output is of type bool?. Unlike logic.or(), does not have short-circuiting behavior.",
CustomClassName("ThreeValuedLogicOr"), Binary, ResultType("O")),
+ 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, 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 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.",
CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")),
diff --git a/ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
index 93fe7bae3..5926dfdd0 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
@@ -56,12 +56,17 @@ namespace ICSharpCode.Decompiler.IL
{
base.CheckInvariant(phase);
Debug.Assert(condition.ResultType == StackType.I4);
- Debug.Assert(trueInst.ResultType == falseInst.ResultType);
+ Debug.Assert(trueInst.ResultType == falseInst.ResultType
+ || trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable)
+ || falseInst.HasDirectFlag(InstructionFlags.EndPointUnreachable));
}
public override StackType ResultType {
get {
- return trueInst.ResultType;
+ if (trueInst.HasDirectFlag(InstructionFlags.EndPointUnreachable))
+ return falseInst.ResultType;
+ else
+ return trueInst.ResultType;
}
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs b/ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs
new file mode 100644
index 000000000..ef12373ea
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs
@@ -0,0 +1,79 @@
+// 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.Diagnostics;
+using System.Linq;
+
+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
+ {
+ internal override void CheckInvariant(ILPhase phase)
+ {
+ base.CheckInvariant(phase);
+ Debug.Assert(Argument.HasFlag(InstructionFlags.MayUnwrapNull));
+ }
+
+ public override InstructionFlags DirectFlags => InstructionFlags.ControlFlow;
+
+ protected override InstructionFlags ComputeFlags()
+ {
+ // Convert MayUnwrapNull flag to ControlFlow flag.
+ // Also, remove EndpointUnreachable flag, because the end-point is reachable through
+ // the implicit nullable.unwrap branch.
+ const InstructionFlags flagsToRemove = InstructionFlags.MayUnwrapNull | InstructionFlags.EndPointUnreachable;
+ return (Argument.Flags & ~flagsToRemove) | InstructionFlags.ControlFlow;
+ }
+
+ public override StackType ResultType {
+ get {
+ if (Argument.ResultType == StackType.Void)
+ return StackType.Void;
+ else
+ return StackType.O;
+ }
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
index d9a5f75ac..2649cf16b 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
@@ -292,6 +292,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (parent is NullCoalescingInstruction && NullableType.IsNullable(v.Type)) {
return true; // inline nullables into ?? operator
}
+ if (parent is NullableUnwrap && NullableType.IsNullable(v.Type)) {
+ return true; // inline nullables into ?. operator
+ }
// decide based on the target into which we are inlining
switch (next.OpCode) {
case OpCode.Leave:
@@ -354,6 +357,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return FindLoadInNext(container.EntryPoint.Instructions[0], v, expressionBeingMoved, out loadInst) ?? false;
// If FindLoadInNext() returns null, we still can't continue searching
// because we can't inline over the remainder of the blockcontainer.
+ } else if (expr is NullableRewrap) {
+ // Inlining into nullable.rewrap is OK unless the expression being inlined
+ // contains a nullable.wrap that isn't being re-wrapped within the expression being inlined.
+ if (expressionBeingMoved.HasFlag(InstructionFlags.MayUnwrapNull))
+ return false;
}
foreach (var child in expr.Children) {
if (!child.SlotInfo.CanInlineInto)
diff --git a/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs
index ab3499fdd..0eab50bd0 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/NullCoalescingTransform.cs
@@ -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.
///
class NullCoalescingTransform : IStatementTransform
{
diff --git a/ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
new file mode 100644
index 000000000..6065f0847
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
@@ -0,0 +1,236 @@
+// 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
+{
+ ///
+ /// Transform that converts code patterns like "v != null ? v.M() : null" to "v?.M()"
+ ///
+ 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)
+ {
+ this.context = context;
+ }
+
+ ///
+ /// Check if "condition ? trueInst : falseInst" can be simplified using the null-conditional operator.
+ /// Returns the replacement instruction, or null if no replacement is possible.
+ ///
+ 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;
+ }
+
+ ///
+ /// testedVar != null ? nonNullInst : nullInst
+ ///
+ 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;
+ }
+
+ ///
+ /// if (x != null) x.AccessChain();
+ /// => x?.AccessChain();
+ ///
+ internal void RunStatements(Block block, int pos)
+ {
+ var ifInst = block.Instructions[pos] as IfInstruction;
+ if (ifInst == null || !ifInst.FalseInst.MatchNop())
+ return;
+ if (ifInst.Condition is Comp comp && comp.Kind == ComparisonKind.Inequality
+ && comp.Left.MatchLdLoc(out var testedVar) && comp.Right.MatchLdNull()) {
+ TryNullPropForVoidCall(testedVar, true, ifInst.TrueInst as Block, ifInst);
+ } else if (NullableLiftingTransform.MatchHasValueCall(ifInst.Condition, out testedVar)) {
+ TryNullPropForVoidCall(testedVar, false, ifInst.TrueInst as Block, ifInst);
+ }
+ }
+
+ void TryNullPropForVoidCall(ILVariable testedVar, bool testedVarHasReferenceType, Block body, IfInstruction ifInst)
+ {
+ if (body == null || body.Instructions.Count != 1)
+ return;
+ var bodyInst = body.Instructions[0];
+ if (bodyInst.MatchNullableRewrap(out var arg)) {
+ bodyInst = arg;
+ }
+ if (!IsValidAccessChain(testedVar, testedVarHasReferenceType, bodyInst, out var varLoad))
+ return;
+ context.Step("Null-propagation (void call)", body);
+ // if (testedVar != null) { testedVar.AccessChain(); }
+ // => testedVar?.AccessChain();
+ IntroduceUnwrap(testedVar, varLoad);
+ ifInst.ReplaceWith(new NullableRewrap(
+ bodyInst
+ ) { ILRange = ifInst.ILRange });
+ }
+
+ 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
+ }
+ if (call.Method.IsAccessor && !IsGetter(call.Method)) {
+ return false; // setter/adder/remover cannot be called with ?. syntax
+ }
+ inst = call.Arguments[0];
+ if (call.Method.DeclaringType.IsReferenceType == false && inst.MatchAddressOf(out var arg)) {
+ inst = arg;
+ }
+ // 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);
+ }
+ }
+ }
+
+ static bool IsGetter(IMethod method)
+ {
+ return method.AccessorOwner is IProperty p && p.Getter == method;
+ }
+
+ 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);
+ }
+ }
+ }
+
+ class NullPropagationStatementTransform : IStatementTransform
+ {
+ public void Run(Block block, int pos, StatementTransformContext context)
+ {
+ if (!context.Settings.NullPropagation)
+ return;
+ new NullPropagationTransform(context).RunStatements(block, pos);
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
index f6ebe5587..526bc4441 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
@@ -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 (via NullPropagationTransform)
///
struct NullableLiftingTransform
{
@@ -55,8 +56,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
///
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
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
condition = arg;
ExtensionMethods.Swap(ref trueInst, ref falseInst);
}
+ if (context.Settings.NullPropagation && !NullPropagationTransform.IsProtectedIfInst(ifInst)) {
+ 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
diff --git a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
index 3d6cd1639..c16bb2f0b 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
@@ -171,22 +171,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms
int leaveIndex = entryPoint.Instructions.Count == 2 ? 1 : 2;
int checkIndex = entryPoint.Instructions.Count == 2 ? 0 : 1;
int castIndex = entryPoint.Instructions.Count == 3 ? 0 : -1;
+ var checkInst = entryPoint.Instructions[checkIndex];
bool isReference = objVar.Type.IsReferenceType != false;
if (castIndex > -1) {
if (!entryPoint.Instructions[castIndex].MatchStLoc(out var tempVar, out var isinst))
return false;
if (!isinst.MatchIsInst(out var load, out var disposableType) || !load.MatchLdLoc(objVar) || !disposableType.IsKnownType(KnownTypeCode.IDisposable))
return false;
- if (tempVar.StoreCount != 1 || tempVar.LoadCount != 2)
+ if (!tempVar.IsSingleDefinition)
return false;
- objVar = tempVar;
isReference = true;
+ if (!MatchDisposeCheck(tempVar, checkInst, isReference, usingNull, out int numObjVarLoadsInCheck))
+ return false;
+ if (tempVar.LoadCount != numObjVarLoadsInCheck)
+ return false;
+ } else {
+ if (!MatchDisposeCheck(objVar, checkInst, isReference, usingNull, out _))
+ return false;
}
if (!entryPoint.Instructions[leaveIndex].MatchLeave(container, out var returnValue) || !returnValue.MatchNop())
return false;
+ return true;
+ }
+
+ bool MatchDisposeCheck(ILVariable objVar, ILInstruction checkInst, bool isReference, bool usingNull, out int numObjVarLoadsInCheck)
+ {
+ numObjVarLoadsInCheck = 2;
CallVirt callVirt;
if (objVar.Type.IsKnownType(KnownTypeCode.NullableOfT)) {
- if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst))
+ if (!checkInst.MatchIfInstruction(out var condition, out var disposeInst))
return false;
if (!NullableLiftingTransform.MatchHasValueCall(condition, objVar))
return false;
@@ -214,9 +227,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
} else {
ILInstruction target;
- if (isReference) {
+ if (isReference && checkInst is NullableRewrap rewrap) {
+ // the null check of reference types might have been transformed into "objVar?.Dispose();"
+ if (!(rewrap.Argument is CallVirt cv))
+ return false;
+ if (!(cv.Arguments.FirstOrDefault() is NullableUnwrap unwrap))
+ return false;
+ numObjVarLoadsInCheck = 1;
+ callVirt = cv;
+ target = unwrap.Argument;
+ } else if (isReference) {
// reference types have a null check.
- if (!entryPoint.Instructions[checkIndex].MatchIfInstruction(out var condition, out var disposeInst))
+ if (!checkInst.MatchIfInstruction(out var condition, out var disposeInst))
return false;
if (!condition.MatchCompNotEquals(out var left, out var right) || !left.MatchLdLoc(objVar) || !right.MatchLdNull())
return false;
@@ -231,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
target = newTarget;
callVirt = cv;
} else {
- if (!(entryPoint.Instructions[checkIndex] is CallVirt cv))
+ if (!(checkInst is CallVirt cv))
return false;
target = cv.Arguments.FirstOrDefault();
if (target == null)
diff --git a/doc/copyright.txt b/doc/copyright.txt
index 57fe86257..a39d8148a 100644
--- a/doc/copyright.txt
+++ b/doc/copyright.txt
@@ -1,4 +1,4 @@
-Copyright 2011-2014 for the SharpDevelop team
+Copyright 2011-2018 for the SharpDevelop team
by
AlphaSierraPapa, Christoph Wille