Browse Source

Fix invalid variable inlining in foreach (fixes #889)

pull/976/head
Siegfried Pammer 8 years ago
parent
commit
d424d93dce
  1. 45
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  2. 345
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  3. 172
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il
  4. 178
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il
  5. 341
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  6. 68
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

45
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -252,6 +252,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
public struct DataItem
{
public int Property {
get;
set;
}
public void TestCall()
{
}
}
private IEnumerable<string> alternatives; private IEnumerable<string> alternatives;
private static void Operation(ref int item) private static void Operation(ref int item)
@ -390,7 +402,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
foreach (int item in items) { foreach (int item in items) {
#if ROSLYN && OPT #if ROSLYN && OPT
// The variable names differs based on whether roslyn optimizes out the 'item' variable // The variable name differs based on whether roslyn optimizes out the 'item' variable
int current = item; int current = item;
Loops.Operation(ref current); Loops.Operation(ref current);
#else #else
@ -441,6 +453,37 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
} }
} }
} }
public void ForEachOverListOfStruct(List<DataItem> items, int value)
{
foreach (DataItem item in items) {
DataItem dataItem = item;
dataItem.Property = value;
}
}
public void ForEachOverListOfStruct2(List<DataItem> items, int value)
{
foreach (DataItem item in items) {
#if ROSLYN && OPT
// The variable name differs based on whether roslyn optimizes out the 'item' variable
DataItem current = item;
current.TestCall();
current.Property = value;
#else
DataItem dataItem = item;
dataItem.TestCall();
dataItem.Property = value;
#endif
}
}
public void ForEachOverListOfStruct3(List<DataItem> items, int value)
{
foreach (DataItem item in items) {
item.TestCall();
}
}
#endregion #endregion
public void ForOverArray(string[] array) public void ForOverArray(string[] array)

