diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index 6b5055438..0572fe08c 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -32,8 +32,8 @@
-
-
+
+
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/CompoundAssignment.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/CompoundAssignment.cs
index 246d45af0..096ae9b17 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/CompoundAssignment.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/CompoundAssignment.cs
@@ -26,6 +26,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
static void Main()
{
PreIncrementProperty();
+ PreIncrementIndexer();
+ CallTwice();
+ UnsignedShiftRightInstanceField();
+ UnsignedShiftRightStaticProperty();
}
static void Test(int a, int b)
@@ -41,16 +45,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
return ++x;
}
+ static int instanceCount;
+ int instanceNumber = ++instanceCount;
+
int instanceField;
public int InstanceProperty
{
get {
- Console.WriteLine("In get_InstanceProperty");
+ Console.WriteLine("In {0}.get_InstanceProperty", instanceNumber);
return instanceField;
}
set {
- Console.WriteLine("In set_InstanceProperty, value=" + value);
+ Console.WriteLine("In {0}.set_InstanceProperty, value=" + value, instanceNumber);
instanceField = value;
}
}
@@ -72,7 +79,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
public static Dictionary GetDict()
{
Console.WriteLine("In GetDict()");
- return new Dictionary();
+ return new Dictionary() { { GetString(), 5 } };
+ }
+
+ static CompoundAssignment GetObject()
+ {
+ Console.WriteLine("In GetObject() (instance #)");
+ return new CompoundAssignment();
}
static string GetString()
@@ -93,5 +106,32 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine("PreIncrementIndexer:");
Test(X(), ++GetDict()[GetString()]);
}
+
+ static void CallTwice()
+ {
+ Console.WriteLine("CallTwice: instanceField:");
+ GetObject().instanceField = GetObject().instanceField + 1;
+ Test(X(), GetObject().instanceField = GetObject().instanceField + 1);
+ Console.WriteLine("CallTwice: InstanceProperty:");
+ GetObject().InstanceProperty = GetObject().InstanceProperty + 1;
+ Test(X(), GetObject().InstanceProperty = GetObject().InstanceProperty + 1);
+ Console.WriteLine("CallTwice: dict indexer:");
+ GetDict()[GetString()] = GetDict()[GetString()] + 1;
+ Test(X(), GetDict()[GetString()] = GetDict()[GetString()] + 1);
+ }
+
+ static void UnsignedShiftRightInstanceField()
+ {
+#if !LEGACY_CSC
+ ref int f = ref new CompoundAssignment().instanceField;
+ Test(X(), f = (int)((uint)f >> 2));
+#endif
+ }
+
+ static void UnsignedShiftRightStaticProperty()
+ {
+ StaticProperty = -15;
+ Test(X(), StaticProperty = (int)((uint)StaticProperty >> 2));
+ }
}
}
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
index d28ca3a29..4730703aa 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
@@ -219,32 +219,92 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return --array[pos];
}
-
+
+ public int PostIncrementArrayElement(int[] array, int pos)
+ {
+ return array[pos]++;
+ }
+
+ public void IncrementArrayElement(int[] array, int pos)
+ {
+ array[pos]++;
+ }
+
public int PreIncrementInstanceField()
{
return ++this.M().Field;
}
+ //public int PostIncrementInstanceField()
+ //{
+ // return this.M().Field++;
+ //}
+
+ public void IncrementInstanceField()
+ {
+ this.M().Field++;
+ }
+
public int PreIncrementInstanceField2(MutableClass m)
{
return ++m.Field;
}
+ //public int PostIncrementInstanceField2(MutableClass m)
+ //{
+ // return m.Field++;
+ //}
+
+ public void IncrementInstanceField2(MutableClass m)
+ {
+ m.Field++;
+ }
+
public int PreIncrementInstanceProperty()
{
return ++this.M().Property;
}
-
+
+ //public int PostIncrementInstanceProperty()
+ //{
+ // return this.M().Property++;
+ //}
+
+ public void IncrementInstanceProperty()
+ {
+ this.M().Property++;
+ }
+
public int PreIncrementStaticField()
{
return ++CompoundAssignmentTest.StaticField;
}
-
+
+ public int PostIncrementStaticField()
+ {
+ return CompoundAssignmentTest.StaticField++;
+ }
+
+ public void IncrementStaticField()
+ {
+ CompoundAssignmentTest.StaticField++;
+ }
+
public int PreIncrementStaticProperty()
{
return ++CompoundAssignmentTest.StaticProperty;
}
+ //public int PostIncrementStaticProperty()
+ //{
+ // return CompoundAssignmentTest.StaticProperty++;
+ //}
+
+ public void IncrementStaticProperty()
+ {
+ CompoundAssignmentTest.StaticProperty++;
+ }
+
private static Item GetItem(object obj)
{
return null;
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.il
index 9943dec1c..dfc206ce2 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.il
@@ -1,5 +1,5 @@
-// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Copyright (c) Microsoft Corporation. All rights reserved.
@@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
-.assembly wswrh1ww
+.assembly kiryblux
{
.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
@@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
-.module wswrh1ww.dll
-// MVID: {0FA9B26D-B874-4697-B526-76EF6D2DAD90}
+.module kiryblux.dll
+// MVID: {34EC794D-1FFD-488F-9BDC-2D5D9C15854D}
.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: 0x029E0000
+// Image base: 0x02A30000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -762,6 +762,51 @@
IL_001c: ret
} // end of method CompoundAssignmentTest::PreIncrementArrayElement
+ .method public hidebysig instance int32
+ PostIncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 29 (0x1d)
+ .maxstack 3
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: ldarg.2
+ IL_0003: ldelema [mscorlib]System.Int32
+ IL_0008: dup
+ IL_0009: ldobj [mscorlib]System.Int32
+ IL_000e: dup
+ IL_000f: stloc.1
+ IL_0010: ldc.i4.1
+ IL_0011: add
+ IL_0012: stobj [mscorlib]System.Int32
+ IL_0017: ldloc.1
+ IL_0018: stloc.0
+ IL_0019: br.s IL_001b
+
+ IL_001b: ldloc.0
+ IL_001c: ret
+ } // end of method CompoundAssignmentTest::PostIncrementArrayElement
+
+ .method public hidebysig instance void
+ IncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 22 (0x16)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: ldarg.2
+ IL_0003: ldelema [mscorlib]System.Int32
+ IL_0008: dup
+ IL_0009: ldobj [mscorlib]System.Int32
+ IL_000e: ldc.i4.1
+ IL_000f: add
+ IL_0010: stobj [mscorlib]System.Int32
+ IL_0015: ret
+ } // end of method CompoundAssignmentTest::IncrementArrayElement
+
.method public hidebysig instance int32
PreIncrementInstanceField() cil managed
{
@@ -787,6 +832,22 @@
IL_001b: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField
+ .method public hidebysig instance void
+ IncrementInstanceField() cil managed
+ {
+ // Code size 21 (0x15)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0007: dup
+ IL_0008: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000d: ldc.i4.1
+ IL_000e: add
+ IL_000f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0014: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField
+
.method public hidebysig instance int32
PreIncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
{
@@ -811,6 +872,21 @@
IL_0016: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField2
+ .method public hidebysig instance void
+ IncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
+ {
+ // Code size 16 (0x10)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: dup
+ IL_0003: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0008: ldc.i4.1
+ IL_0009: add
+ IL_000a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000f: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField2
+
.method public hidebysig instance int32
PreIncrementInstanceProperty() cil managed
{
@@ -837,6 +913,23 @@
IL_001c: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceProperty
+ .method public hidebysig instance void
+ IncrementInstanceProperty() cil managed
+ {
+ // Code size 22 (0x16)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0007: dup
+ IL_0008: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::get_Property()
+ IL_000d: ldc.i4.1
+ IL_000e: add
+ IL_000f: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::set_Property(int32)
+ IL_0014: nop
+ IL_0015: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceProperty
+
.method public hidebysig instance int32
PreIncrementStaticField() cil managed
{
@@ -856,6 +949,38 @@
IL_0012: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticField
+ .method public hidebysig instance int32
+ PostIncrementStaticField() cil managed
+ {
+ // Code size 19 (0x13)
+ .maxstack 3
+ .locals init (int32 V_0)
+ IL_0000: nop
+ IL_0001: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0006: dup
+ IL_0007: ldc.i4.1
+ IL_0008: add
+ IL_0009: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000e: stloc.0
+ IL_000f: br.s IL_0011
+
+ IL_0011: ldloc.0
+ IL_0012: ret
+ } // end of method CompoundAssignmentTest::PostIncrementStaticField
+
+ .method public hidebysig instance void
+ IncrementStaticField() cil managed
+ {
+ // Code size 14 (0xe)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0006: ldc.i4.1
+ IL_0007: add
+ IL_0008: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000d: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticField
+
.method public hidebysig instance int32
PreIncrementStaticProperty() cil managed
{
@@ -876,6 +1001,20 @@
IL_0013: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticProperty
+ .method public hidebysig instance void
+ IncrementStaticProperty() cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::get_StaticProperty()
+ IL_0006: ldc.i4.1
+ IL_0007: add
+ IL_0008: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::set_StaticProperty(int32)
+ IL_000d: nop
+ IL_000e: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticProperty
+
.method private hidebysig static class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/Item
GetItem(object obj) cil managed
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.il
index 96ae56094..2dea51f56 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.il
@@ -1,5 +1,5 @@
-// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Copyright (c) Microsoft Corporation. All rights reserved.
@@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
-.assembly ag42vicc
+.assembly d4bhqxbe
{
.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
@@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
-.module ag42vicc.dll
-// MVID: {EB752380-6A62-4B20-9497-B68A784C5BD7}
+.module d4bhqxbe.dll
+// MVID: {B884BD61-6FE3-4893-B161-02EE675C0DF0}
.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: 0x00DE0000
+// Image base: 0x003A0000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -647,6 +647,44 @@
IL_0017: ret
} // end of method CompoundAssignmentTest::PreIncrementArrayElement
+ .method public hidebysig instance int32
+ PostIncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 24 (0x18)
+ .maxstack 3
+ .locals init (int32 V_0)
+ IL_0000: ldarg.1
+ IL_0001: ldarg.2
+ IL_0002: ldelema [mscorlib]System.Int32
+ IL_0007: dup
+ IL_0008: ldobj [mscorlib]System.Int32
+ IL_000d: dup
+ IL_000e: stloc.0
+ IL_000f: ldc.i4.1
+ IL_0010: add
+ IL_0011: stobj [mscorlib]System.Int32
+ IL_0016: ldloc.0
+ IL_0017: ret
+ } // end of method CompoundAssignmentTest::PostIncrementArrayElement
+
+ .method public hidebysig instance void
+ IncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 21 (0x15)
+ .maxstack 8
+ IL_0000: ldarg.1
+ IL_0001: ldarg.2
+ IL_0002: ldelema [mscorlib]System.Int32
+ IL_0007: dup
+ IL_0008: ldobj [mscorlib]System.Int32
+ IL_000d: ldc.i4.1
+ IL_000e: add
+ IL_000f: stobj [mscorlib]System.Int32
+ IL_0014: ret
+ } // end of method CompoundAssignmentTest::IncrementArrayElement
+
.method public hidebysig instance int32
PreIncrementInstanceField() cil managed
{
@@ -666,6 +704,21 @@
IL_0016: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField
+ .method public hidebysig instance void
+ IncrementInstanceField() cil managed
+ {
+ // Code size 20 (0x14)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0006: dup
+ IL_0007: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000c: ldc.i4.1
+ IL_000d: add
+ IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0013: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField
+
.method public hidebysig instance int32
PreIncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
{
@@ -684,6 +737,20 @@
IL_0011: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField2
+ .method public hidebysig instance void
+ IncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 8
+ IL_0000: ldarg.1
+ IL_0001: dup
+ IL_0002: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0007: ldc.i4.1
+ IL_0008: add
+ IL_0009: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000e: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField2
+
.method public hidebysig instance int32
PreIncrementInstanceProperty() cil managed
{
@@ -703,6 +770,21 @@
IL_0016: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceProperty
+ .method public hidebysig instance void
+ IncrementInstanceProperty() cil managed
+ {
+ // Code size 20 (0x14)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0006: dup
+ IL_0007: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::get_Property()
+ IL_000c: ldc.i4.1
+ IL_000d: add
+ IL_000e: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::set_Property(int32)
+ IL_0013: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceProperty
+
.method public hidebysig instance int32
PreIncrementStaticField() cil managed
{
@@ -716,6 +798,31 @@
IL_000d: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticField
+ .method public hidebysig instance int32
+ PostIncrementStaticField() cil managed
+ {
+ // Code size 14 (0xe)
+ .maxstack 8
+ IL_0000: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0005: dup
+ IL_0006: ldc.i4.1
+ IL_0007: add
+ IL_0008: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000d: ret
+ } // end of method CompoundAssignmentTest::PostIncrementStaticField
+
+ .method public hidebysig instance void
+ IncrementStaticField() cil managed
+ {
+ // Code size 13 (0xd)
+ .maxstack 8
+ IL_0000: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0005: ldc.i4.1
+ IL_0006: add
+ IL_0007: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000c: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticField
+
.method public hidebysig instance int32
PreIncrementStaticProperty() cil managed
{
@@ -729,6 +836,18 @@
IL_000d: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticProperty
+ .method public hidebysig instance void
+ IncrementStaticProperty() cil managed
+ {
+ // Code size 13 (0xd)
+ .maxstack 8
+ IL_0000: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::get_StaticProperty()
+ IL_0005: ldc.i4.1
+ IL_0006: add
+ IL_0007: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::set_StaticProperty(int32)
+ IL_000c: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticProperty
+
.method private hidebysig static class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/Item
GetItem(object obj) cil managed
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.roslyn.il
index a68694af0..36f83b082 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.roslyn.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.roslyn.il
@@ -1,5 +1,5 @@
-// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Copyright (c) Microsoft Corporation. All rights reserved.
@@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module CompoundAssignmentTest.dll
-// MVID: {104CDF7A-FBAC-406D-AA60-4C777388A178}
+// MVID: {6E5749EE-F4C5-4B86-96FC-F4A665551BA6}
.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: 0x008E0000
+// Image base: 0x028A0000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -650,6 +650,44 @@
IL_000f: ret
} // end of method CompoundAssignmentTest::PreIncrementArrayElement
+ .method public hidebysig instance int32
+ PostIncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 16 (0x10)
+ .maxstack 3
+ .locals init (int32 V_0)
+ IL_0000: ldarg.1
+ IL_0001: ldarg.2
+ IL_0002: ldelema [mscorlib]System.Int32
+ IL_0007: dup
+ IL_0008: ldind.i4
+ IL_0009: stloc.0
+ IL_000a: ldloc.0
+ IL_000b: ldc.i4.1
+ IL_000c: add
+ IL_000d: stind.i4
+ IL_000e: ldloc.0
+ IL_000f: ret
+ } // end of method CompoundAssignmentTest::PostIncrementArrayElement
+
+ .method public hidebysig instance void
+ IncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 13 (0xd)
+ .maxstack 8
+ IL_0000: ldarg.1
+ IL_0001: ldarg.2
+ IL_0002: ldelema [mscorlib]System.Int32
+ IL_0007: dup
+ IL_0008: ldind.i4
+ IL_0009: ldc.i4.1
+ IL_000a: add
+ IL_000b: stind.i4
+ IL_000c: ret
+ } // end of method CompoundAssignmentTest::IncrementArrayElement
+
.method public hidebysig instance int32
PreIncrementInstanceField() cil managed
{
@@ -669,6 +707,21 @@
IL_0016: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField
+ .method public hidebysig instance void
+ IncrementInstanceField() cil managed
+ {
+ // Code size 20 (0x14)
+ .maxstack 8
+ IL_0000: ldarg.0
+ IL_0001: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0006: dup
+ IL_0007: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000c: ldc.i4.1
+ IL_000d: add
+ IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0013: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField
+
.method public hidebysig instance int32
PreIncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
{
@@ -687,6 +740,20 @@
IL_0011: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField2
+ .method public hidebysig instance void
+ IncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 8
+ IL_0000: ldarg.1
+ IL_0001: dup
+ IL_0002: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0007: ldc.i4.1
+ IL_0008: add
+ IL_0009: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000e: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField2
+
.method public hidebysig instance int32
PreIncrementInstanceProperty() cil managed
{
@@ -706,6 +773,24 @@
IL_0016: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceProperty
+ .method public hidebysig instance void
+ IncrementInstanceProperty() cil managed
+ {
+ // Code size 22 (0x16)
+ .maxstack 3
+ .locals init (int32 V_0)
+ IL_0000: ldarg.0
+ IL_0001: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0006: dup
+ IL_0007: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::get_Property()
+ IL_000c: stloc.0
+ IL_000d: ldloc.0
+ IL_000e: ldc.i4.1
+ IL_000f: add
+ IL_0010: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::set_Property(int32)
+ IL_0015: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceProperty
+
.method public hidebysig instance int32
PreIncrementStaticField() cil managed
{
@@ -719,6 +804,31 @@
IL_000d: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticField
+ .method public hidebysig instance int32
+ PostIncrementStaticField() cil managed
+ {
+ // Code size 14 (0xe)
+ .maxstack 8
+ IL_0000: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0005: dup
+ IL_0006: ldc.i4.1
+ IL_0007: add
+ IL_0008: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000d: ret
+ } // end of method CompoundAssignmentTest::PostIncrementStaticField
+
+ .method public hidebysig instance void
+ IncrementStaticField() cil managed
+ {
+ // Code size 13 (0xd)
+ .maxstack 8
+ IL_0000: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0005: ldc.i4.1
+ IL_0006: add
+ IL_0007: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000c: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticField
+
.method public hidebysig instance int32
PreIncrementStaticProperty() cil managed
{
@@ -732,6 +842,18 @@
IL_000d: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticProperty
+ .method public hidebysig instance void
+ IncrementStaticProperty() cil managed
+ {
+ // Code size 13 (0xd)
+ .maxstack 8
+ IL_0000: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::get_StaticProperty()
+ IL_0005: ldc.i4.1
+ IL_0006: add
+ IL_0007: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::set_StaticProperty(int32)
+ IL_000c: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticProperty
+
.method private hidebysig static class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/Item
GetItem(object obj) cil managed
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.roslyn.il
index 9b1077169..1404a451f 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.roslyn.il
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.roslyn.il
@@ -1,5 +1,5 @@
-// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.17929
+// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.18020
// Copyright (c) Microsoft Corporation. All rights reserved.
@@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module CompoundAssignmentTest.dll
-// MVID: {E4D6BDFE-1178-4790-A328-6755C028F1BE}
+// MVID: {391C1968-5381-4AC7-9C19-7B5F6ED36AF8}
.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: 0x00D10000
+// Image base: 0x003D0000
// =============== CLASS MEMBERS DECLARATION ===================
@@ -759,6 +759,51 @@
IL_0014: ret
} // end of method CompoundAssignmentTest::PreIncrementArrayElement
+ .method public hidebysig instance int32
+ PostIncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 21 (0x15)
+ .maxstack 3
+ .locals init (int32 V_0,
+ int32 V_1)
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: ldarg.2
+ IL_0003: ldelema [mscorlib]System.Int32
+ IL_0008: dup
+ IL_0009: ldind.i4
+ IL_000a: stloc.0
+ IL_000b: ldloc.0
+ IL_000c: ldc.i4.1
+ IL_000d: add
+ IL_000e: stind.i4
+ IL_000f: ldloc.0
+ IL_0010: stloc.1
+ IL_0011: br.s IL_0013
+
+ IL_0013: ldloc.1
+ IL_0014: ret
+ } // end of method CompoundAssignmentTest::PostIncrementArrayElement
+
+ .method public hidebysig instance void
+ IncrementArrayElement(int32[] 'array',
+ int32 pos) cil managed
+ {
+ // Code size 14 (0xe)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: ldarg.2
+ IL_0003: ldelema [mscorlib]System.Int32
+ IL_0008: dup
+ IL_0009: ldind.i4
+ IL_000a: ldc.i4.1
+ IL_000b: add
+ IL_000c: stind.i4
+ IL_000d: ret
+ } // end of method CompoundAssignmentTest::IncrementArrayElement
+
.method public hidebysig instance int32
PreIncrementInstanceField() cil managed
{
@@ -784,6 +829,22 @@
IL_001b: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField
+ .method public hidebysig instance void
+ IncrementInstanceField() cil managed
+ {
+ // Code size 21 (0x15)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0007: dup
+ IL_0008: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000d: ldc.i4.1
+ IL_000e: add
+ IL_000f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0014: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField
+
.method public hidebysig instance int32
PreIncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
{
@@ -808,6 +869,21 @@
IL_0016: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceField2
+ .method public hidebysig instance void
+ IncrementInstanceField2(class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass m) cil managed
+ {
+ // Code size 16 (0x10)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldarg.1
+ IL_0002: dup
+ IL_0003: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_0008: ldc.i4.1
+ IL_0009: add
+ IL_000a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::Field
+ IL_000f: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceField2
+
.method public hidebysig instance int32
PreIncrementInstanceProperty() cil managed
{
@@ -834,6 +910,26 @@
IL_001c: ret
} // end of method CompoundAssignmentTest::PreIncrementInstanceProperty
+ .method public hidebysig instance void
+ IncrementInstanceProperty() cil managed
+ {
+ // Code size 24 (0x18)
+ .maxstack 3
+ .locals init (int32 V_0)
+ IL_0000: nop
+ IL_0001: ldarg.0
+ IL_0002: call instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::M()
+ IL_0007: dup
+ IL_0008: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::get_Property()
+ IL_000d: stloc.0
+ IL_000e: ldloc.0
+ IL_000f: ldc.i4.1
+ IL_0010: add
+ IL_0011: callvirt instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MutableClass::set_Property(int32)
+ IL_0016: nop
+ IL_0017: ret
+ } // end of method CompoundAssignmentTest::IncrementInstanceProperty
+
.method public hidebysig instance int32
PreIncrementStaticField() cil managed
{
@@ -853,6 +949,38 @@
IL_0012: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticField
+ .method public hidebysig instance int32
+ PostIncrementStaticField() cil managed
+ {
+ // Code size 19 (0x13)
+ .maxstack 3
+ .locals init (int32 V_0)
+ IL_0000: nop
+ IL_0001: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0006: dup
+ IL_0007: ldc.i4.1
+ IL_0008: add
+ IL_0009: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000e: stloc.0
+ IL_000f: br.s IL_0011
+
+ IL_0011: ldloc.0
+ IL_0012: ret
+ } // end of method CompoundAssignmentTest::PostIncrementStaticField
+
+ .method public hidebysig instance void
+ IncrementStaticField() cil managed
+ {
+ // Code size 14 (0xe)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: ldsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_0006: ldc.i4.1
+ IL_0007: add
+ IL_0008: stsfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::StaticField
+ IL_000d: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticField
+
.method public hidebysig instance int32
PreIncrementStaticProperty() cil managed
{
@@ -873,6 +1001,20 @@
IL_0013: ret
} // end of method CompoundAssignmentTest::PreIncrementStaticProperty
+ .method public hidebysig instance void
+ IncrementStaticProperty() cil managed
+ {
+ // Code size 15 (0xf)
+ .maxstack 8
+ IL_0000: nop
+ IL_0001: call int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::get_StaticProperty()
+ IL_0006: ldc.i4.1
+ IL_0007: add
+ IL_0008: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest::set_StaticProperty(int32)
+ IL_000d: nop
+ IL_000e: ret
+ } // end of method CompoundAssignmentTest::IncrementStaticProperty
+
.method private hidebysig static class ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/Item
GetItem(object obj) cil managed
{
diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index 1503561f0..1d3990401 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -75,12 +75,8 @@ namespace ICSharpCode.Decompiler.CSharp
new AsyncAwaitDecompiler(), // must run after inlining but before loop detection
new DetectCatchWhenConditionBlocks(), // must run after inlining but before loop detection
new DetectExitPoints(canIntroduceExitForReturn: false),
- new BlockILTransform {
- PostOrderTransforms = {
- new ExpressionTransforms() // for RemoveDeadVariableInit
- }
- },
- // RemoveDeadVariableInit must run after ExpressionTransforms so that stobj(ldloca V, ...)
+ new EarlyExpressionTransforms(),
+ // RemoveDeadVariableInit must run after EarlyExpressionTransforms so that stobj(ldloca V, ...)
// is already collapsed into stloc(V, ...).
new RemoveDeadVariableInit(),
new SplitVariables(), // split variables once again, because the stobj(ldloca V, ...) may open up new replacements
@@ -107,8 +103,7 @@ namespace ICSharpCode.Decompiler.CSharp
// and must run before NullCoalescingTransform
new CachedDelegateInitialization(),
new ILInlining(),
- new TransformAssignment(),
- new NullableLiftingBlockTransform(),
+ new TransformAssignment(), // must run before CopyPropagation
new CopyPropagation(),
new StatementTransform(
// per-block transforms that depend on each other, and thus need to
@@ -120,6 +115,7 @@ namespace ICSharpCode.Decompiler.CSharp
// Any other transform that opens up new inlining opportunities should call RequestRerun().
new ExpressionTransforms(),
new NullCoalescingTransform(),
+ new NullableLiftingStatementTransform(),
new TransformArrayInitializers(),
new TransformCollectionAndObjectInitializers()
)
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 387d453b5..581380e6d 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -49,8 +49,8 @@
-
-
+
+
@@ -271,6 +271,7 @@
+
diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
index ec64edf8c..bc3a92038 100644
--- a/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
+++ b/ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
@@ -127,7 +127,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.StepStartGroup("CleanUpBodyOfMoveNext", function);
// Simplify stobj(ldloca) -> stloc
foreach (var stobj in function.Descendants.OfType()) {
- ExpressionTransforms.StObjToStLoc(stobj, context);
+ EarlyExpressionTransforms.StObjToStLoc(stobj, context);
}
// Copy-propagate temporaries holding a copy of 'this'.
diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
index 48ecdf218..268b9a429 100644
--- a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
+++ b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
@@ -146,7 +146,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
targetBlock.Instructions.AddRange(nestedTrueBlock.Instructions);
// add falseInsts to inner block
nestedTrueBlock.Instructions.ReplaceList(falseInsts);
- nestedIfInst.Condition.AcceptVisitor(new ExpressionTransforms { context = context });
+ nestedIfInst.Condition.AcceptVisitor(new ExpressionTransforms { context = new StatementTransformContext(context) });
}
break;
}
diff --git a/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
index 3289afc05..7d372c5cf 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
@@ -58,6 +58,7 @@ namespace ICSharpCode.Decompiler.IL
public CompoundAssignmentInstruction(BinaryNumericInstruction binary, ILInstruction target, ILInstruction value, IType type, CompoundAssignmentType compoundAssignmentType)
: base(OpCode.CompoundAssignmentInstruction)
{
+ Debug.Assert(IsBinaryCompatibleWithType(binary, type));
this.CheckForOverflow = binary.CheckForOverflow;
this.Sign = binary.Sign;
this.LeftInputType = binary.LeftInputType;
@@ -69,10 +70,28 @@ namespace ICSharpCode.Decompiler.IL
this.Target = target;
this.type = type;
this.Value = value;
+ this.ILRange = binary.ILRange;
Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub));
Debug.Assert(IsValidCompoundAssignmentTarget(Target));
}
+ ///
+ /// Gets whether the specific binary instruction is compatible with a compound operation on the specified type.
+ ///
+ internal static bool IsBinaryCompatibleWithType(BinaryNumericInstruction binary, IType type)
+ {
+ if (binary.IsLifted) {
+ if (!NullableType.IsNullable(type))
+ return false;
+ type = NullableType.GetUnderlyingType(type);
+ }
+ if (binary.Sign != Sign.None) {
+ if (type.GetSign() != binary.Sign)
+ return false;
+ }
+ return true;
+ }
+
internal static bool IsValidCompoundAssignmentTarget(ILInstruction inst)
{
switch (inst.OpCode) {
diff --git a/ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs b/ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs
new file mode 100644
index 000000000..c48bc0655
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs
@@ -0,0 +1,93 @@
+// Copyright (c) 2017 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.Linq;
+using System.Text;
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.Decompiler.IL.Transforms
+{
+ class EarlyExpressionTransforms : ILVisitor, IILTransform
+ {
+ ILTransformContext context;
+
+ public void Run(ILFunction function, ILTransformContext context)
+ {
+ this.context = context;
+ Default(function);
+ }
+
+ protected override void Default(ILInstruction inst)
+ {
+ foreach (var child in inst.Children) {
+ child.AcceptVisitor(this);
+ }
+ }
+
+ protected internal override void VisitStObj(StObj inst)
+ {
+ base.VisitStObj(inst);
+ StObjToStLoc(inst, context);
+ }
+
+ // This transform is required because ILInlining only works with stloc/ldloc
+ internal static bool StObjToStLoc(StObj inst, ILTransformContext context)
+ {
+ if (inst.Target.MatchLdLoca(out ILVariable v)
+ && TypeUtils.IsCompatibleTypeForMemoryAccess(new ByReferenceType(v.Type), inst.Type)
+ && inst.UnalignedPrefix == 0
+ && !inst.IsVolatile) {
+ context.Step($"stobj(ldloca {v.Name}, ...) => stloc {v.Name}(...)", inst);
+ inst.ReplaceWith(new StLoc(v, inst.Value));
+ return true;
+ }
+ return false;
+ }
+
+ protected internal override void VisitCall(Call inst)
+ {
+ var expr = HandleCall(inst, context);
+ if (expr != null) {
+ // The resulting expression may trigger further rules, so continue visiting the replacement:
+ expr.AcceptVisitor(this);
+ } else {
+ base.VisitCall(inst);
+ }
+ }
+
+ internal static ILInstruction HandleCall(Call inst, ILTransformContext context)
+ {
+ if (inst.Method.IsConstructor && !inst.Method.IsStatic && inst.Method.DeclaringType.Kind == TypeKind.Struct) {
+ Debug.Assert(inst.Arguments.Count == inst.Method.Parameters.Count + 1);
+ context.Step("Transform call to struct constructor", inst);
+ // call(ref, ...)
+ // => stobj(ref, newobj(...))
+ var newObj = new NewObj(inst.Method);
+ newObj.ILRange = inst.ILRange;
+ newObj.Arguments.AddRange(inst.Arguments.Skip(1));
+ var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType);
+ inst.ReplaceWith(expr);
+ return expr;
+ }
+ return null;
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
index bb786a765..4b97e7ac0 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
@@ -1,4 +1,4 @@
-// Copyright (c) 2014 Daniel Grunwald
+// Copyright (c) 2014-2017 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
@@ -29,16 +29,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
///
/// Should run after inlining so that the expression patterns can be detected.
///
- public class ExpressionTransforms : ILVisitor, IBlockTransform, IStatementTransform
+ public class ExpressionTransforms : ILVisitor, IStatementTransform
{
- internal ILTransformContext context;
-
- public void Run(Block block, BlockTransformContext context)
- {
- this.context = context;
- Default(block);
- }
-
+ internal StatementTransformContext context;
+
public void Run(Block block, int pos, StatementTransformContext context)
{
this.context = context;
@@ -229,23 +223,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms
protected internal override void VisitCall(Call inst)
{
- if (inst.Method.IsConstructor && !inst.Method.IsStatic && inst.Method.DeclaringType.Kind == TypeKind.Struct) {
- Debug.Assert(inst.Arguments.Count == inst.Method.Parameters.Count + 1);
- context.Step("Transform call to struct constructor", inst);
- // call(ref, ...)
- // => stobj(ref, newobj(...))
- var newObj = new NewObj(inst.Method);
- newObj.ILRange = inst.ILRange;
- newObj.Arguments.AddRange(inst.Arguments.Skip(1));
- var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType);
- inst.ReplaceWith(expr);
- // Both the StObj and the NewObj may trigger further rules, so continue visiting the replacement:
- VisitStObj(expr);
+ var expr = EarlyExpressionTransforms.HandleCall(inst, context);
+ if (expr != null) {
+ // The resulting expression may trigger further rules, so continue visiting the replacement:
+ expr.AcceptVisitor(this);
} else {
base.VisitCall(inst);
+ TransformAssignment.HandleCallCompoundAssign(inst, context);
}
}
-
+
+ protected internal override void VisitCallVirt(CallVirt inst)
+ {
+ base.VisitCallVirt(inst);
+ TransformAssignment.HandleCallCompoundAssign(inst, context);
+ }
+
protected internal override void VisitNewObj(NewObj inst)
{
LdcDecimal decimalConstant;
@@ -286,13 +279,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
protected internal override void VisitStObj(StObj inst)
{
base.VisitStObj(inst);
- if (StObjToStLoc(inst, context)) {
+ if (EarlyExpressionTransforms.StObjToStLoc(inst, context)) {
+ context.RequestRerun();
return;
}
if (inst.Value is BinaryNumericInstruction binary
&& binary.Left.MatchLdObj(out ILInstruction target, out IType t)
- && inst.Target.Match(target).Success)
+ && inst.Target.Match(target).Success
+ && SemanticHelper.IsPure(target.Flags)
+ && CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, t))
{
context.Step("compound assignment", inst);
// stobj(target, binary.op(ldobj(target), ...))
@@ -303,20 +299,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
- // This transform is required because ILInlining only works with stloc/ldloc
- internal static bool StObjToStLoc(StObj inst, ILTransformContext context)
- {
- if (inst.Target.MatchLdLoca(out ILVariable v)
- && TypeUtils.IsCompatibleTypeForMemoryAccess(new ByReferenceType(v.Type), inst.Type)
- && inst.UnalignedPrefix == 0
- && !inst.IsVolatile) {
- context.Step($"stobj(ldloca {v.Name}, ...) => stloc {v.Name}(...)", inst);
- inst.ReplaceWith(new StLoc(v, inst.Value));
- return true;
- }
- return false;
- }
-
protected internal override void VisitIfInstruction(IfInstruction inst)
{
inst.TrueInst.AcceptVisitor(this);
@@ -360,7 +342,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1);
newIf.ILRange = inst.ILRange;
inst.ReplaceWith(new StLoc(v, newIf));
- (context as StatementTransformContext)?.RequestRerun(); // trigger potential inlining of the newly created StLoc
+ context.RequestRerun(); // trigger potential inlining of the newly created StLoc
return newIf;
}
return inst;
diff --git a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
index e09216067..0ee050f4a 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
@@ -64,7 +64,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
- public bool RunBlock(Block block)
+ public bool RunStatements(Block block, int pos)
{
if (!context.Settings.LiftNullables)
return false;
@@ -73,18 +73,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// leave IL_0000 (default.value System.Nullable`1[[System.Int64]])
// }
// leave IL_0000 (newobj .ctor(exprToLift))
- IfInstruction ifInst;
- if (block.Instructions.Last() is Leave elseLeave) {
- ifInst = block.Instructions.SecondToLastOrDefault() as IfInstruction;
- if (ifInst == null || !ifInst.FalseInst.MatchNop())
- return false;
- } else {
+ if (pos != block.Instructions.Count - 2)
+ return false;
+ if (!(block.Instructions[pos] is IfInstruction ifInst))
return false;
- }
if (!(Block.Unwrap(ifInst.TrueInst) is Leave thenLeave))
return false;
+ if (!ifInst.FalseInst.MatchNop())
+ return false;
+
+ if (!(block.Instructions[pos + 1] is Leave elseLeave))
+ return false;
if (elseLeave.TargetContainer != thenLeave.TargetContainer)
return false;
+
var lifted = Lift(ifInst, thenLeave.Value, elseLeave.Value);
if (lifted != null) {
thenLeave.Value = lifted;
@@ -149,7 +151,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// => a != b
return LiftCSharpEqualityComparison(comp, ComparisonKind.Inequality, trueInst)
?? LiftCSharpUserEqualityComparison(comp, ComparisonKind.Inequality, trueInst);
- } else if (IsGenericNewPattern(condition, trueInst, falseInst)) {
+ } else if (IsGenericNewPattern(comp.Left, comp.Right, trueInst, falseInst)) {
// (default(T) == null) ? Activator.CreateInstance() : default(T)
// => Activator.CreateInstance()
return trueInst;
@@ -245,16 +247,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null;
}
- private bool IsGenericNewPattern(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst)
+ private bool IsGenericNewPattern(ILInstruction compLeft, ILInstruction compRight, ILInstruction trueInst, ILInstruction falseInst)
{
// (default(T) == null) ? Activator.CreateInstance() : default(T)
return falseInst.MatchDefaultValue(out var type) &&
(trueInst is Call c && c.Method.FullName == "System.Activator.CreateInstance" && c.Method.TypeArguments.Count == 1) &&
type.Kind == TypeKind.TypeParameter &&
- condition.MatchCompEquals(out var left, out var right) &&
- left.MatchDefaultValue(out var type2) &&
+ compLeft.MatchDefaultValue(out var type2) &&
type.Equals(type2) &&
- right.MatchLdNull();
+ compRight.MatchLdNull();
}
private bool MatchThreeValuedLogicConditionPattern(ILInstruction condition, out ILVariable nullable1, out ILVariable nullable2)
@@ -847,11 +848,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
#endregion
}
- class NullableLiftingBlockTransform : IBlockTransform
+ class NullableLiftingStatementTransform : IStatementTransform
{
- public void Run(Block block, BlockTransformContext context)
+ public void Run(Block block, int pos, StatementTransformContext context)
{
- new NullableLiftingTransform(context).RunBlock(block);
+ new NullableLiftingTransform(context).RunStatements(block, pos);
}
}
}
diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
index 3d029d661..5d41bb402 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
@@ -16,13 +16,14 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
+using System;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
///
- /// Description of TransformAssignment.
+ /// Constructs compound assignments and inline assignments.
///
public class TransformAssignment : IBlockTransform
{
@@ -42,7 +43,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (TransformInlineAssignmentStObj(block, i))
continue;
- if (TransformInlineAssignmentCall(block, i))
+ if (TransformInlineCompoundAssignmentCall(block, i))
+ continue;
+ if (TransformRoslynCompoundAssignmentCall(block, i))
continue;
}
}
@@ -82,8 +85,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
replacement = new StObj(fieldStore.Target, inst.Value, fieldStore.Type);
} else { // otherwise it must be local
- TransformInlineAssignmentLocal(block, i);
- return false;
+ return TransformInlineAssignmentLocal(block, i);
}
context.Step("Inline assignment to instance field", fieldStore);
local = localStore.Variable;
@@ -106,76 +108,151 @@ namespace ICSharpCode.Decompiler.IL.Transforms
///
/// stloc s(binary(callvirt(getter), value))
/// callvirt (setter, ldloc s)
- /// ... usage of s ...
- /// -->
- /// ... compound.op.new(callvirt(getter), value) ...
- ///
- /// -or-
- ///
- /// stloc s(stloc v(binary(callvirt(getter), value)))
- /// callvirt (setter, ldloc s)
- /// ... usage of v ...
+ /// (followed by single usage of s in next instruction)
/// -->
- /// ... compound.op.new(callvirt(getter), value) ...
+ /// stloc s(compound.op.new(callvirt(getter), value))
///
- bool TransformInlineAssignmentCall(Block block, int i)
+ bool TransformInlineCompoundAssignmentCall(Block block, int i)
{
- var inst = block.Instructions[i] as StLoc;
+ var mainStLoc = block.Instructions[i] as StLoc;
// in some cases it can be a compiler-generated local
- if (inst == null || (inst.Variable.Kind != VariableKind.StackSlot && inst.Variable.Kind != VariableKind.Local))
+ if (mainStLoc == null || (mainStLoc.Variable.Kind != VariableKind.StackSlot && mainStLoc.Variable.Kind != VariableKind.Local))
+ return false;
+ BinaryNumericInstruction binary = mainStLoc.Value as BinaryNumericInstruction;
+ ILVariable localVariable = mainStLoc.Variable;
+ if (!localVariable.IsSingleDefinition)
+ return false;
+ if (localVariable.LoadCount != 2)
return false;
- BinaryNumericInstruction binary;
- ILVariable localVariable;
- if (inst.Value is StLoc) {
- var tmp = (StLoc)inst.Value;
- binary = tmp.Value as BinaryNumericInstruction;
- localVariable = tmp.Variable;
- } else {
- binary = inst.Value as BinaryNumericInstruction;
- localVariable = inst.Variable;
- }
var getterCall = binary?.Left as CallInstruction;
var setterCall = block.Instructions.ElementAtOrDefault(i + 1) as CallInstruction;
- if (getterCall == null || setterCall == null || !IsSameMember(getterCall.Method.AccessorOwner, setterCall.Method.AccessorOwner))
+ if (!MatchingGetterAndSetterCalls(getterCall, setterCall))
return false;
- var owner = getterCall.Method.AccessorOwner as IProperty;
- if (owner == null || !IsSameMember(getterCall.Method, owner.Getter) || !IsSameMember(setterCall.Method, owner.Setter))
+ if (!setterCall.Arguments.Last().MatchLdLoc(localVariable))
return false;
+
var next = block.Instructions.ElementAtOrDefault(i + 2);
if (next == null)
return false;
- var usages = next.Descendants.Where(d => d.MatchLdLoc(localVariable)).ToArray();
- if (usages.Length != 1)
+ if (next.Descendants.Where(d => d.MatchLdLoc(localVariable)).Count() != 1)
return false;
- context.Step($"Compound assignment to '{owner.Name}'", setterCall);
- block.Instructions.RemoveAt(i + 1);
- block.Instructions.RemoveAt(i);
- usages[0].ReplaceWith(new CompoundAssignmentInstruction(
+ if (!CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, getterCall.Method.ReturnType))
+ return false;
+ context.Step($"Inline compound assignment to '{getterCall.Method.AccessorOwner.Name}'", setterCall);
+ block.Instructions.RemoveAt(i + 1); // remove setter call
+ binary.ReplaceWith(new CompoundAssignmentInstruction(
binary, getterCall, binary.Right,
getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue));
return true;
}
+ ///
+ /// Roslyn compound assignment that's not inline within another instruction.
+ ///
+ bool TransformRoslynCompoundAssignmentCall(Block block, int i)
+ {
+ // stloc variable(callvirt get_Property(ldloc obj))
+ // callvirt set_Property(ldloc obj, binary.op(ldloc variable, ldc.i4 1))
+ // => compound.op.new(callvirt get_Property(ldloc obj), ldc.i4 1)
+ if (!(block.Instructions[i] is StLoc stloc))
+ return false;
+ if (!(stloc.Variable.IsSingleDefinition && stloc.Variable.LoadCount == 1))
+ return false;
+ var getterCall = stloc.Value as CallInstruction;
+ var setterCall = block.Instructions[i + 1] as CallInstruction;
+ if (!(MatchingGetterAndSetterCalls(getterCall, setterCall)))
+ return false;
+ var binary = setterCall.Arguments.Last() as BinaryNumericInstruction;
+ if (binary == null || !binary.Left.MatchLdLoc(stloc.Variable))
+ return false;
+ if (!CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, getterCall.Method.ReturnType))
+ return false;
+ context.Step($"Compound assignment to '{getterCall.Method.AccessorOwner.Name}'", setterCall);
+ block.Instructions.RemoveAt(i + 1); // remove setter call
+ stloc.ReplaceWith(new CompoundAssignmentInstruction(
+ binary, getterCall, binary.Right,
+ getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue));
+ return true;
+ }
+
+ static bool MatchingGetterAndSetterCalls(CallInstruction getterCall, CallInstruction setterCall)
+ {
+ if (getterCall == null || setterCall == null || !IsSameMember(getterCall.Method.AccessorOwner, setterCall.Method.AccessorOwner))
+ return false;
+ var owner = getterCall.Method.AccessorOwner as IProperty;
+ if (owner == null || !IsSameMember(getterCall.Method, owner.Getter) || !IsSameMember(setterCall.Method, owner.Setter))
+ return false;
+ if (setterCall.Arguments.Count != getterCall.Arguments.Count + 1)
+ return false;
+ // Ensure that same arguments are passed to getterCall and setterCall:
+ for (int j = 0; j < getterCall.Arguments.Count; j++) {
+ if (!SemanticHelper.IsPure(getterCall.Arguments[j].Flags))
+ return false;
+ if (!getterCall.Arguments[j].Match(setterCall.Arguments[j]).Success)
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// Transform compound assignments where the return value is not being used,
+ /// or where there's an inlined assignment within the setter call.
+ ///
+ ///
+ /// Called by ExpressionTransforms.
+ ///
+ internal static bool HandleCallCompoundAssign(CallInstruction setterCall, StatementTransformContext context)
+ {
+ // callvirt set_Property(ldloc S_1, binary.op(callvirt get_Property(ldloc S_1), value))
+ // ==> compound.op.new(callvirt(callvirt get_Property(ldloc S_1)), value)
+ var setterValue = setterCall.Arguments.LastOrDefault();
+ var storeInSetter = setterValue as StLoc;
+ if (storeInSetter != null) {
+ // callvirt set_Property(ldloc S_1, stloc v(binary.op(callvirt get_Property(ldloc S_1), value)))
+ // ==> stloc v(compound.op.new(callvirt(callvirt get_Property(ldloc S_1)), value))
+ setterValue = storeInSetter.Value;
+ }
+ if (!(setterValue is BinaryNumericInstruction binary))
+ return false;
+ var getterCall = binary.Left as CallInstruction;
+ if (!MatchingGetterAndSetterCalls(getterCall, setterCall))
+ return false;
+ if (!CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, getterCall.Method.ReturnType))
+ return false;
+ context.Step($"Compound assignment to '{getterCall.Method.AccessorOwner.Name}'", setterCall);
+ ILInstruction newInst = new CompoundAssignmentInstruction(
+ binary, getterCall, binary.Right,
+ getterCall.Method.ReturnType, CompoundAssignmentType.EvaluatesToNewValue);
+ if (storeInSetter != null) {
+ storeInSetter.Value = newInst;
+ newInst = storeInSetter;
+ context.RequestRerun(); // moving stloc to top-level might trigger inlining
+ }
+ setterCall.ReplaceWith(newInst);
+ return true;
+ }
+
///
/// stloc s(value)
/// stloc l(ldloc s)
/// -->
/// stloc s(stloc l(value))
///
- void TransformInlineAssignmentLocal(Block block, int i)
+ bool TransformInlineAssignmentLocal(Block block, int i)
{
var inst = block.Instructions[i] as StLoc;
var nextInst = block.Instructions.ElementAtOrDefault(i + 1) as StLoc;
if (inst == null || nextInst == null)
- return;
+ return false;
if (nextInst.Variable.Kind == VariableKind.StackSlot || !nextInst.Value.MatchLdLoc(inst.Variable))
- return;
+ return false;
context.Step("Inline assignment to local variable", inst);
var value = inst.Value;
var var = nextInst.Variable;
var stackVar = inst.Variable;
block.Instructions.RemoveAt(i);
nextInst.ReplaceWith(new StLoc(stackVar, new StLoc(var, value)));
+ return true;
}
///