Browse Source

Fix bug mentioned in #909

pull/927/head
Siegfried Pammer 8 years ago
parent
commit
381bd42599
  1. 13
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs
  2. 56
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il
  3. 49
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il
  4. 39
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il
  5. 46
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il
  6. 9
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  7. 59
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs
  8. 7
      ICSharpCode.Decompiler/Util/CollectionExtensions.cs

13
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs

@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return c; return c;
} }
public C Test() public C Test1()
{ {
C c = new C(); C c = new C();
c.L = new List<S>(); c.L = new List<S>();
@ -54,6 +54,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return c; return c;
} }
public C Test1Alternative()
{
return InitializerTests.TestCall(1, new C {
L = new List<S> {
new S(1)
}
});
}
public C Test2() public C Test2()
{ {
C c = new C(); C c = new C();
@ -84,8 +93,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
C c = new C(); C c = new C();
c.Y.A = 1; c.Y.A = 1;
c.Y.B = 3;
c.Z = 2; c.Z = 2;
c.Y.B = 3;
return c; return c;
} }
} }

56
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il

@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0 .ver 4:0:0:0
} }
.assembly '0zopdghu' .assembly '0meyjl4r'
{ {
.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.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 .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 .hash algorithm 0x00008004
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module '0zopdghu.dll' .module '0meyjl4r.dll'
// MVID: {56C873AC-FD1E-4808-A65A-845BA0A3C2B7} // MVID: {DBAD72F7-978F-407F-9C77-44D3E99CD8AD}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x032A0000 // Image base: 0x02FE0000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -93,7 +93,7 @@
} // end of method InitializerTests::TestCall } // end of method InitializerTests::TestCall
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test() cil managed Test1() cil managed
{ {
// Code size 42 (0x2a) // Code size 42 (0x2a)
.maxstack 2 .maxstack 2
@ -117,7 +117,39 @@
IL_0028: ldloc.1 IL_0028: ldloc.1
IL_0029: ret IL_0029: ret
} // end of method InitializerTests::Test } // end of method InitializerTests::Test1
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test1Alternative() cil managed
{
// Code size 45 (0x2d)
.maxstack 4
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C V_0,
class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S> V_1,
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C V_2)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::.ctor()
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: newobj instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::.ctor()
IL_000e: stloc.1
IL_000f: ldloc.1
IL_0010: ldc.i4.1
IL_0011: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::.ctor(int32)
IL_0016: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0)
IL_001b: nop
IL_001c: ldloc.1
IL_001d: stfld class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S> ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::L
IL_0022: ldloc.0
IL_0023: call class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests::TestCall(int32,
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C)
IL_0028: stloc.2
IL_0029: br.s IL_002b
IL_002b: ldloc.2
IL_002c: ret
} // end of method InitializerTests::Test1Alternative
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test2() cil managed Test2() cil managed
@ -212,12 +244,12 @@
IL_000d: ldc.i4.1 IL_000d: ldc.i4.1
IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A
IL_0013: ldloc.0 IL_0013: ldloc.0
IL_0014: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y IL_0014: ldc.i4.2
IL_0019: ldc.i4.3 IL_0015: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z
IL_001a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_001a: ldloc.0
IL_001f: ldloc.0 IL_001b: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y
IL_0020: ldc.i4.2 IL_0020: ldc.i4.3
IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B
IL_0026: ldloc.0 IL_0026: ldloc.0
IL_0027: stloc.1 IL_0027: stloc.1
IL_0028: br.s IL_002a IL_0028: br.s IL_002a

49
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il