345
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.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 n3qdq2uj .assembly dky1g03y
{ {
.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 n3qdq2uj.dll .module dky1g03y.dll
// MVID: {98B4F05B-5E30-48EB-AAF5-A90EA42A94A2} // MVID: {4ADF70C5-8EC0-41AF-A9B1-6DF95B943C1A}
.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: 0x02AD0000 // Image base: 0x03580000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -584,6 +584,55 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current } // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // end of class CustomStructEnumeratorWithIDisposable`1 } // end of class CustomStructEnumeratorWithIDisposable`1
.class sequential ansi sealed nested public beforefieldinit DataItem
extends [mscorlib]System.ValueType
{
.field private int32 '<Property>k__BackingField'
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.method public hidebysig specialname
instance int32 get_Property() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 11 (0xb)
.maxstack 1
.locals init (int32 V_0)
IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
} // end of method DataItem::get_Property
.method public hidebysig specialname
instance void set_Property(int32 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0007: ret
} // end of method DataItem::set_Property
.method public hidebysig instance void
TestCall() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method DataItem::TestCall
.property instance int32 Property()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::get_Property()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
} // end of property DataItem::Property
} // end of class DataItem
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass1' .class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass1'
extends [mscorlib]System.Object extends [mscorlib]System.Object
{ {
@ -1269,7 +1318,7 @@
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed .method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{ {
// Code size 111 (0x6f) // Code size 113 (0x71)
.maxstack 2 .maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0, .locals init (class [mscorlib]System.Collections.IEnumerator V_0,
object V_1, object V_1,
@ -1308,7 +1357,7 @@
IL_0044: nop IL_0044: nop
IL_0045: nop IL_0045: nop
IL_0046: nop IL_0046: nop
IL_0047: leave.s IL_0062 IL_0047: leave.s IL_0064
} // end .try } // end .try
finally finally
@ -1322,19 +1371,21 @@
IL_0053: ceq IL_0053: ceq
IL_0055: stloc.3 IL_0055: stloc.3
IL_0056: ldloc.3 IL_0056: ldloc.3
IL_0057: brtrue.s IL_0060 IL_0057: brtrue.s IL_0062
IL_0059: ldloc.2 IL_0059: nop
IL_005a: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_005a: ldloc.2
IL_005f: nop IL_005b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0060: nop IL_0060: nop
IL_0061: endfinally IL_0061: nop
IL_0062: nop
IL_0063: endfinally
} // end handler } // end handler
IL_0062: nop IL_0064: nop
IL_0063: ldstr "After finally!" IL_0065: ldstr "After finally!"
IL_0068: call void [mscorlib]System.Console::WriteLine(string) IL_006a: call void [mscorlib]System.Console::WriteLine(string)
IL_006d: nop IL_006f: nop
IL_006e: ret IL_0070: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest } // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig static void ForeachWithRefUsage(class [mscorlib]System.Collections.Generic.List`1<int32> items) cil managed .method public hidebysig static void ForeachWithRefUsage(class [mscorlib]System.Collections.Generic.List`1<int32> items) cil managed
@ -1669,6 +1720,158 @@
IL_0069: ret IL_0069: ret
} // end of method Loops::ForEachBreakWhenFound } // end of method Loops::ForEachBreakWhenFound
.method public hidebysig instance void
ForEachOverListOfStruct(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 62 (0x3e)
.maxstack 2
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_2,
bool V_3)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.1
IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0008: stloc.2
.try
{
IL_0009: br.s IL_0020
IL_000b: ldloca.s V_2
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0012: stloc.0
IL_0013: nop
IL_0014: ldloc.0
IL_0015: stloc.1
IL_0016: ldloca.s V_1
IL_0018: ldarg.2
IL_0019: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_001e: nop
IL_001f: nop
IL_0020: ldloca.s V_2
IL_0022: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0027: stloc.3
IL_0028: ldloc.3
IL_0029: brtrue.s IL_000b
IL_002b: leave.s IL_003c
} // end .try
finally
{
IL_002d: ldloca.s V_2
IL_002f: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_0035: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003a: nop
IL_003b: endfinally
} // end handler
IL_003c: nop
IL_003d: ret
} // end of method Loops::ForEachOverListOfStruct
.method public hidebysig instance void
ForEachOverListOfStruct2(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 70 (0x46)
.maxstack 2
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_2,
bool V_3)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.1
IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0008: stloc.2
.try
{
IL_0009: br.s IL_0028
IL_000b: ldloca.s V_2
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0012: stloc.0
IL_0013: nop
IL_0014: ldloc.0
IL_0015: stloc.1
IL_0016: ldloca.s V_1
IL_0018: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_001d: nop
IL_001e: ldloca.s V_1
IL_0020: ldarg.2
IL_0021: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_0026: nop
IL_0027: nop
IL_0028: ldloca.s V_2
IL_002a: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_002f: stloc.3
IL_0030: ldloc.3
IL_0031: brtrue.s IL_000b
IL_0033: leave.s IL_0044
} // end .try
finally
{
IL_0035: ldloca.s V_2
IL_0037: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_003d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0042: nop
IL_0043: endfinally
} // end handler
IL_0044: nop
IL_0045: ret
} // end of method Loops::ForEachOverListOfStruct2
.method public hidebysig instance void
ForEachOverListOfStruct3(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 59 (0x3b)
.maxstack 1
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_0,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_1,
bool V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.1
IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0008: stloc.1
.try
{
IL_0009: br.s IL_001d
IL_000b: ldloca.s V_1
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0012: stloc.0
IL_0013: nop
IL_0014: ldloca.s V_0
IL_0016: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_001b: nop
IL_001c: nop
IL_001d: ldloca.s V_1
IL_001f: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0024: stloc.2
IL_0025: ldloc.2
IL_0026: brtrue.s IL_000b
IL_0028: leave.s IL_0039
} // end .try
finally
{
IL_002a: ldloca.s V_1
IL_002c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_0032: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0037: nop
IL_0038: endfinally
} // end handler
IL_0039: nop
IL_003a: ret
} // end of method Loops::ForEachOverListOfStruct3
.method public hidebysig instance void .method public hidebysig instance void
ForOverArray(string[] 'array') cil managed ForOverArray(string[] 'array') cil managed
{ {
@ -1848,7 +2051,7 @@
.method public hidebysig instance void .method public hidebysig instance void
WhileLoop() cil managed WhileLoop() cil managed
{ {
// Code size 154 (0x9a) // Code size 155 (0x9b)
.maxstack 2 .maxstack 2
.locals init (bool V_0) .locals init (bool V_0)
IL_0000: nop IL_0000: nop
@ -1862,10 +2065,10 @@
IL_0018: ceq IL_0018: ceq
IL_001a: stloc.0 IL_001a: stloc.0
IL_001b: ldloc.0 IL_001b: ldloc.0
IL_001c: brtrue.s IL_008e IL_001c: brtrue.s IL_008f
IL_001e: nop IL_001e: nop
IL_001f: br.s IL_0073 IL_001f: br.s IL_0074
IL_0021: nop IL_0021: nop
IL_0022: ldstr "Loop Body" IL_0022: ldstr "Loop Body"
@ -1878,7 +2081,7 @@
IL_0039: ceq IL_0039: ceq
IL_003b: stloc.0 IL_003b: stloc.0
IL_003c: ldloc.0 IL_003c: ldloc.0
IL_003d: brtrue.s IL_0067 IL_003d: brtrue.s IL_0068
IL_003f: nop IL_003f: nop
IL_0040: ldarg.0 IL_0040: ldarg.0
@ -1891,43 +2094,44 @@
IL_0050: brtrue.s IL_0055 IL_0050: brtrue.s IL_0055
IL_0052: nop IL_0052: nop
IL_0053: br.s IL_0073 IL_0053: br.s IL_0074
IL_0055: ldarg.0 IL_0055: ldarg.0
IL_0056: ldstr "break" IL_0056: ldstr "break"
IL_005b: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_005b: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0060: stloc.0 IL_0060: stloc.0
IL_0061: ldloc.0 IL_0061: ldloc.0
IL_0062: brtrue.s IL_0066 IL_0062: brtrue.s IL_0067
IL_0064: br.s IL_0082 IL_0064: nop
IL_0065: br.s IL_0083
IL_0066: nop IL_0067: nop
IL_0067: ldstr "End of loop body" IL_0068: ldstr "End of loop body"
IL_006c: call void [mscorlib]System.Console::WriteLine(string) IL_006d: call void [mscorlib]System.Console::WriteLine(string)
IL_0071: nop
IL_0072: nop IL_0072: nop
IL_0073: ldarg.0 IL_0073: nop
IL_0074: ldstr "while" IL_0074: ldarg.0
IL_0079: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_0075: ldstr "while"
IL_007e: stloc.0 IL_007a: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_007f: ldloc.0 IL_007f: stloc.0
IL_0080: brtrue.s IL_0021 IL_0080: ldloc.0
IL_0081: brtrue.s IL_0021
IL_0082: ldstr "After loop"
IL_0087: call void [mscorlib]System.Console::WriteLine(string) IL_0083: ldstr "After loop"
IL_008c: nop IL_0088: call void [mscorlib]System.Console::WriteLine(string)
IL_008d: nop IL_008d: nop
IL_008e: ldstr "End of method" IL_008e: nop
IL_0093: call void [mscorlib]System.Console::WriteLine(string) IL_008f: ldstr "End of method"
IL_0098: nop IL_0094: call void [mscorlib]System.Console::WriteLine(string)
IL_0099: ret IL_0099: nop
IL_009a: ret
} // end of method Loops::WhileLoop } // end of method Loops::WhileLoop
.method public hidebysig instance void .method public hidebysig instance void
ForLoop() cil managed ForLoop() cil managed
{ {
// Code size 160 (0xa0) // Code size 161 (0xa1)
.maxstack 2 .maxstack 2
.locals init (int32 V_0, .locals init (int32 V_0,
bool V_1) bool V_1)
@ -1942,12 +2146,12 @@
IL_0018: ceq IL_0018: ceq
IL_001a: stloc.1 IL_001a: stloc.1
IL_001b: ldloc.1 IL_001b: ldloc.1
IL_001c: brtrue.s IL_0094 IL_001c: brtrue.s IL_0095
IL_001e: nop IL_001e: nop
IL_001f: ldc.i4.0 IL_001f: ldc.i4.0
IL_0020: stloc.0 IL_0020: stloc.0
IL_0021: br.s IL_0079 IL_0021: br.s IL_007a
IL_0023: nop IL_0023: nop
IL_0024: ldstr "Loop Body" IL_0024: ldstr "Loop Body"
@ -1960,7 +2164,7 @@
IL_003b: ceq IL_003b: ceq
IL_003d: stloc.1 IL_003d: stloc.1
IL_003e: ldloc.1 IL_003e: ldloc.1
IL_003f: brtrue.s IL_0069 IL_003f: brtrue.s IL_006a
IL_0041: nop IL_0041: nop
IL_0042: ldarg.0 IL_0042: ldarg.0
@ -1973,41 +2177,42 @@
IL_0052: brtrue.s IL_0057 IL_0052: brtrue.s IL_0057
IL_0054: nop IL_0054: nop
IL_0055: br.s IL_0075 IL_0055: br.s IL_0076
IL_0057: ldarg.0 IL_0057: ldarg.0
IL_0058: ldstr "not-break" IL_0058: ldstr "not-break"
IL_005d: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_005d: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0062: stloc.1 IL_0062: stloc.1
IL_0063: ldloc.1 IL_0063: ldloc.1
IL_0064: brtrue.s IL_0068 IL_0064: brtrue.s IL_0069
IL_0066: br.s IL_0088 IL_0066: nop
IL_0067: br.s IL_0089
IL_0068: nop IL_0069: nop
IL_0069: ldstr "End of loop body" IL_006a: ldstr "End of loop body"
IL_006e: call void [mscorlib]System.Console::WriteLine(string) IL_006f: call void [mscorlib]System.Console::WriteLine(string)
IL_0073: nop
IL_0074: nop IL_0074: nop
IL_0075: ldloc.0 IL_0075: nop
IL_0076: ldc.i4.1 IL_0076: ldloc.0
IL_0077: add IL_0077: ldc.i4.1
IL_0078: stloc.0 IL_0078: add
IL_0079: ldarg.0 IL_0079: stloc.0
IL_007a: ldstr "for" IL_007a: ldarg.0
IL_007f: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_007b: ldstr "for"
IL_0084: stloc.1 IL_0080: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0085: ldloc.1 IL_0085: stloc.1
IL_0086: brtrue.s IL_0023 IL_0086: ldloc.1
IL_0087: brtrue.s IL_0023
IL_0088: ldstr "After loop"
IL_008d: call void [mscorlib]System.Console::WriteLine(string) IL_0089: ldstr "After loop"
IL_0092: nop IL_008e: call void [mscorlib]System.Console::WriteLine(string)
IL_0093: nop IL_0093: nop
IL_0094: ldstr "End of method" IL_0094: nop
IL_0099: call void [mscorlib]System.Console::WriteLine(string) IL_0095: ldstr "End of method"
IL_009e: nop IL_009a: call void [mscorlib]System.Console::WriteLine(string)
IL_009f: ret IL_009f: nop
IL_00a0: ret
} // end of method Loops::ForLoop } // end of method Loops::ForLoop
.method public hidebysig specialname rtspecialname .method public hidebysig specialname rtspecialname

172
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.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 spdzj2hg .assembly trg3dx5v
{ {
.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 spdzj2hg.dll .module trg3dx5v.dll
// MVID: {D8CD3A33-FD06-4791-A4E6-AC836DA34D06} // MVID: {39502A20-4431-466D-88D2-F47B21FB8C58}
.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: 0x00B30000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -506,6 +506,49 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current } // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // end of class CustomStructEnumeratorWithIDisposable`1 } // end of class CustomStructEnumeratorWithIDisposable`1
.class sequential ansi sealed nested public beforefieldinit DataItem
extends [mscorlib]System.ValueType
{
.field private int32 '<Property>k__BackingField'
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.method public hidebysig specialname
instance int32 get_Property() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0006: ret
} // end of method DataItem::get_Property
.method public hidebysig specialname
instance void set_Property(int32 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0007: ret
} // end of method DataItem::set_Property
.method public hidebysig instance void
TestCall() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method DataItem::TestCall
.property instance int32 Property()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::get_Property()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
} // end of property DataItem::Property
} // end of class DataItem
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass1' .class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass1'
extends [mscorlib]System.Object extends [mscorlib]System.Object
{ {
@ -1336,6 +1379,127 @@
IL_0056: ret IL_0056: ret
} // end of method Loops::ForEachBreakWhenFound } // end of method Loops::ForEachBreakWhenFound
.method public hidebysig instance void
ForEachOverListOfStruct(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 53 (0x35)
.maxstack 2
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_2)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0006: stloc.2
.try
{
IL_0007: br.s IL_001b
IL_0009: ldloca.s V_2
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: stloc.1
IL_0013: ldloca.s V_1
IL_0015: ldarg.2
IL_0016: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_001b: ldloca.s V_2
IL_001d: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0022: brtrue.s IL_0009
IL_0024: leave.s IL_0034
} // end .try
finally
{
IL_0026: ldloca.s V_2
IL_0028: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_002e: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0033: endfinally
} // end handler
IL_0034: ret
} // end of method Loops::ForEachOverListOfStruct
.method public hidebysig instance void
ForEachOverListOfStruct2(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 60 (0x3c)
.maxstack 2
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_2)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0006: stloc.2
.try
{
IL_0007: br.s IL_0022
IL_0009: ldloca.s V_2
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: stloc.1
IL_0013: ldloca.s V_1
IL_0015: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_001a: ldloca.s V_1
IL_001c: ldarg.2
IL_001d: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_0022: ldloca.s V_2
IL_0024: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0029: brtrue.s IL_0009
IL_002b: leave.s IL_003b
} // end .try
finally
{
IL_002d: ldloca.s V_2
IL_002f: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_0035: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003a: endfinally
} // end handler
IL_003b: ret
} // end of method Loops::ForEachOverListOfStruct2
.method public hidebysig instance void
ForEachOverListOfStruct3(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 50 (0x32)
.maxstack 1
.locals init (valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_0,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_1)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0006: stloc.1
.try
{
IL_0007: br.s IL_0018
IL_0009: ldloca.s V_1
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0010: stloc.0
IL_0011: ldloca.s V_0
IL_0013: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_0018: ldloca.s V_1
IL_001a: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_001f: brtrue.s IL_0009
IL_0021: leave.s IL_0031
} // end .try
finally
{
IL_0023: ldloca.s V_1
IL_0025: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_002b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0030: endfinally
} // end handler
IL_0031: ret
} // end of method Loops::ForEachOverListOfStruct3
.method public hidebysig instance void .method public hidebysig instance void
ForOverArray(string[] 'array') cil managed ForOverArray(string[] 'array') cil managed
{ {

178
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il

@ -25,14 +25,14 @@
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module Loops.dll .module Loops.dll
// MVID: {B3F85A6A-79B4-41C0-9146-2088985BFC34} // MVID: {F193AB7E-127F-4EFE-9BF9-ADF41756C267}
.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: 0x02550000 // Image base: 0x03460000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -510,7 +510,50 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current } // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // end of class CustomStructEnumeratorWithIDisposable`1 } // end of class CustomStructEnumeratorWithIDisposable`1
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass25_0' .class sequential ansi sealed nested public beforefieldinit DataItem
extends [mscorlib]System.ValueType
{
.field private int32 '<Property>k__BackingField'
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.method public hidebysig specialname
instance int32 get_Property() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0006: ret
} // end of method DataItem::get_Property
.method public hidebysig specialname
instance void set_Property(int32 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0007: ret
} // end of method DataItem::set_Property
.method public hidebysig instance void
TestCall() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method DataItem::TestCall
.property instance int32 Property()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::get_Property()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
} // end of property DataItem::Property
} // end of class DataItem
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass26_0'
extends [mscorlib]System.Object extends [mscorlib]System.Object
{ {
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
@ -523,7 +566,7 @@
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret IL_0006: ret
} // end of method '<>c__DisplayClass25_0'::.ctor } // end of method '<>c__DisplayClass26_0'::.ctor
.method assembly hidebysig instance bool .method assembly hidebysig instance bool
'<ForeachWithCapturedVariable>b__0'() cil managed '<ForeachWithCapturedVariable>b__0'() cil managed
@ -531,13 +574,13 @@
// Code size 10 (0xa) // Code size 10 (0xa)
.maxstack 8 .maxstack 8
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::c
IL_0006: ldc.i4.5 IL_0006: ldc.i4.5
IL_0007: ceq IL_0007: ceq
IL_0009: ret IL_0009: ret
} // end of method '<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0' } // end of method '<>c__DisplayClass26_0'::'<ForeachWithCapturedVariable>b__0'
} // end of class '<>c__DisplayClass25_0' } // end of class '<>c__DisplayClass26_0'
.field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives .field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives
.method private hidebysig static void Operation(int32& item) cil managed .method private hidebysig static void Operation(int32& item) cil managed
@ -1101,11 +1144,11 @@
IL_0009: ldloca.s V_0 IL_0009: ldloca.s V_0
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current() IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0010: stloc.1 IL_0010: stloc.1
IL_0011: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::.ctor() IL_0011: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::.ctor()
IL_0016: dup IL_0016: dup
IL_0017: ldloc.1 IL_0017: ldloc.1
IL_0018: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c IL_0018: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::c
IL_001d: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0'() IL_001d: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::'<ForeachWithCapturedVariable>b__0'()
IL_0023: newobj instance void class [mscorlib]System.Func`1<bool>::.ctor(object, IL_0023: newobj instance void class [mscorlib]System.Func`1<bool>::.ctor(object,
native int) native int)
IL_0028: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>) IL_0028: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>)
@ -1295,6 +1338,121 @@
IL_0058: ret IL_0058: ret
} // end of method Loops::ForEachBreakWhenFound } // end of method Loops::ForEachBreakWhenFound
.method public hidebysig instance void
ForEachOverListOfStruct(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 51 (0x33)
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0006: stloc.0
.try
{
IL_0007: br.s IL_0019
IL_0009: ldloca.s V_0
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0010: stloc.1
IL_0011: ldloca.s V_1
IL_0013: ldarg.2
IL_0014: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_0019: ldloca.s V_0
IL_001b: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0020: brtrue.s IL_0009
IL_0022: leave.s IL_0032
} // end .try
finally
{
IL_0024: ldloca.s V_0
IL_0026: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_002c: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0031: endfinally
} // end handler
IL_0032: ret
} // end of method Loops::ForEachOverListOfStruct
.method public hidebysig instance void
ForEachOverListOfStruct2(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 58 (0x3a)
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0006: stloc.0
.try
{
IL_0007: br.s IL_0020
IL_0009: ldloca.s V_0
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0010: stloc.1
IL_0011: ldloca.s V_1
IL_0013: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_0018: ldloca.s V_1
IL_001a: ldarg.2
IL_001b: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_0020: ldloca.s V_0
IL_0022: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0027: brtrue.s IL_0009
IL_0029: leave.s IL_0039
} // end .try
finally
{
IL_002b: ldloca.s V_0
IL_002d: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_0033: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0038: endfinally
} // end handler
IL_0039: ret
} // end of method Loops::ForEachOverListOfStruct2
.method public hidebysig instance void
ForEachOverListOfStruct3(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 50 (0x32)
.maxstack 1
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1)
IL_0000: ldarg.1
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0006: stloc.0
.try
{
IL_0007: br.s IL_0018
IL_0009: ldloca.s V_0
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0010: stloc.1
IL_0011: ldloca.s V_1
IL_0013: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_0018: ldloca.s V_0
IL_001a: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_001f: brtrue.s IL_0009
IL_0021: leave.s IL_0031
} // end .try
finally
{
IL_0023: ldloca.s V_0
IL_0025: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_002b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0030: endfinally
} // end handler
IL_0031: ret
} // end of method Loops::ForEachOverListOfStruct3
.method public hidebysig instance void .method public hidebysig instance void
ForOverArray(string[] 'array') cil managed ForOverArray(string[] 'array') cil managed
{ {

341
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il

@ -25,14 +25,14 @@
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module Loops.dll .module Loops.dll
// MVID: {8261F08F-23F6-43C1-9650-C5B6A10A0F30} // MVID: {8F6E41CD-7AE5-437C-BACB-4A672A0014D0}
.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: 0x00720000 // Image base: 0x00C80000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -592,7 +592,52 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current } // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // end of class CustomStructEnumeratorWithIDisposable`1 } // end of class CustomStructEnumeratorWithIDisposable`1
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass25_0' .class sequential ansi sealed nested public beforefieldinit DataItem
extends [mscorlib]System.ValueType
{
.field private int32 '<Property>k__BackingField'
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 )
.method public hidebysig specialname
instance int32 get_Property() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0006: ret
} // end of method DataItem::get_Property
.method public hidebysig specialname
instance void set_Property(int32 'value') cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::'<Property>k__BackingField'
IL_0007: ret
} // end of method DataItem::set_Property
.method public hidebysig instance void
TestCall() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method DataItem::TestCall
.property instance int32 Property()
{
.get instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::get_Property()
.set instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
} // end of property DataItem::Property
} // end of class DataItem
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass26_0'
extends [mscorlib]System.Object extends [mscorlib]System.Object
{ {
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
@ -606,7 +651,7 @@
IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop IL_0006: nop
IL_0007: ret IL_0007: ret
} // end of method '<>c__DisplayClass25_0'::.ctor } // end of method '<>c__DisplayClass26_0'::.ctor
.method assembly hidebysig instance bool .method assembly hidebysig instance bool
'<ForeachWithCapturedVariable>b__0'() cil managed '<ForeachWithCapturedVariable>b__0'() cil managed
@ -614,13 +659,13 @@
// Code size 10 (0xa) // Code size 10 (0xa)
.maxstack 8 .maxstack 8
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c IL_0001: ldfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::c
IL_0006: ldc.i4.5 IL_0006: ldc.i4.5
IL_0007: ceq IL_0007: ceq
IL_0009: ret IL_0009: ret
} // end of method '<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0' } // end of method '<>c__DisplayClass26_0'::'<ForeachWithCapturedVariable>b__0'
} // end of class '<>c__DisplayClass25_0' } // end of class '<>c__DisplayClass26_0'
.field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives .field private class [mscorlib]System.Collections.Generic.IEnumerable`1<string> alternatives
.method private hidebysig static void Operation(int32& item) cil managed .method private hidebysig static void Operation(int32& item) cil managed
@ -1189,7 +1234,7 @@
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed .method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{ {
// Code size 109 (0x6d) // Code size 111 (0x6f)
.maxstack 2 .maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0, .locals init (class [mscorlib]System.Collections.IEnumerator V_0,
bool V_1, bool V_1,
@ -1227,7 +1272,7 @@
IL_0041: nop IL_0041: nop
IL_0042: nop IL_0042: nop
IL_0043: nop IL_0043: nop
IL_0044: leave.s IL_0061 IL_0044: leave.s IL_0063
} // end .try } // end .try
finally finally
@ -1241,18 +1286,20 @@
IL_0050: cgt.un IL_0050: cgt.un
IL_0052: stloc.s V_4 IL_0052: stloc.s V_4
IL_0054: ldloc.s V_4 IL_0054: ldloc.s V_4
IL_0056: brfalse.s IL_005f IL_0056: brfalse.s IL_0061
IL_0058: ldloc.3 IL_0058: nop
IL_0059: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_0059: ldloc.3
IL_005e: nop IL_005a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_005f: nop IL_005f: nop
IL_0060: endfinally IL_0060: nop
IL_0061: nop
IL_0062: endfinally
} // end handler } // end handler
IL_0061: ldstr "After finally!" IL_0063: ldstr "After finally!"
IL_0066: call void [mscorlib]System.Console::WriteLine(string) IL_0068: call void [mscorlib]System.Console::WriteLine(string)
IL_006b: nop IL_006d: nop
IL_006c: ret IL_006e: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest } // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig static void ForeachWithRefUsage(class [mscorlib]System.Collections.Generic.List`1<int32> items) cil managed .method public hidebysig static void ForeachWithRefUsage(class [mscorlib]System.Collections.Generic.List`1<int32> items) cil managed
@ -1305,7 +1352,7 @@
.maxstack 2 .maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> V_0, .locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> V_0,
int32 V_1, int32 V_1,
class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0' V_2) class ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0' V_2)
IL_0000: nop IL_0000: nop
IL_0001: nop IL_0001: nop
IL_0002: ldarg.0 IL_0002: ldarg.0
@ -1318,14 +1365,14 @@
IL_000b: ldloca.s V_0 IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current() IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0012: stloc.1 IL_0012: stloc.1
IL_0013: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::.ctor() IL_0013: newobj instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::.ctor()
IL_0018: stloc.2 IL_0018: stloc.2
IL_0019: nop IL_0019: nop
IL_001a: ldloc.2 IL_001a: ldloc.2
IL_001b: ldloc.1 IL_001b: ldloc.1
IL_001c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c IL_001c: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::c
IL_0021: ldloc.2 IL_0021: ldloc.2
IL_0022: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0'() IL_0022: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass26_0'::'<ForeachWithCapturedVariable>b__0'()
IL_0028: newobj instance void class [mscorlib]System.Func`1<bool>::.ctor(object, IL_0028: newobj instance void class [mscorlib]System.Func`1<bool>::.ctor(object,
native int) native int)
IL_002d: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>) IL_002d: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>)
@ -1554,6 +1601,146 @@
IL_0060: ret IL_0060: ret
} // end of method Loops::ForEachBreakWhenFound } // end of method Loops::ForEachBreakWhenFound
.method public hidebysig instance void
ForEachOverListOfStruct(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 59 (0x3b)
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.1
IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0008: stloc.0
.try
{
IL_0009: br.s IL_0020
IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0012: stloc.1
IL_0013: nop
IL_0014: ldloc.1
IL_0015: stloc.2
IL_0016: ldloca.s V_2
IL_0018: ldarg.2
IL_0019: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_001e: nop
IL_001f: nop
IL_0020: ldloca.s V_0
IL_0022: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0027: brtrue.s IL_000b
IL_0029: leave.s IL_003a
} // end .try
finally
{
IL_002b: ldloca.s V_0
IL_002d: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_0033: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0038: nop
IL_0039: endfinally
} // end handler
IL_003a: ret
} // end of method Loops::ForEachOverListOfStruct
.method public hidebysig instance void
ForEachOverListOfStruct2(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 67 (0x43)
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_2)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.1
IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0008: stloc.0
.try
{
IL_0009: br.s IL_0028
IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0012: stloc.1
IL_0013: nop
IL_0014: ldloc.1
IL_0015: stloc.2
IL_0016: ldloca.s V_2
IL_0018: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_001d: nop
IL_001e: ldloca.s V_2
IL_0020: ldarg.2
IL_0021: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::set_Property(int32)
IL_0026: nop
IL_0027: nop
IL_0028: ldloca.s V_0
IL_002a: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_002f: brtrue.s IL_000b
IL_0031: leave.s IL_0042
} // end .try
finally
{
IL_0033: ldloca.s V_0
IL_0035: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_003b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0040: nop
IL_0041: endfinally
} // end handler
IL_0042: ret
} // end of method Loops::ForEachOverListOfStruct2
.method public hidebysig instance void
ForEachOverListOfStruct3(class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> items,
int32 'value') cil managed
{
// Code size 56 (0x38)
.maxstack 1
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem> V_0,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem V_1)
IL_0000: nop
IL_0001: nop
IL_0002: ldarg.1
IL_0003: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::GetEnumerator()
IL_0008: stloc.0
.try
{
IL_0009: br.s IL_001d
IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::get_Current()
IL_0012: stloc.1
IL_0013: nop
IL_0014: ldloca.s V_1
IL_0016: call instance void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem::TestCall()
IL_001b: nop
IL_001c: nop
IL_001d: ldloca.s V_0
IL_001f: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>::MoveNext()
IL_0024: brtrue.s IL_000b
IL_0026: leave.s IL_0037
} // end .try
finally
{
IL_0028: ldloca.s V_0
IL_002a: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/DataItem>
IL_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0035: nop
IL_0036: endfinally
} // end handler
IL_0037: ret
} // end of method Loops::ForEachOverListOfStruct3
.method public hidebysig instance void .method public hidebysig instance void
ForOverArray(string[] 'array') cil managed ForOverArray(string[] 'array') cil managed
{ {
@ -1732,7 +1919,7 @@
.method public hidebysig instance void .method public hidebysig instance void
WhileLoop() cil managed WhileLoop() cil managed
{ {
// Code size 150 (0x96) // Code size 151 (0x97)
.maxstack 2 .maxstack 2
.locals init (bool V_0, .locals init (bool V_0,
bool V_1, bool V_1,
@ -1748,10 +1935,10 @@
IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0017: stloc.0 IL_0017: stloc.0
IL_0018: ldloc.0 IL_0018: ldloc.0
IL_0019: brfalse.s IL_008a IL_0019: brfalse.s IL_008b
IL_001b: nop IL_001b: nop
IL_001c: br.s IL_006d IL_001c: br.s IL_006e
IL_001e: nop IL_001e: nop
IL_001f: ldstr "Loop Body" IL_001f: ldstr "Loop Body"
@ -1762,7 +1949,7 @@
IL_0030: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_0030: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0035: stloc.1 IL_0035: stloc.1
IL_0036: ldloc.1 IL_0036: ldloc.1
IL_0037: brfalse.s IL_0061 IL_0037: brfalse.s IL_0062
IL_0039: nop IL_0039: nop
IL_003a: ldarg.0 IL_003a: ldarg.0
@ -1773,7 +1960,7 @@
IL_0047: brfalse.s IL_004c IL_0047: brfalse.s IL_004c
IL_0049: nop IL_0049: nop
IL_004a: br.s IL_006d IL_004a: br.s IL_006e
IL_004c: ldarg.0 IL_004c: ldarg.0
IL_004d: ldstr "break" IL_004d: ldstr "break"
@ -1782,36 +1969,37 @@
IL_0058: ceq IL_0058: ceq
IL_005a: stloc.3 IL_005a: stloc.3
IL_005b: ldloc.3 IL_005b: ldloc.3
IL_005c: brfalse.s IL_0060 IL_005c: brfalse.s IL_0061
IL_005e: br.s IL_007e IL_005e: nop
IL_005f: br.s IL_007f
IL_0060: nop IL_0061: nop
IL_0061: ldstr "End of loop body" IL_0062: ldstr "End of loop body"
IL_0066: call void [mscorlib]System.Console::WriteLine(string) IL_0067: call void [mscorlib]System.Console::WriteLine(string)
IL_006b: nop
IL_006c: nop IL_006c: nop
IL_006d: ldarg.0 IL_006d: nop
IL_006e: ldstr "while" IL_006e: ldarg.0
IL_0073: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_006f: ldstr "while"
IL_0078: stloc.s V_4 IL_0074: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_007a: ldloc.s V_4 IL_0079: stloc.s V_4
IL_007c: brtrue.s IL_001e IL_007b: ldloc.s V_4
IL_007d: brtrue.s IL_001e
IL_007e: ldstr "After loop"
IL_0083: call void [mscorlib]System.Console::WriteLine(string) IL_007f: ldstr "After loop"
IL_0088: nop IL_0084: call void [mscorlib]System.Console::WriteLine(string)
IL_0089: nop IL_0089: nop
IL_008a: ldstr "End of method" IL_008a: nop
IL_008f: call void [mscorlib]System.Console::WriteLine(string) IL_008b: ldstr "End of method"
IL_0094: nop IL_0090: call void [mscorlib]System.Console::WriteLine(string)
IL_0095: ret IL_0095: nop
IL_0096: ret
} // end of method Loops::WhileLoop } // end of method Loops::WhileLoop
.method public hidebysig instance void .method public hidebysig instance void
ForLoop() cil managed ForLoop() cil managed
{ {
// Code size 158 (0x9e) // Code size 159 (0x9f)
.maxstack 2 .maxstack 2
.locals init (bool V_0, .locals init (bool V_0,
int32 V_1, int32 V_1,
@ -1828,12 +2016,12 @@
IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0017: stloc.0 IL_0017: stloc.0
IL_0018: ldloc.0 IL_0018: ldloc.0
IL_0019: brfalse.s IL_0092 IL_0019: brfalse.s IL_0093
IL_001b: nop IL_001b: nop
IL_001c: ldc.i4.0 IL_001c: ldc.i4.0
IL_001d: stloc.1 IL_001d: stloc.1
IL_001e: br.s IL_0075 IL_001e: br.s IL_0076
IL_0020: nop IL_0020: nop
IL_0021: ldstr "Loop Body" IL_0021: ldstr "Loop Body"
@ -1844,7 +2032,7 @@
IL_0032: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_0032: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0037: stloc.2 IL_0037: stloc.2
IL_0038: ldloc.2 IL_0038: ldloc.2
IL_0039: brfalse.s IL_0065 IL_0039: brfalse.s IL_0066
IL_003b: nop IL_003b: nop
IL_003c: ldarg.0 IL_003c: ldarg.0
@ -1855,7 +2043,7 @@
IL_0049: brfalse.s IL_004e IL_0049: brfalse.s IL_004e
IL_004b: nop IL_004b: nop
IL_004c: br.s IL_0071 IL_004c: br.s IL_0072
IL_004e: ldarg.0 IL_004e: ldarg.0
IL_004f: ldstr "not-break" IL_004f: ldstr "not-break"
@ -1864,34 +2052,35 @@
IL_005a: ceq IL_005a: ceq
IL_005c: stloc.s V_4 IL_005c: stloc.s V_4
IL_005e: ldloc.s V_4 IL_005e: ldloc.s V_4
IL_0060: brfalse.s IL_0064 IL_0060: brfalse.s IL_0065
IL_0062: br.s IL_0086 IL_0062: nop
IL_0063: br.s IL_0087
IL_0064: nop IL_0065: nop
IL_0065: ldstr "End of loop body" IL_0066: ldstr "End of loop body"
IL_006a: call void [mscorlib]System.Console::WriteLine(string) IL_006b: call void [mscorlib]System.Console::WriteLine(string)
IL_006f: nop
IL_0070: nop IL_0070: nop
IL_0071: ldloc.1 IL_0071: nop
IL_0072: ldc.i4.1 IL_0072: ldloc.1
IL_0073: add IL_0073: ldc.i4.1
IL_0074: stloc.1 IL_0074: add
IL_0075: ldarg.0 IL_0075: stloc.1
IL_0076: ldstr "for" IL_0076: ldarg.0
IL_007b: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string) IL_0077: ldstr "for"
IL_0080: stloc.s V_5 IL_007c: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0082: ldloc.s V_5 IL_0081: stloc.s V_5
IL_0084: brtrue.s IL_0020 IL_0083: ldloc.s V_5
IL_0085: brtrue.s IL_0020
IL_0086: ldstr "After loop"
IL_008b: call void [mscorlib]System.Console::WriteLine(string) IL_0087: ldstr "After loop"
IL_0090: nop IL_008c: call void [mscorlib]System.Console::WriteLine(string)
IL_0091: nop IL_0091: nop
IL_0092: ldstr "End of method" IL_0092: nop
IL_0097: call void [mscorlib]System.Console::WriteLine(string) IL_0093: ldstr "End of method"
IL_009c: nop IL_0098: call void [mscorlib]System.Console::WriteLine(string)
IL_009d: ret IL_009d: nop
IL_009e: ret
} // end of method Loops::ForLoop } // end of method Loops::ForLoop
.method public hidebysig specialname rtspecialname .method public hidebysig specialname rtspecialname

68
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -471,6 +471,19 @@ namespace ICSharpCode.Decompiler.CSharp
instToReplace.ReplaceWith(new LdLoc(foreachVariable)); instToReplace.ReplaceWith(new LdLoc(foreachVariable));
body.Instructions.Insert(0, new StLoc(foreachVariable, instToReplace)); body.Instructions.Insert(0, new StLoc(foreachVariable, instToReplace));
break; break;
case RequiredGetCurrentTransformation.IntroduceNewVariableAndLocalCopy:
foreachVariable = currentFunction.RegisterVariable(
VariableKind.ForeachLocal, type,
AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>())
);
var localCopyVariable = currentFunction.RegisterVariable(
VariableKind.Local, type,
AssignVariableNames.GenerateVariableName(currentFunction, type)
);
instToReplace.Parent.ReplaceWith(new LdLoca(localCopyVariable));
body.Instructions.Insert(0, new StLoc(localCopyVariable, new LdLoc(foreachVariable)));
body.Instructions.Insert(0, new StLoc(foreachVariable, instToReplace));
break;
} }
// Convert the modified body to C# AST: // Convert the modified body to C# AST:
var whileLoop = (WhileStatement)ConvertAsBlock(container).First(); var whileLoop = (WhileStatement)ConvertAsBlock(container).First();
@ -563,7 +576,20 @@ namespace ICSharpCode.Decompiler.CSharp
/// ... (ldloc foreachVar) ... /// ... (ldloc foreachVar) ...
/// </code> /// </code>
/// </summary> /// </summary>
IntroduceNewVariable IntroduceNewVariable,
/// <summary>
/// No store was found, thus create a new variable and use it as foreach variable.
/// Additionally it is necessary to copy the value of the foreach variable to another local
/// to allow safe modification of its value.
/// <code>
/// ... addressof(call get_Current()) ...
/// =>
/// stloc foreachVar(call get_Current())
/// stloc copy(ldloc foreachVar)
/// ... (ldloca copy) ...
/// </code>
/// </summary>
IntroduceNewVariableAndLocalCopy
} }
/// <summary> /// <summary>
@ -603,6 +629,11 @@ namespace ICSharpCode.Decompiler.CSharp
return RequiredGetCurrentTransformation.UseExistingVariable; return RequiredGetCurrentTransformation.UseExistingVariable;
} }
} }
// In optimized Roslyn code it can happen that the foreach variable is referenced via addressof
// We only do this unwrapping if where dealing with a custom struct type.
if (CurrentIsStructSetterTarget(inst, singleGetter)) {
return RequiredGetCurrentTransformation.IntroduceNewVariableAndLocalCopy;
}
// No suitable variable was found: we need a new one. // No suitable variable was found: we need a new one.
return RequiredGetCurrentTransformation.IntroduceNewVariable; return RequiredGetCurrentTransformation.IntroduceNewVariable;
} }
@ -616,13 +647,46 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(usingContainer))) if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(usingContainer)))
return false; return false;
if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(usingContainer) || !ILInlining.IsUsedAsThisPointerInCall(la))) if (storeInst.Variable.AddressInstructions.Any(la => !la.IsDescendantOf(usingContainer) || !ILInlining.IsUsedAsThisPointerInCall(la) || IsTargetOfSetterCall(la, la.Variable.Type)))
return false; return false;
if (storeInst.Variable.StoreInstructions.OfType<ILInstruction>().Any(st => st != storeInst)) if (storeInst.Variable.StoreInstructions.OfType<ILInstruction>().Any(st => st != storeInst))
return false; return false;
return true; return true;
} }
/// <summary>
/// Returns true if singleGetter is a value type and its address is used as setter target.
/// </summary>
bool CurrentIsStructSetterTarget(ILInstruction inst, CallInstruction singleGetter)
{
if (!(inst.Parent is AddressOf addr))
return false;
return IsTargetOfSetterCall(addr, singleGetter.Method.ReturnType);
}
bool IsTargetOfSetterCall(ILInstruction inst, IType targetType)
{
if (inst.ChildIndex != 0)
return false;
if (targetType.IsReferenceType ?? false)
return false;
switch (inst.Parent.OpCode) {
case OpCode.Call:
case OpCode.CallVirt:
var targetMethod = ((CallInstruction)inst.Parent).Method;
if (!targetMethod.IsAccessor || targetMethod.IsStatic)
return false;
switch (targetMethod.AccessorOwner) {
case IProperty p:
return p.Setter == targetMethod;
default:
return true;
}
default:
return false;
}
}
bool ParentIsCurrentGetter(ILInstruction inst) bool ParentIsCurrentGetter(ILInstruction inst)
{ {
return inst.Parent is CallInstruction cv && cv.Method.IsAccessor && return inst.Parent is CallInstruction cv && cv.Method.IsAccessor &&

Loading…
Cancel
Save