diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs index 352e68a17..6309f08b0 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs @@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty return c; } - public C Test() + public C Test1() { C c = new C(); c.L = new List(); @@ -54,6 +54,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty return c; } + public C Test1Alternative() + { + return InitializerTests.TestCall(1, new C { + L = new List { + new S(1) + } + }); + } + public C Test2() { C c = new C(); @@ -84,8 +93,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { C c = new C(); c.Y.A = 1; - c.Y.B = 3; c.Z = 2; + c.Y.B = 3; return c; } } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il index 88dc47267..29834fb53 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .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.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 '0zopdghu.dll' -// MVID: {56C873AC-FD1E-4808-A65A-845BA0A3C2B7} +.module '0meyjl4r.dll' +// MVID: {DBAD72F7-978F-407F-9C77-44D3E99CD8AD} .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: 0x032A0000 +// Image base: 0x02FE0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -93,7 +93,7 @@ } // end of method InitializerTests::TestCall .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C - Test() cil managed + Test1() cil managed { // Code size 42 (0x2a) .maxstack 2 @@ -117,7 +117,39 @@ IL_0028: ldloc.1 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 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::.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::Add(!0) + IL_001b: nop + IL_001c: ldloc.1 + IL_001d: stfld class [mscorlib]System.Collections.Generic.List`1 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 Test2() cil managed @@ -212,12 +244,12 @@ IL_000d: ldc.i4.1 IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_0013: ldloc.0 - IL_0014: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y - IL_0019: ldc.i4.3 - IL_001a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B - IL_001f: ldloc.0 - IL_0020: ldc.i4.2 - IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_0014: ldc.i4.2 + IL_0015: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_001a: 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.3 + IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_0026: ldloc.0 IL_0027: stloc.1 IL_0028: br.s IL_002a diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il index 9045f3b19..8de6548d9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .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.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 xvcsxiw0.dll -// MVID: {ADB73224-52C3-4DFE-AB87-E9CEDD4FB2C3} +.module u2solxiw.dll +// MVID: {D1507E89-2CB3-46B1-AEC7-B176088BA3F9} .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: 0x00D20000 +// Image base: 0x028E0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -86,7 +86,7 @@ } // end of method InitializerTests::TestCall .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C - Test() cil managed + Test1() cil managed { // Code size 36 (0x24) .maxstack 2 @@ -103,7 +103,32 @@ IL_001d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0) IL_0022: ldloc.0 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 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::.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::Add(!0) + IL_001a: ldloc.1 + IL_001b: stfld class [mscorlib]System.Collections.Generic.List`1 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 Test2() cil managed @@ -178,12 +203,12 @@ IL_000c: ldc.i4.1 IL_000d: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_0012: ldloc.0 - IL_0013: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y - IL_0018: ldc.i4.3 - IL_0019: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B - IL_001e: ldloc.0 - IL_001f: ldc.i4.2 - IL_0020: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_0013: ldc.i4.2 + IL_0014: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_0019: 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.3 + IL_0020: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_0025: ldloc.0 IL_0026: ret } // end of method InitializerTests::Test4 diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il index b4dca5b95..8b03bca83 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.opt.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .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 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x03230000 +// Image base: 0x029A0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -90,7 +90,7 @@ } // end of method InitializerTests::TestCall .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C - Test() cil managed + Test1() cil managed { // Code size 34 (0x22) .maxstack 8 @@ -104,7 +104,26 @@ 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::Add(!0) 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::.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::Add(!0) + IL_0018: stfld class [mscorlib]System.Collections.Generic.List`1 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 Test2() cil managed @@ -168,12 +187,12 @@ IL_000b: ldc.i4.1 IL_000c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_0011: dup - IL_0012: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y - IL_0017: ldc.i4.3 - IL_0018: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B - IL_001d: dup - IL_001e: ldc.i4.2 - IL_001f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_0012: ldc.i4.2 + IL_0013: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_0018: dup + IL_0019: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y + IL_001e: ldc.i4.3 + IL_001f: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_0024: ret } // end of method InitializerTests::Test4 diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il index dab3fefa3..383822da9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .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 ) .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY -// Image base: 0x002F0000 +// Image base: 0x00C90000 // =============== CLASS MEMBERS DECLARATION =================== @@ -98,7 +98,7 @@ } // end of method InitializerTests::TestCall .method public hidebysig instance class ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C - Test() cil managed + Test1() cil managed { // Code size 42 (0x2a) .maxstack 2 @@ -122,7 +122,33 @@ IL_0028: ldloc.1 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::.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::Add(!0) + IL_0019: nop + IL_001a: stfld class [mscorlib]System.Collections.Generic.List`1 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 Test2() cil managed @@ -214,12 +240,12 @@ IL_000d: ldc.i4.1 IL_000e: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::A IL_0013: ldloc.0 - IL_0014: ldflda valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Y - IL_0019: ldc.i4.3 - IL_001a: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B - IL_001f: ldloc.0 - IL_0020: ldc.i4.2 - IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_0014: ldc.i4.2 + IL_0015: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/C::Z + IL_001a: 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.3 + IL_0021: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests/S::B IL_0026: ldloc.0 IL_0027: stloc.1 IL_0028: br.s IL_002a diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 25ed0ddb3..7aec147d5 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1427,11 +1427,10 @@ namespace ICSharpCode.Decompiler.CSharp if (currentPath == null) { currentPath = info.Path; } else { - int firstDifferenceIndex = Math.Min(currentPath.Count, info.Path.Count); - int index = 0; - while (index < firstDifferenceIndex && info.Path[index] == currentPath[index]) - index++; - firstDifferenceIndex = index; + int minLen = Math.Min(currentPath.Count, info.Path.Count); + int firstDifferenceIndex = 0; + while (firstDifferenceIndex < minLen && info.Path[firstDifferenceIndex] == currentPath[firstDifferenceIndex]) + firstDifferenceIndex++; while (elementsStack.Count - 1 > firstDifferenceIndex) { var methodElement = currentPath[elementsStack.Count - 1]; var pathElement = currentPath[elementsStack.Count - 2]; diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs index 1e66d3b1e..e01b58a84 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Linq; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.IL.Transforms { @@ -83,13 +84,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms } int initializerItemsCount = 0; var blockType = initializerBlock?.Type ?? BlockType.CollectionInitializer; - var possibleIndexVariables = new Dictionary(); + possibleIndexVariables = new Dictionary(); + currentPath = new List(); + isCollection = false; + pathStack = new Stack>(); + pathStack.Push(new HashSet()); // Detect initializer type by scanning the following statements // 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 named Add and has at least 2 arguments we're dealing with a collection/dictionary initializer 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++; } 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; } - bool IsPartOfInitializer(InstructionCollection instructions, int pos, ILVariable target, IType rootType, ref BlockType blockType, Dictionary possibleIndexVariables) + Dictionary possibleIndexVariables; + List currentPath; + bool isCollection; + Stack> pathStack; + + bool IsPartOfInitializer(InstructionCollection 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 (stloc.Value.Descendants.OfType().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)); 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()); + } switch (kind) { case AccessPathKind.Adder: - return target == targetVariable; + isCollection = true; + if (pathStack.Peek().Count != 0) + return false; + return true; case AccessPathKind.Setter: - if (values.Count == 1 && target == targetVariable) { + if (isCollection || !pathStack.Peek().Add(lastElement)) + return false; + if (values.Count == 1) { blockType = BlockType.ObjectInitializer; return true; } @@ -319,7 +357,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms 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) @@ -343,12 +382,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms return true; if (x == null || y == null) 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) { - return obj.GetHashCode(); + throw new NotSupportedException(); } } } diff --git a/ICSharpCode.Decompiler/Util/CollectionExtensions.cs b/ICSharpCode.Decompiler/Util/CollectionExtensions.cs index d6f67cae8..df1785c7e 100644 --- a/ICSharpCode.Decompiler/Util/CollectionExtensions.cs +++ b/ICSharpCode.Decompiler/Util/CollectionExtensions.cs @@ -190,5 +190,12 @@ namespace ICSharpCode.Decompiler.Util return maxElement; } } + + public static void RemoveLast(this IList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + list.RemoveAt(list.Count - 1); + } } }