@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0 .ver 4:0:0:0
} }
.assembly xvcsxiw0 .assembly u2solxiw
{ {
.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.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 .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 .hash algorithm 0x00008004
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module xvcsxiw0.dll .module u2solxiw.dll
// MVID: {ADB73224-52C3-4DFE-AB87-E9CEDD4FB2C3} // MVID: {D1507E89-2CB3-46B1-AEC7-B176088BA3F9}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x00D20000 // Image base: 0x028E0000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -86,7 +86,7 @@
} // end of method InitializerTests::TestCall } // end of method InitializerTests::TestCall
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test() cil managed Test1() cil managed
{ {
// Code size 36 (0x24) // Code size 36 (0x24)
.maxstack 2 .maxstack 2
@ -103,7 +103,32 @@
IL_001d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0) IL_001d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0)
IL_0022: ldloc.0 IL_0022: ldloc.0
IL_0023: ret IL_0023: ret
} // end of method InitializerTests::Test } // end of method InitializerTests::Test1
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test1Alternative() cil managed
{
// Code size 39 (0x27)
.maxstack 4
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C V_0,
class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S> V_1)
IL_0000: ldc.i4.1
IL_0001: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: newobj instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::.ctor()
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldc.i4.1
IL_0010: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::.ctor(int32)
IL_0015: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0)
IL_001a: ldloc.1
IL_001b: stfld class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S> ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::L
IL_0020: ldloc.0
IL_0021: call class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests::TestCall(int32,
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C)
IL_0026: ret
} // end of method InitializerTests::Test1Alternative
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test2() cil managed Test2() cil managed
@ -178,12 +203,12 @@
IL_000c: ldc.i4.1 IL_000c: ldc.i4.1
IL_000d: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_000d: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A
IL_0012: ldloc.0 IL_0012: ldloc.0
IL_0013: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y IL_0013: ldc.i4.2
IL_0018: ldc.i4.3 IL_0014: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z
IL_0019: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_0019: ldloc.0
IL_001e: ldloc.0 IL_001a: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y
IL_001f: ldc.i4.2 IL_001f: ldc.i4.3
IL_0020: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z IL_0020: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B
IL_0025: ldloc.0 IL_0025: ldloc.0
IL_0026: ret IL_0026: ret
} // end of method InitializerTests::Test4 } // end of method InitializerTests::Test4

39
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il

@ -25,14 +25,14 @@
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module InitializerTests.dll .module InitializerTests.dll
// MVID: {73C118AC-648F-43DB-A2FB-1B159DF870BA} // MVID: {F2C6C41E-98CC-4261-BF7B-1991B54DA121}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x03230000 // Image base: 0x029A0000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -90,7 +90,7 @@
} // end of method InitializerTests::TestCall } // end of method InitializerTests::TestCall
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test() cil managed Test1() cil managed
{ {
// Code size 34 (0x22) // Code size 34 (0x22)
.maxstack 8 .maxstack 8
@ -104,7 +104,26 @@
IL_0017: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::.ctor(int32) IL_0017: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::.ctor(int32)
IL_001c: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0) IL_001c: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0)
IL_0021: ret IL_0021: ret
} // end of method InitializerTests::Test } // end of method InitializerTests::Test1
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test1Alternative() cil managed
{
// Code size 35 (0x23)
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::.ctor()
IL_0006: dup
IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::.ctor()
IL_000c: dup
IL_000d: ldc.i4.1
IL_000e: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::.ctor(int32)
IL_0013: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0)
IL_0018: stfld class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S> ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::L
IL_001d: call class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests::TestCall(int32,
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C)
IL_0022: ret
} // end of method InitializerTests::Test1Alternative
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test2() cil managed Test2() cil managed
@ -168,12 +187,12 @@
IL_000b: ldc.i4.1 IL_000b: ldc.i4.1
IL_000c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_000c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A
IL_0011: dup IL_0011: dup
IL_0012: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y IL_0012: ldc.i4.2
IL_0017: ldc.i4.3 IL_0013: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z
IL_0018: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_0018: dup
IL_001d: dup IL_0019: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y
IL_001e: ldc.i4.2 IL_001e: ldc.i4.3
IL_001f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z IL_001f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B
IL_0024: ret IL_0024: ret
} // end of method InitializerTests::Test4 } // end of method InitializerTests::Test4

46
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il

