diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs index 9b45c0f30..46e84646f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs @@ -495,7 +495,38 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty item.TestCall(); } } - #endregion + + public void ForEachOverMultiDimArray(int[,] items) + { + foreach (int value in items) { + Console.WriteLine(value); + Console.WriteLine(value); + } + } + + public void ForEachOverMultiDimArray2(int[,,] items) + { + foreach (int value in items) { + Console.WriteLine(value); + Console.WriteLine(value); + } + } + + public unsafe void ForEachOverMultiDimArray3(int*[,] items) + { +#if ROSLYN && OPT + foreach (int* intPtr in items) { + Console.WriteLine(*intPtr); + Console.WriteLine(*intPtr); + } +#else + foreach (int* ptr in items) { + Console.WriteLine(*ptr); + Console.WriteLine(*ptr); + } +#endif + } +#endregion public void ForOverArray(string[] array) { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il index 36e65e870..5ead7472c 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly gc5hv5wh +.assembly '50bjvac5' { .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 gc5hv5wh.dll -// MVID: {062C7BAF-1AEF-4973-83C5-A0DC279703B8} +.module '50bjvac5.dll' +// MVID: {7EA9F0A8-B896-4F84-BCD8-AC7B4D44BBC0} .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: 0x038E0000 +// Image base: 0x03450000 // =============== CLASS MEMBERS DECLARATION =================== @@ -1901,6 +1901,272 @@ IL_003a: ret } // end of method Loops::ForEachOverListOfStruct3 + .method public hidebysig instance void + ForEachOverMultiDimArray(int32[0...,0...] items) cil managed + { + // Code size 110 (0x6e) + .maxstack 3 + .locals init (int32 V_0, + int32[0...,0...] V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5, + bool V_6) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: stloc.1 + IL_0004: ldloc.1 + IL_0005: ldc.i4.0 + IL_0006: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_000b: stloc.2 + IL_000c: ldloc.1 + IL_000d: ldc.i4.1 + IL_000e: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0013: stloc.3 + IL_0014: ldloc.1 + IL_0015: ldc.i4.0 + IL_0016: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_001b: stloc.s V_4 + IL_001d: br.s IL_005f + + IL_001f: ldloc.1 + IL_0020: ldc.i4.1 + IL_0021: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0026: stloc.s V_5 + IL_0028: br.s IL_004b + + IL_002a: ldloc.1 + IL_002b: ldloc.s V_4 + IL_002d: ldloc.s V_5 + IL_002f: call instance int32 int32[0...,0...]::Get(int32, + int32) + IL_0034: stloc.0 + IL_0035: nop + IL_0036: ldloc.0 + IL_0037: call void [mscorlib]System.Console::WriteLine(int32) + IL_003c: nop + IL_003d: ldloc.0 + IL_003e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0043: nop + IL_0044: nop + IL_0045: ldloc.s V_5 + IL_0047: ldc.i4.1 + IL_0048: add + IL_0049: stloc.s V_5 + IL_004b: ldloc.s V_5 + IL_004d: ldloc.3 + IL_004e: cgt + IL_0050: ldc.i4.0 + IL_0051: ceq + IL_0053: stloc.s V_6 + IL_0055: ldloc.s V_6 + IL_0057: brtrue.s IL_002a + + IL_0059: ldloc.s V_4 + IL_005b: ldc.i4.1 + IL_005c: add + IL_005d: stloc.s V_4 + IL_005f: ldloc.s V_4 + IL_0061: ldloc.2 + IL_0062: cgt + IL_0064: ldc.i4.0 + IL_0065: ceq + IL_0067: stloc.s V_6 + IL_0069: ldloc.s V_6 + IL_006b: brtrue.s IL_001f + + IL_006d: ret + } // end of method Loops::ForEachOverMultiDimArray + + .method public hidebysig instance void + ForEachOverMultiDimArray2(int32[0...,0...,0...] items) cil managed + { + // Code size 153 (0x99) + .maxstack 4 + .locals init (int32 V_0, + int32[0...,0...,0...] V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5, + int32 V_6, + int32 V_7, + bool V_8) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: stloc.1 + IL_0004: ldloc.1 + IL_0005: ldc.i4.0 + IL_0006: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_000b: stloc.2 + IL_000c: ldloc.1 + IL_000d: ldc.i4.1 + IL_000e: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0013: stloc.3 + IL_0014: ldloc.1 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_001b: stloc.s V_4 + IL_001d: ldloc.1 + IL_001e: ldc.i4.0 + IL_001f: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0024: stloc.s V_5 + IL_0026: br.s IL_008a + + IL_0028: ldloc.1 + IL_0029: ldc.i4.1 + IL_002a: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_002f: stloc.s V_6 + IL_0031: br.s IL_0076 + + IL_0033: ldloc.1 + IL_0034: ldc.i4.2 + IL_0035: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_003a: stloc.s V_7 + IL_003c: br.s IL_0061 + + IL_003e: ldloc.1 + IL_003f: ldloc.s V_5 + IL_0041: ldloc.s V_6 + IL_0043: ldloc.s V_7 + IL_0045: call instance int32 int32[0...,0...,0...]::Get(int32, + int32, + int32) + IL_004a: stloc.0 + IL_004b: nop + IL_004c: ldloc.0 + IL_004d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0052: nop + IL_0053: ldloc.0 + IL_0054: call void [mscorlib]System.Console::WriteLine(int32) + IL_0059: nop + IL_005a: nop + IL_005b: ldloc.s V_7 + IL_005d: ldc.i4.1 + IL_005e: add + IL_005f: stloc.s V_7 + IL_0061: ldloc.s V_7 + IL_0063: ldloc.s V_4 + IL_0065: cgt + IL_0067: ldc.i4.0 + IL_0068: ceq + IL_006a: stloc.s V_8 + IL_006c: ldloc.s V_8 + IL_006e: brtrue.s IL_003e + + IL_0070: ldloc.s V_6 + IL_0072: ldc.i4.1 + IL_0073: add + IL_0074: stloc.s V_6 + IL_0076: ldloc.s V_6 + IL_0078: ldloc.3 + IL_0079: cgt + IL_007b: ldc.i4.0 + IL_007c: ceq + IL_007e: stloc.s V_8 + IL_0080: ldloc.s V_8 + IL_0082: brtrue.s IL_0033 + + IL_0084: ldloc.s V_5 + IL_0086: ldc.i4.1 + IL_0087: add + IL_0088: stloc.s V_5 + IL_008a: ldloc.s V_5 + IL_008c: ldloc.2 + IL_008d: cgt + IL_008f: ldc.i4.0 + IL_0090: ceq + IL_0092: stloc.s V_8 + IL_0094: ldloc.s V_8 + IL_0096: brtrue.s IL_0028 + + IL_0098: ret + } // end of method Loops::ForEachOverMultiDimArray2 + + .method public hidebysig instance void + ForEachOverMultiDimArray3(int32*[0...,0...] items) cil managed + { + // Code size 112 (0x70) + .maxstack 3 + .locals init (int32* V_0, + int32*[0...,0...] V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5, + bool V_6) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: stloc.1 + IL_0004: ldloc.1 + IL_0005: ldc.i4.0 + IL_0006: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_000b: stloc.2 + IL_000c: ldloc.1 + IL_000d: ldc.i4.1 + IL_000e: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0013: stloc.3 + IL_0014: ldloc.1 + IL_0015: ldc.i4.0 + IL_0016: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_001b: stloc.s V_4 + IL_001d: br.s IL_0061 + + IL_001f: ldloc.1 + IL_0020: ldc.i4.1 + IL_0021: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0026: stloc.s V_5 + IL_0028: br.s IL_004d + + IL_002a: ldloc.1 + IL_002b: ldloc.s V_4 + IL_002d: ldloc.s V_5 + IL_002f: call instance int32* int32*[0...,0...]::Get(int32, + int32) + IL_0034: stloc.0 + IL_0035: nop + IL_0036: ldloc.0 + IL_0037: ldind.i4 + IL_0038: call void [mscorlib]System.Console::WriteLine(int32) + IL_003d: nop + IL_003e: ldloc.0 + IL_003f: ldind.i4 + IL_0040: call void [mscorlib]System.Console::WriteLine(int32) + IL_0045: nop + IL_0046: nop + IL_0047: ldloc.s V_5 + IL_0049: ldc.i4.1 + IL_004a: add + IL_004b: stloc.s V_5 + IL_004d: ldloc.s V_5 + IL_004f: ldloc.3 + IL_0050: cgt + IL_0052: ldc.i4.0 + IL_0053: ceq + IL_0055: stloc.s V_6 + IL_0057: ldloc.s V_6 + IL_0059: brtrue.s IL_002a + + IL_005b: ldloc.s V_4 + IL_005d: ldc.i4.1 + IL_005e: add + IL_005f: stloc.s V_4 + IL_0061: ldloc.s V_4 + IL_0063: ldloc.2 + IL_0064: cgt + IL_0066: ldc.i4.0 + IL_0067: ceq + IL_0069: stloc.s V_6 + IL_006b: ldloc.s V_6 + IL_006d: brtrue.s IL_001f + + IL_006f: ret + } // end of method Loops::ForEachOverMultiDimArray3 + .method public hidebysig instance void ForOverArray(string[] 'array') cil managed { @@ -2352,7 +2618,7 @@ .method public hidebysig instance void ForeachLoopWithEarlyReturn(class [mscorlib]System.Collections.Generic.List`1 items) cil managed { - // Code size 73 (0x49) + // Code size 74 (0x4a) .maxstack 3 .locals init (object V_0, valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_1, @@ -2365,7 +2631,7 @@ IL_0008: stloc.1 .try { - IL_0009: br.s IL_002b + IL_0009: br.s IL_002c IL_000b: ldloca.s V_1 IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() @@ -2383,30 +2649,31 @@ IL_0022: ceq IL_0024: stloc.3 IL_0025: ldloc.3 - IL_0026: brtrue.s IL_002a + IL_0026: brtrue.s IL_002b - IL_0028: br.s IL_0036 + IL_0028: nop + IL_0029: br.s IL_0037 - IL_002a: nop - IL_002b: ldloca.s V_1 - IL_002d: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() - IL_0032: stloc.3 - IL_0033: ldloc.3 - IL_0034: brtrue.s IL_000b + IL_002b: nop + IL_002c: ldloca.s V_1 + IL_002e: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0033: stloc.3 + IL_0034: ldloc.3 + IL_0035: brtrue.s IL_000b - IL_0036: leave.s IL_0047 + IL_0037: leave.s IL_0048 } // end .try finally { - IL_0038: ldloca.s V_1 - IL_003a: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator - IL_0040: callvirt instance void [mscorlib]System.IDisposable::Dispose() - IL_0045: nop - IL_0046: endfinally + IL_0039: ldloca.s V_1 + IL_003b: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_0041: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0046: nop + IL_0047: endfinally } // end handler - IL_0047: nop - IL_0048: ret + IL_0048: nop + IL_0049: ret } // end of method Loops::ForeachLoopWithEarlyReturn .method public hidebysig specialname rtspecialname diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il index ded149edc..85c9a754c 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il @@ -10,7 +10,7 @@ .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } -.assembly iyvgltxy +.assembly ca3webe1 { .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 iyvgltxy.dll -// MVID: {29F6B869-DC6A-4F23-A073-750A25BF2F78} +.module ca3webe1.dll +// MVID: {3674B35A-51F1-4E0A-A67E-D7FEBA11373B} .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: 0x01130000 +// Image base: 0x02DA0000 // =============== CLASS MEMBERS DECLARATION =================== @@ -1528,6 +1528,216 @@ IL_0031: ret } // end of method Loops::ForEachOverListOfStruct3 + .method public hidebysig instance void + ForEachOverMultiDimArray(int32[0...,0...] items) cil managed + { + // Code size 86 (0x56) + .maxstack 3 + .locals init (int32 V_0, + int32[0...,0...] V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5) + IL_0000: ldarg.1 + IL_0001: stloc.1 + IL_0002: ldloc.1 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0009: stloc.2 + IL_000a: ldloc.1 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0011: stloc.3 + IL_0012: ldloc.1 + IL_0013: ldc.i4.0 + IL_0014: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0019: stloc.s V_4 + IL_001b: br.s IL_0050 + + IL_001d: ldloc.1 + IL_001e: ldc.i4.1 + IL_001f: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0024: stloc.s V_5 + IL_0026: br.s IL_0045 + + IL_0028: ldloc.1 + IL_0029: ldloc.s V_4 + IL_002b: ldloc.s V_5 + IL_002d: call instance int32 int32[0...,0...]::Get(int32, + int32) + IL_0032: stloc.0 + IL_0033: ldloc.0 + IL_0034: call void [mscorlib]System.Console::WriteLine(int32) + IL_0039: ldloc.0 + IL_003a: call void [mscorlib]System.Console::WriteLine(int32) + IL_003f: ldloc.s V_5 + IL_0041: ldc.i4.1 + IL_0042: add + IL_0043: stloc.s V_5 + IL_0045: ldloc.s V_5 + IL_0047: ldloc.3 + IL_0048: ble.s IL_0028 + + IL_004a: ldloc.s V_4 + IL_004c: ldc.i4.1 + IL_004d: add + IL_004e: stloc.s V_4 + IL_0050: ldloc.s V_4 + IL_0052: ldloc.2 + IL_0053: ble.s IL_001d + + IL_0055: ret + } // end of method Loops::ForEachOverMultiDimArray + + .method public hidebysig instance void + ForEachOverMultiDimArray2(int32[0...,0...,0...] items) cil managed + { + // Code size 120 (0x78) + .maxstack 4 + .locals init (int32 V_0, + int32[0...,0...,0...] V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5, + int32 V_6, + int32 V_7) + IL_0000: ldarg.1 + IL_0001: stloc.1 + IL_0002: ldloc.1 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0009: stloc.2 + IL_000a: ldloc.1 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0011: stloc.3 + IL_0012: ldloc.1 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0019: stloc.s V_4 + IL_001b: ldloc.1 + IL_001c: ldc.i4.0 + IL_001d: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0022: stloc.s V_5 + IL_0024: br.s IL_0072 + + IL_0026: ldloc.1 + IL_0027: ldc.i4.1 + IL_0028: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_002d: stloc.s V_6 + IL_002f: br.s IL_0067 + + IL_0031: ldloc.1 + IL_0032: ldc.i4.2 + IL_0033: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0038: stloc.s V_7 + IL_003a: br.s IL_005b + + IL_003c: ldloc.1 + IL_003d: ldloc.s V_5 + IL_003f: ldloc.s V_6 + IL_0041: ldloc.s V_7 + IL_0043: call instance int32 int32[0...,0...,0...]::Get(int32, + int32, + int32) + IL_0048: stloc.0 + IL_0049: ldloc.0 + IL_004a: call void [mscorlib]System.Console::WriteLine(int32) + IL_004f: ldloc.0 + IL_0050: call void [mscorlib]System.Console::WriteLine(int32) + IL_0055: ldloc.s V_7 + IL_0057: ldc.i4.1 + IL_0058: add + IL_0059: stloc.s V_7 + IL_005b: ldloc.s V_7 + IL_005d: ldloc.s V_4 + IL_005f: ble.s IL_003c + + IL_0061: ldloc.s V_6 + IL_0063: ldc.i4.1 + IL_0064: add + IL_0065: stloc.s V_6 + IL_0067: ldloc.s V_6 + IL_0069: ldloc.3 + IL_006a: ble.s IL_0031 + + IL_006c: ldloc.s V_5 + IL_006e: ldc.i4.1 + IL_006f: add + IL_0070: stloc.s V_5 + IL_0072: ldloc.s V_5 + IL_0074: ldloc.2 + IL_0075: ble.s IL_0026 + + IL_0077: ret + } // end of method Loops::ForEachOverMultiDimArray2 + + .method public hidebysig instance void + ForEachOverMultiDimArray3(int32*[0...,0...] items) cil managed + { + // Code size 88 (0x58) + .maxstack 3 + .locals init (int32* V_0, + int32*[0...,0...] V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5) + IL_0000: ldarg.1 + IL_0001: stloc.1 + IL_0002: ldloc.1 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0009: stloc.2 + IL_000a: ldloc.1 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0011: stloc.3 + IL_0012: ldloc.1 + IL_0013: ldc.i4.0 + IL_0014: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0019: stloc.s V_4 + IL_001b: br.s IL_0052 + + IL_001d: ldloc.1 + IL_001e: ldc.i4.1 + IL_001f: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0024: stloc.s V_5 + IL_0026: br.s IL_0047 + + IL_0028: ldloc.1 + IL_0029: ldloc.s V_4 + IL_002b: ldloc.s V_5 + IL_002d: call instance int32* int32*[0...,0...]::Get(int32, + int32) + IL_0032: stloc.0 + IL_0033: ldloc.0 + IL_0034: ldind.i4 + IL_0035: call void [mscorlib]System.Console::WriteLine(int32) + IL_003a: ldloc.0 + IL_003b: ldind.i4 + IL_003c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0041: ldloc.s V_5 + IL_0043: ldc.i4.1 + IL_0044: add + IL_0045: stloc.s V_5 + IL_0047: ldloc.s V_5 + IL_0049: ldloc.3 + IL_004a: ble.s IL_0028 + + IL_004c: ldloc.s V_4 + IL_004e: ldc.i4.1 + IL_004f: add + IL_0050: stloc.s V_4 + IL_0052: ldloc.s V_4 + IL_0054: ldloc.2 + IL_0055: ble.s IL_001d + + IL_0057: ret + } // end of method Loops::ForEachOverMultiDimArray3 + .method public hidebysig instance void ForOverArray(string[] 'array') cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il index 40c9a5c84..81e85acc4 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .module Loops.dll -// MVID: {781CB7F6-E31A-4804-B6CA-CB8C7FDF34DA} +// MVID: {F07742D5-57A8-4CEC-B130-8CFD8D8E0AFC} .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: 0x03730000 +// Image base: 0x04780000 // =============== CLASS MEMBERS DECLARATION =================== @@ -1481,6 +1481,207 @@ IL_0031: ret } // end of method Loops::ForEachOverListOfStruct3 + .method public hidebysig instance void + ForEachOverMultiDimArray(int32[0...,0...] items) cil managed + { + // Code size 79 (0x4f) + .maxstack 3 + .locals init (int32[0...,0...] V_0, + int32 V_1, + int32 V_2, + int32 V_3, + int32 V_4) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0009: stloc.1 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0011: stloc.2 + IL_0012: ldloc.0 + IL_0013: ldc.i4.0 + IL_0014: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0019: stloc.3 + IL_001a: br.s IL_004a + + IL_001c: ldloc.0 + IL_001d: ldc.i4.1 + IL_001e: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0023: stloc.s V_4 + IL_0025: br.s IL_0041 + + IL_0027: ldloc.0 + IL_0028: ldloc.3 + IL_0029: ldloc.s V_4 + IL_002b: call instance int32 int32[0...,0...]::Get(int32, + int32) + IL_0030: dup + IL_0031: call void [mscorlib]System.Console::WriteLine(int32) + IL_0036: call void [mscorlib]System.Console::WriteLine(int32) + IL_003b: ldloc.s V_4 + IL_003d: ldc.i4.1 + IL_003e: add + IL_003f: stloc.s V_4 + IL_0041: ldloc.s V_4 + IL_0043: ldloc.2 + IL_0044: ble.s IL_0027 + + IL_0046: ldloc.3 + IL_0047: ldc.i4.1 + IL_0048: add + IL_0049: stloc.3 + IL_004a: ldloc.3 + IL_004b: ldloc.1 + IL_004c: ble.s IL_001c + + IL_004e: ret + } // end of method Loops::ForEachOverMultiDimArray + + .method public hidebysig instance void + ForEachOverMultiDimArray2(int32[0...,0...,0...] items) cil managed + { + // Code size 116 (0x74) + .maxstack 4 + .locals init (int32[0...,0...,0...] V_0, + int32 V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5, + int32 V_6) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0009: stloc.1 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0011: stloc.2 + IL_0012: ldloc.0 + IL_0013: ldc.i4.2 + IL_0014: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0019: stloc.3 + IL_001a: ldloc.0 + IL_001b: ldc.i4.0 + IL_001c: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0021: stloc.s V_4 + IL_0023: br.s IL_006e + + IL_0025: ldloc.0 + IL_0026: ldc.i4.1 + IL_0027: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_002c: stloc.s V_5 + IL_002e: br.s IL_0063 + + IL_0030: ldloc.0 + IL_0031: ldc.i4.2 + IL_0032: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0037: stloc.s V_6 + IL_0039: br.s IL_0058 + + IL_003b: ldloc.0 + IL_003c: ldloc.s V_4 + IL_003e: ldloc.s V_5 + IL_0040: ldloc.s V_6 + IL_0042: call instance int32 int32[0...,0...,0...]::Get(int32, + int32, + int32) + IL_0047: dup + IL_0048: call void [mscorlib]System.Console::WriteLine(int32) + IL_004d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0052: ldloc.s V_6 + IL_0054: ldc.i4.1 + IL_0055: add + IL_0056: stloc.s V_6 + IL_0058: ldloc.s V_6 + IL_005a: ldloc.3 + IL_005b: ble.s IL_003b + + IL_005d: ldloc.s V_5 + IL_005f: ldc.i4.1 + IL_0060: add + IL_0061: stloc.s V_5 + IL_0063: ldloc.s V_5 + IL_0065: ldloc.2 + IL_0066: ble.s IL_0030 + + IL_0068: ldloc.s V_4 + IL_006a: ldc.i4.1 + IL_006b: add + IL_006c: stloc.s V_4 + IL_006e: ldloc.s V_4 + IL_0070: ldloc.1 + IL_0071: ble.s IL_0025 + + IL_0073: ret + } // end of method Loops::ForEachOverMultiDimArray2 + + .method public hidebysig instance void + ForEachOverMultiDimArray3(int32*[0...,0...] items) cil managed + { + // Code size 81 (0x51) + .maxstack 3 + .locals init (int32*[0...,0...] V_0, + int32 V_1, + int32 V_2, + int32 V_3, + int32 V_4) + IL_0000: ldarg.1 + IL_0001: stloc.0 + IL_0002: ldloc.0 + IL_0003: ldc.i4.0 + IL_0004: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0009: stloc.1 + IL_000a: ldloc.0 + IL_000b: ldc.i4.1 + IL_000c: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0011: stloc.2 + IL_0012: ldloc.0 + IL_0013: ldc.i4.0 + IL_0014: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0019: stloc.3 + IL_001a: br.s IL_004c + + IL_001c: ldloc.0 + IL_001d: ldc.i4.1 + IL_001e: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0023: stloc.s V_4 + IL_0025: br.s IL_0043 + + IL_0027: ldloc.0 + IL_0028: ldloc.3 + IL_0029: ldloc.s V_4 + IL_002b: call instance int32* int32*[0...,0...]::Get(int32, + int32) + IL_0030: dup + IL_0031: ldind.i4 + IL_0032: call void [mscorlib]System.Console::WriteLine(int32) + IL_0037: ldind.i4 + IL_0038: call void [mscorlib]System.Console::WriteLine(int32) + IL_003d: ldloc.s V_4 + IL_003f: ldc.i4.1 + IL_0040: add + IL_0041: stloc.s V_4 + IL_0043: ldloc.s V_4 + IL_0045: ldloc.2 + IL_0046: ble.s IL_0027 + + IL_0048: ldloc.3 + IL_0049: ldc.i4.1 + IL_004a: add + IL_004b: stloc.3 + IL_004c: ldloc.3 + IL_004d: ldloc.1 + IL_004e: ble.s IL_001c + + IL_0050: ret + } // end of method Loops::ForEachOverMultiDimArray3 + .method public hidebysig instance void ForOverArray(string[] 'array') cil managed { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il index 21100b415..5c15860a0 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il @@ -25,14 +25,14 @@ .ver 0:0:0:0 } .module Loops.dll -// MVID: {673E7ABD-594F-4CEA-B653-2C92D7588EE4} +// MVID: {FFD462DB-4ADF-4242-B780-E01C783B2038} .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: 0x033F0000 +// Image base: 0x04F90000 // =============== CLASS MEMBERS DECLARATION =================== @@ -1771,6 +1771,234 @@ IL_0037: ret } // end of method Loops::ForEachOverListOfStruct3 + .method public hidebysig instance void + ForEachOverMultiDimArray(int32[0...,0...] items) cil managed + { + // Code size 90 (0x5a) + .maxstack 3 + .locals init (int32[0...,0...] V_0, + int32 V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: stloc.0 + IL_0004: ldloc.0 + IL_0005: ldc.i4.0 + IL_0006: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_000b: stloc.1 + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0013: stloc.2 + IL_0014: ldloc.0 + IL_0015: ldc.i4.0 + IL_0016: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_001b: stloc.3 + IL_001c: br.s IL_0055 + + IL_001e: ldloc.0 + IL_001f: ldc.i4.1 + IL_0020: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0025: stloc.s V_4 + IL_0027: br.s IL_004c + + IL_0029: ldloc.0 + IL_002a: ldloc.3 + IL_002b: ldloc.s V_4 + IL_002d: call instance int32 int32[0...,0...]::Get(int32, + int32) + IL_0032: stloc.s V_5 + IL_0034: nop + IL_0035: ldloc.s V_5 + IL_0037: call void [mscorlib]System.Console::WriteLine(int32) + IL_003c: nop + IL_003d: ldloc.s V_5 + IL_003f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0044: nop + IL_0045: nop + IL_0046: ldloc.s V_4 + IL_0048: ldc.i4.1 + IL_0049: add + IL_004a: stloc.s V_4 + IL_004c: ldloc.s V_4 + IL_004e: ldloc.2 + IL_004f: ble.s IL_0029 + + IL_0051: ldloc.3 + IL_0052: ldc.i4.1 + IL_0053: add + IL_0054: stloc.3 + IL_0055: ldloc.3 + IL_0056: ldloc.1 + IL_0057: ble.s IL_001e + + IL_0059: ret + } // end of method Loops::ForEachOverMultiDimArray + + .method public hidebysig instance void + ForEachOverMultiDimArray2(int32[0...,0...,0...] items) cil managed + { + // Code size 127 (0x7f) + .maxstack 4 + .locals init (int32[0...,0...,0...] V_0, + int32 V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32 V_5, + int32 V_6, + int32 V_7) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: stloc.0 + IL_0004: ldloc.0 + IL_0005: ldc.i4.0 + IL_0006: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_000b: stloc.1 + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0013: stloc.2 + IL_0014: ldloc.0 + IL_0015: ldc.i4.2 + IL_0016: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_001b: stloc.3 + IL_001c: ldloc.0 + IL_001d: ldc.i4.0 + IL_001e: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0023: stloc.s V_4 + IL_0025: br.s IL_0079 + + IL_0027: ldloc.0 + IL_0028: ldc.i4.1 + IL_0029: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_002e: stloc.s V_5 + IL_0030: br.s IL_006e + + IL_0032: ldloc.0 + IL_0033: ldc.i4.2 + IL_0034: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0039: stloc.s V_6 + IL_003b: br.s IL_0063 + + IL_003d: ldloc.0 + IL_003e: ldloc.s V_4 + IL_0040: ldloc.s V_5 + IL_0042: ldloc.s V_6 + IL_0044: call instance int32 int32[0...,0...,0...]::Get(int32, + int32, + int32) + IL_0049: stloc.s V_7 + IL_004b: nop + IL_004c: ldloc.s V_7 + IL_004e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0053: nop + IL_0054: ldloc.s V_7 + IL_0056: call void [mscorlib]System.Console::WriteLine(int32) + IL_005b: nop + IL_005c: nop + IL_005d: ldloc.s V_6 + IL_005f: ldc.i4.1 + IL_0060: add + IL_0061: stloc.s V_6 + IL_0063: ldloc.s V_6 + IL_0065: ldloc.3 + IL_0066: ble.s IL_003d + + IL_0068: ldloc.s V_5 + IL_006a: ldc.i4.1 + IL_006b: add + IL_006c: stloc.s V_5 + IL_006e: ldloc.s V_5 + IL_0070: ldloc.2 + IL_0071: ble.s IL_0032 + + IL_0073: ldloc.s V_4 + IL_0075: ldc.i4.1 + IL_0076: add + IL_0077: stloc.s V_4 + IL_0079: ldloc.s V_4 + IL_007b: ldloc.1 + IL_007c: ble.s IL_0027 + + IL_007e: ret + } // end of method Loops::ForEachOverMultiDimArray2 + + .method public hidebysig instance void + ForEachOverMultiDimArray3(int32*[0...,0...] items) cil managed + { + // Code size 92 (0x5c) + .maxstack 3 + .locals init (int32*[0...,0...] V_0, + int32 V_1, + int32 V_2, + int32 V_3, + int32 V_4, + int32* V_5) + IL_0000: nop + IL_0001: nop + IL_0002: ldarg.1 + IL_0003: stloc.0 + IL_0004: ldloc.0 + IL_0005: ldc.i4.0 + IL_0006: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_000b: stloc.1 + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: callvirt instance int32 [mscorlib]System.Array::GetUpperBound(int32) + IL_0013: stloc.2 + IL_0014: ldloc.0 + IL_0015: ldc.i4.0 + IL_0016: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_001b: stloc.3 + IL_001c: br.s IL_0057 + + IL_001e: ldloc.0 + IL_001f: ldc.i4.1 + IL_0020: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + IL_0025: stloc.s V_4 + IL_0027: br.s IL_004e + + IL_0029: ldloc.0 + IL_002a: ldloc.3 + IL_002b: ldloc.s V_4 + IL_002d: call instance int32* int32*[0...,0...]::Get(int32, + int32) + IL_0032: stloc.s V_5 + IL_0034: nop + IL_0035: ldloc.s V_5 + IL_0037: ldind.i4 + IL_0038: call void [mscorlib]System.Console::WriteLine(int32) + IL_003d: nop + IL_003e: ldloc.s V_5 + IL_0040: ldind.i4 + IL_0041: call void [mscorlib]System.Console::WriteLine(int32) + IL_0046: nop + IL_0047: nop + IL_0048: ldloc.s V_4 + IL_004a: ldc.i4.1 + IL_004b: add + IL_004c: stloc.s V_4 + IL_004e: ldloc.s V_4 + IL_0050: ldloc.2 + IL_0051: ble.s IL_0029 + + IL_0053: ldloc.3 + IL_0054: ldc.i4.1 + IL_0055: add + IL_0056: stloc.3 + IL_0057: ldloc.3 + IL_0058: ldloc.1 + IL_0059: ble.s IL_001e + + IL_005b: ret + } // end of method Loops::ForEachOverMultiDimArray3 + .method public hidebysig instance void ForOverArray(string[] 'array') cil managed { @@ -2217,7 +2445,7 @@ .method public hidebysig instance void ForeachLoopWithEarlyReturn(class [mscorlib]System.Collections.Generic.List`1 items) cil managed { - // Code size 67 (0x43) + // Code size 68 (0x44) .maxstack 3 .locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator V_0, object V_1, @@ -2230,7 +2458,7 @@ IL_0008: stloc.0 .try { - IL_0009: br.s IL_0028 + IL_0009: br.s IL_0029 IL_000b: ldloca.s V_0 IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::get_Current() @@ -2246,27 +2474,28 @@ IL_001f: ceq IL_0021: stloc.2 IL_0022: ldloc.2 - IL_0023: brfalse.s IL_0027 + IL_0023: brfalse.s IL_0028 - IL_0025: br.s IL_0031 + IL_0025: nop + IL_0026: br.s IL_0032 - IL_0027: nop - IL_0028: ldloca.s V_0 - IL_002a: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() - IL_002f: brtrue.s IL_000b + IL_0028: nop + IL_0029: ldloca.s V_0 + IL_002b: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator::MoveNext() + IL_0030: brtrue.s IL_000b - IL_0031: leave.s IL_0042 + IL_0032: leave.s IL_0043 } // end .try finally { - IL_0033: ldloca.s V_0 - IL_0035: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator - IL_003b: callvirt instance void [mscorlib]System.IDisposable::Dispose() - IL_0040: nop - IL_0041: endfinally + IL_0034: ldloca.s V_0 + IL_0036: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator + IL_003c: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0041: nop + IL_0042: endfinally } // end handler - IL_0042: ret + IL_0043: ret } // end of method Loops::ForeachLoopWithEarlyReturn .method public hidebysig specialname rtspecialname diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs index cef6c8b52..10e27db79 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs @@ -72,7 +72,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms public override AstNode VisitExpressionStatement(ExpressionStatement expressionStatement) { - AstNode result = TransformFor(expressionStatement); + AstNode result = TransformForeachOnMultiDimArray(expressionStatement); + if (result != null) + return result; + result = TransformFor(expressionStatement); if (result != null) return result; if (context.Settings.AutomaticProperties) { @@ -269,6 +272,164 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms return foreachStmt; } + static readonly ForStatement forOnArrayMultiDimPattern = new ForStatement { + Initializers = { }, + Condition = new BinaryOperatorExpression( + new NamedNode("indexVariable", new IdentifierExpression(Pattern.AnyString)), + BinaryOperatorType.LessThanOrEqual, + new NamedNode("upperBoundVariable", new IdentifierExpression(Pattern.AnyString)) + ), + Iterators = { + new ExpressionStatement( + new AssignmentExpression( + new IdentifierExpressionBackreference("indexVariable"), + new BinaryOperatorExpression(new IdentifierExpressionBackreference("indexVariable"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + )) + }, + EmbeddedStatement = new BlockStatement { Statements = { new AnyNode("lowerBoundAssign"), new Repeat(new AnyNode("statements")) } } + }; + + /// + /// $variable = $collection.GetUpperBound($index); + /// + static readonly AstNode variableAssignUpperBoundPattern = new ExpressionStatement( + new AssignmentExpression( + new NamedNode("variable", new IdentifierExpression(Pattern.AnyString)), + new InvocationExpression( + new MemberReferenceExpression( + new NamedNode("collection", new IdentifierExpression(Pattern.AnyString)), + "GetUpperBound" + ), + new NamedNode("index", new PrimitiveExpression(PrimitiveExpression.AnyValue)) + ))); + + /// + /// $variable = $collection.GetLowerBound($index); + /// + static readonly ExpressionStatement variableAssignLowerBoundPattern = new ExpressionStatement( + new AssignmentExpression( + new NamedNode("variable", new IdentifierExpression(Pattern.AnyString)), + new InvocationExpression( + new MemberReferenceExpression( + new NamedNode("collection", new IdentifierExpression(Pattern.AnyString)), + "GetLowerBound" + ), + new NamedNode("index", new PrimitiveExpression(PrimitiveExpression.AnyValue)) + ))); + + /// + /// $variable = $collection[$index1, $index2, ...]; + /// + static readonly ExpressionStatement foreachVariableOnMultArrayAssignPattern = new ExpressionStatement( + new AssignmentExpression( + new NamedNode("variable", new IdentifierExpression(Pattern.AnyString)), + new IndexerExpression( + new NamedNode("collection", new IdentifierExpression(Pattern.AnyString)), + new Repeat(new NamedNode("index", new IdentifierExpression(Pattern.AnyString)) + ) + ))); + + bool MatchLowerBound(int indexNum, out IL.ILVariable index, IL.ILVariable collection, Statement statement) + { + index = null; + var m = variableAssignLowerBoundPattern.Match(statement); + if (!m.Success) return false; + if (!int.TryParse(m.Get("index").Single().Value.ToString(), out int i) || indexNum != i) + return false; + index = m.Get("variable").Single().GetILVariable(); + return m.Get("collection").Single().GetILVariable() == collection; + } + + bool MatchForeachOnMultiDimArray(IL.ILVariable[] upperBounds, IL.ILVariable collection, Statement firstInitializerStatement, out IdentifierExpression foreachVariable, out IList statements, out IL.ILVariable[] lowerBounds) + { + int i = 0; + foreachVariable = null; + statements = null; + lowerBounds = new IL.ILVariable[upperBounds.Length]; + Statement stmt = firstInitializerStatement; + Match m = default(Match); + while (i < upperBounds.Length && MatchLowerBound(i, out IL.ILVariable indexVariable, collection, stmt)) { + m = forOnArrayMultiDimPattern.Match(stmt.GetNextStatement()); + if (!m.Success) return false; + var upperBound = m.Get("upperBoundVariable").Single().GetILVariable(); + if (upperBounds[i] != upperBound) + return false; + stmt = m.Get("lowerBoundAssign").Single(); + lowerBounds[i] = indexVariable; + i++; + } + var m2 = foreachVariableOnMultArrayAssignPattern.Match(stmt); + if (!m2.Success) + return false; + var collection2 = m2.Get("collection").Single().GetILVariable(); + if (collection2 != collection) + return false; + foreachVariable = m2.Get("variable").Single(); + statements = m.Get("statements").ToList(); + return true; + } + + Statement TransformForeachOnMultiDimArray(ExpressionStatement expressionStatement) + { + Match m; + Statement stmt = expressionStatement; + IL.ILVariable collection = null; + IL.ILVariable[] upperBounds = null; + List statementsToDelete = new List(); + int i = 0; + // first we look for all the upper bound initializations + do { + m = variableAssignUpperBoundPattern.Match(stmt); + if (!m.Success) break; + if (upperBounds == null) { + collection = m.Get("collection").Single().GetILVariable(); + if (!(collection.Type is Decompiler.TypeSystem.ArrayType arrayType)) + break; + upperBounds = new IL.ILVariable[arrayType.Dimensions]; + } else { + statementsToDelete.Add(stmt); + } + var nextCollection = m.Get("collection").Single().GetILVariable(); + if (nextCollection != collection) + break; + if (!int.TryParse(m.Get("index").Single().Value?.ToString() ?? "", out int index) || index != i) + break; + upperBounds[i] = m.Get("variable").Single().GetILVariable(); + stmt = stmt.GetNextStatement(); + i++; + } while (stmt != null && i < upperBounds.Length); + + if (upperBounds?.LastOrDefault() == null || collection == null) + return null; + if (!MatchForeachOnMultiDimArray(upperBounds, collection, stmt, out var foreachVariable, out var statements, out var lowerBounds)) + return null; + statementsToDelete.Add(stmt); + statementsToDelete.Add(stmt.GetNextStatement()); + var itemVariable = foreachVariable.GetILVariable(); + if (!itemVariable.IsSingleDefinition + || !upperBounds.All(ub => ub.IsSingleDefinition && ub.LoadCount == 1) + || !lowerBounds.All(lb => lb.StoreCount == 2 && lb.LoadCount == 3 && lb.AddressCount == 0)) + return null; + var body = new BlockStatement(); + foreach (var statement in statements) + body.Statements.Add(statement.Detach()); + var foreachStmt = new ForeachStatement { + VariableType = context.Settings.AnonymousTypes && itemVariable.Type.ContainsAnonymousType() ? new SimpleType("var") : context.TypeSystemAstBuilder.ConvertType(itemVariable.Type), + VariableName = itemVariable.Name, + InExpression = m.Get("collection").Single().Detach(), + EmbeddedStatement = body + }; + foreach (var statement in statementsToDelete) + statement.Detach(); + //foreachStmt.CopyAnnotationsFrom(forStatement); + itemVariable.Kind = IL.VariableKind.ForeachLocal; + // Add the variable annotation for highlighting (TokenTextWriter expects it directly on the ForeachStatement). + foreachStmt.AddAnnotation(new ILVariableResolveResult(itemVariable, itemVariable.Type)); + // TODO : add ForeachAnnotation + expressionStatement.ReplaceWith(foreachStmt); + return foreachStmt; + } + #endregion #region Automatic Properties