@ -25,14 +25,14 @@
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module InitializerTests.dll .module InitializerTests.dll
// MVID: {53F415C2-DC80-4EFA-8787-82F129B1AC28} // MVID: {7000C1D7-C4EC-4376-B053-4BE74428CE7A}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x002F0000 // Image base: 0x00C90000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -98,7 +98,7 @@
} // end of method InitializerTests::TestCall } // end of method InitializerTests::TestCall
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test() cil managed Test1() cil managed
{ {
// Code size 42 (0x2a) // Code size 42 (0x2a)
.maxstack 2 .maxstack 2
@ -122,7 +122,33 @@
IL_0028: ldloc.1 IL_0028: ldloc.1
IL_0029: ret IL_0029: ret
} // end of method InitializerTests::Test } // end of method InitializerTests::Test1
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test1Alternative() cil managed
{
// Code size 41 (0x29)
.maxstack 6
.locals init (class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C V_0)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::.ctor()
IL_0007: dup
IL_0008: newobj instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::.ctor()
IL_000d: dup
IL_000e: ldc.i4.1
IL_000f: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::.ctor(int32)
IL_0014: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S>::Add(!0)
IL_0019: nop
IL_001a: stfld class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S> ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::L
IL_001f: call class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests::TestCall(int32,
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C)
IL_0024: stloc.0
IL_0025: br.s IL_0027
IL_0027: ldloc.0
IL_0028: ret
} // end of method InitializerTests::Test1Alternative
.method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C
Test2() cil managed Test2() cil managed
@ -214,12 +240,12 @@
IL_000d: ldc.i4.1 IL_000d: ldc.i4.1
IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A
IL_0013: ldloc.0 IL_0013: ldloc.0
IL_0014: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y IL_0014: ldc.i4.2
IL_0019: ldc.i4.3 IL_0015: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z
IL_001a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_001a: ldloc.0
IL_001f: ldloc.0 IL_001b: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y
IL_0020: ldc.i4.2 IL_0020: ldc.i4.3
IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B
IL_0026: ldloc.0 IL_0026: ldloc.0
IL_0027: stloc.1 IL_0027: stloc.1
IL_0028: br.s IL_002a IL_0028: br.s IL_002a

9
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1427,11 +1427,10 @@ namespace ICSharpCode.Decompiler.CSharp
if (currentPath == null) { if (currentPath == null) {
currentPath = info.Path; currentPath = info.Path;
} else { } else {
int firstDifferenceIndex = Math.Min(currentPath.Count, info.Path.Count); int minLen = Math.Min(currentPath.Count, info.Path.Count);
int index = 0; int firstDifferenceIndex = 0;
while (index < firstDifferenceIndex && info.Path[index] == currentPath[index]) while (firstDifferenceIndex < minLen && info.Path[firstDifferenceIndex] == currentPath[firstDifferenceIndex])
index++; firstDifferenceIndex++;
firstDifferenceIndex = index;
while (elementsStack.Count - 1 > firstDifferenceIndex) { while (elementsStack.Count - 1 > firstDifferenceIndex) {
var methodElement = currentPath[elementsStack.Count - 1]; var methodElement = currentPath[elementsStack.Count - 1];
var pathElement = currentPath[elementsStack.Count - 2]; var pathElement = currentPath[elementsStack.Count - 2];

59
ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms namespace ICSharpCode.Decompiler.IL.Transforms
{ {
@ -83,13 +84,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
int initializerItemsCount = 0; int initializerItemsCount = 0;
var blockType = initializerBlock?.Type ?? BlockType.CollectionInitializer; var blockType = initializerBlock?.Type ?? BlockType.CollectionInitializer;
var possibleIndexVariables = new Dictionary<ILVariable, (int Index, ILInstruction Value)>(); possibleIndexVariables = new Dictionary<ILVariable, (int Index, ILInstruction Value)>();
currentPath = new List<AccessPathElement>();
isCollection = false;
pathStack = new Stack<HashSet<AccessPathElement>>();
pathStack.Push(new HashSet<AccessPathElement>());
// Detect initializer type by scanning the following statements // Detect initializer type by scanning the following statements
// each must be a callvirt with ldloc v as first argument // each must be a callvirt with ldloc v as first argument
// if the method is a setter we're dealing with an object initializer // if the method is a setter we're dealing with an object initializer
// if the method is named Add and has at least 2 arguments we're dealing with a collection/dictionary initializer // if the method is named Add and has at least 2 arguments we're dealing with a collection/dictionary initializer
while (pos + initializerItemsCount + 1 < body.Instructions.Count while (pos + initializerItemsCount + 1 < body.Instructions.Count
&& IsPartOfInitializer(body.Instructions, pos + initializerItemsCount + 1, v, instType, ref blockType, possibleIndexVariables)) { && IsPartOfInitializer(body.Instructions, pos + initializerItemsCount + 1, v, instType, ref blockType)) {
initializerItemsCount++; initializerItemsCount++;
} }
var index = possibleIndexVariables.Where(info => info.Value.Index > -1).Min(info => (int?)info.Value.Index); var index = possibleIndexVariables.Where(info => info.Value.Index > -1).Min(info => (int?)info.Value.Index);
@ -139,7 +144,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; return true;
} }
bool IsPartOfInitializer(InstructionCollection<ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockType blockType, Dictionary<ILVariable, (int Index, ILInstruction Value)> possibleIndexVariables) Dictionary<ILVariable, (int Index, ILInstruction Value)> possibleIndexVariables;
List<AccessPathElement> currentPath;
bool isCollection;
Stack<HashSet<AccessPathElement>> pathStack;
bool IsPartOfInitializer(InstructionCollection<ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockType blockType)
{ {
if (instructions[pos] is StLoc stloc && stloc.Variable.Kind == VariableKind.Local && stloc.Variable.IsSingleDefinition) { if (instructions[pos] is StLoc stloc && stloc.Variable.Kind == VariableKind.Local && stloc.Variable.IsSingleDefinition) {
if (stloc.Value.Descendants.OfType<IInstructionWithVariableOperand>().Any(ld => ld.Variable == target && (ld is LdLoc || ld is LdLoca))) if (stloc.Value.Descendants.OfType<IInstructionWithVariableOperand>().Any(ld => ld.Variable == target && (ld is LdLoc || ld is LdLoca)))
@ -147,12 +157,40 @@ namespace ICSharpCode.Decompiler.IL.Transforms
possibleIndexVariables.Add(stloc.Variable, (stloc.ChildIndex, stloc.Value)); possibleIndexVariables.Add(stloc.Variable, (stloc.ChildIndex, stloc.Value));
return true; return true;
} }
(var kind, var path, var values, var targetVariable) = AccessPathElement.GetAccessPath(instructions[pos], rootType, possibleIndexVariables); (var kind, var newPath, var values, var targetVariable) = AccessPathElement.GetAccessPath(instructions[pos], rootType, possibleIndexVariables);
if (kind == AccessPathKind.Invalid || target != targetVariable)
return false;
// Treat last element separately:
// Can either be an Add method call or property setter.
var lastElement = newPath.Last();
newPath.RemoveLast();
// Compare new path with current path:
int minLen = Math.Min(currentPath.Count, newPath.Count);
int firstDifferenceIndex = 0;
while (firstDifferenceIndex < minLen && newPath[firstDifferenceIndex] == currentPath[firstDifferenceIndex])
firstDifferenceIndex++;
while (currentPath.Count > firstDifferenceIndex) {
isCollection = false;
currentPath.RemoveAt(currentPath.Count - 1);
pathStack.Pop();
}
while (currentPath.Count < newPath.Count) {
AccessPathElement newElement = newPath[currentPath.Count];
currentPath.Add(newElement);
if (isCollection || !pathStack.Peek().Add(newElement))
return false;
pathStack.Push(new HashSet<AccessPathElement>());
}
switch (kind) { switch (kind) {
case AccessPathKind.Adder: case AccessPathKind.Adder:
return target == targetVariable; isCollection = true;
if (pathStack.Peek().Count != 0)
return false;
return true;
case AccessPathKind.Setter: case AccessPathKind.Setter:
if (values.Count == 1 && target == targetVariable) { if (isCollection || !pathStack.Peek().Add(lastElement))
return false;
if (values.Count == 1) {
blockType = BlockType.ObjectInitializer; blockType = BlockType.ObjectInitializer;
return true; return true;
} }
@ -319,7 +357,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
public bool Equals(AccessPathElement other) public bool Equals(AccessPathElement other)
{ {
return other.Member.Equals(this.Member) && (other.Indices == this.Indices || other.Indices.SequenceEqual(this.Indices, ILInstructionMatchComparer.Instance)); return other.Member.Equals(this.Member)
&& (other.Indices == this.Indices || other.Indices.SequenceEqual(this.Indices, ILInstructionMatchComparer.Instance));
} }
public static bool operator ==(AccessPathElement lhs, AccessPathElement rhs) public static bool operator ==(AccessPathElement lhs, AccessPathElement rhs)
@ -343,12 +382,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; return true;
if (x == null || y == null) if (x == null || y == null)
return false; return false;
return x.Match(y).Success; return SemanticHelper.IsPure(x.Flags)
&& SemanticHelper.IsPure(y.Flags)
&& x.Match(y).Success;
} }
public int GetHashCode(ILInstruction obj) public int GetHashCode(ILInstruction obj)
{ {
return obj.GetHashCode(); throw new NotSupportedException();
} }
} }
} }

7
ICSharpCode.Decompiler/Util/CollectionExtensions.cs

@ -190,5 +190,12 @@ namespace ICSharpCode.Decompiler.Util
return maxElement; return maxElement;
} }
} }
public static void RemoveLast<T>(this IList<T> list)
{
if (list == null)
throw new ArgumentNullException(nameof(list));
list.RemoveAt(list.Count - 1);
}
} }
} }

Loading…
Cancel
Save