Browse Source

Merge pull request #976 from icsharpcode/loops

HighLevelLoopTransform
pull/987/head
Siegfried Pammer 8 years ago committed by GitHub
parent
commit
a9ca403260
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 39
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Capturing.cs
  2. 54
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  3. 345
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  4. 172
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il
  5. 178
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il
  6. 341
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  7. 1
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  8. 68
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  9. 120
      ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs
  10. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs
  11. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  12. 69
      ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs
  13. 1
      ILSpy/Options/DecompilerSettingsPanel.xaml
  14. 2
      ILSpy/Options/DecompilerSettingsPanel.xaml.cs

39
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Capturing.cs

@ -19,6 +19,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -19,6 +19,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
OutsideLoopOverArray();
OutsideLoopOverArray2();
InsideLoopOverArray2();
NotWhileDueToVariableInsideLoop();
NotDoWhileDueToVariableInsideLoop();
}
static void TestCase1()
@ -174,5 +176,42 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -174,5 +176,42 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine(func());
}
}
static int nextVal;
static int GetVal()
{
return ++nextVal & 7;
}
static void NotWhileDueToVariableInsideLoop()
{
Console.WriteLine("NotWhileDueToVariableInsideLoop:");
var functions = new List<Func<int>>();
while (true) {
int v;
if ((v = GetVal()) == 0)
break;
functions.Add(() => v);
}
foreach (var f in functions) {
Console.WriteLine(f());
}
}
static void NotDoWhileDueToVariableInsideLoop()
{
Console.WriteLine("NotDoWhileDueToVariableInsideLoop:");
var functions = new List<Func<int>>();
while (true) {
int v = GetVal();
functions.Add(() => v);
if (v == 0)
break;
}
foreach (var f in functions) {
Console.WriteLine(f());
}
}
}
}

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

@ -252,6 +252,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -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 static void Operation(ref int item)
@ -379,8 +391,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -379,8 +391,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
} finally {
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
if (disposable != null) {
disposable.Dispose();
}
}
Console.WriteLine("After finally!");
}
@ -389,7 +402,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -389,7 +402,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
foreach (int item in items) {
#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;
Loops.Operation(ref current);
#else
@ -440,6 +453,37 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -440,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
public void ForOverArray(string[] array)
@ -527,8 +571,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -527,8 +571,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
if (this.Condition("continue")) {
continue;
}
if (!this.Condition("break"))
if (!this.Condition("break")) {
break;
}
}
Console.WriteLine("End of loop body");
}
@ -582,8 +627,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -582,8 +627,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
if (this.Condition("continue")) {
continue;
}
if (!this.Condition("not-break"))
if (!this.Condition("not-break")) {
break;
}
}
Console.WriteLine("End of loop body");
}

345
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.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.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module n3qdq2uj.dll
// MVID: {98B4F05B-5E30-48EB-AAF5-A90EA42A94A2}
.module dky1g03y.dll
// MVID: {4ADF70C5-8EC0-41AF-A9B1-6DF95B943C1A}
.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: 0x02AD0000
// Image base: 0x03580000
// =============== CLASS MEMBERS DECLARATION ===================
@ -584,6 +584,55 @@ @@ -584,6 +584,55 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // 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'
extends [mscorlib]System.Object
{
@ -1269,7 +1318,7 @@ @@ -1269,7 +1318,7 @@
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{
// Code size 111 (0x6f)
// Code size 113 (0x71)
.maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
object V_1,
@ -1308,7 +1357,7 @@ @@ -1308,7 +1357,7 @@
IL_0044: nop
IL_0045: nop
IL_0046: nop
IL_0047: leave.s IL_0062
IL_0047: leave.s IL_0064
} // end .try
finally
@ -1322,19 +1371,21 @@ @@ -1322,19 +1371,21 @@
IL_0053: ceq
IL_0055: stloc.3
IL_0056: ldloc.3
IL_0057: brtrue.s IL_0060
IL_0057: brtrue.s IL_0062
IL_0059: ldloc.2
IL_005a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_005f: nop
IL_0059: nop
IL_005a: ldloc.2
IL_005b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0060: nop
IL_0061: endfinally
IL_0061: nop
IL_0062: nop
IL_0063: endfinally
} // end handler
IL_0062: nop
IL_0063: ldstr "After finally!"
IL_0068: call void [mscorlib]System.Console::WriteLine(string)
IL_006d: nop
IL_006e: ret
IL_0064: nop
IL_0065: ldstr "After finally!"
IL_006a: call void [mscorlib]System.Console::WriteLine(string)
IL_006f: nop
IL_0070: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig static void ForeachWithRefUsage(class [mscorlib]System.Collections.Generic.List`1<int32> items) cil managed
@ -1669,6 +1720,158 @@ @@ -1669,6 +1720,158 @@
IL_0069: ret
} // 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
ForOverArray(string[] 'array') cil managed
{
@ -1848,7 +2051,7 @@ @@ -1848,7 +2051,7 @@
.method public hidebysig instance void
WhileLoop() cil managed
{
// Code size 154 (0x9a)
// Code size 155 (0x9b)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
@ -1862,10 +2065,10 @@ @@ -1862,10 +2065,10 @@
IL_0018: ceq
IL_001a: stloc.0
IL_001b: ldloc.0
IL_001c: brtrue.s IL_008e
IL_001c: brtrue.s IL_008f
IL_001e: nop
IL_001f: br.s IL_0073
IL_001f: br.s IL_0074
IL_0021: nop
IL_0022: ldstr "Loop Body"
@ -1878,7 +2081,7 @@ @@ -1878,7 +2081,7 @@
IL_0039: ceq
IL_003b: stloc.0
IL_003c: ldloc.0
IL_003d: brtrue.s IL_0067
IL_003d: brtrue.s IL_0068
IL_003f: nop
IL_0040: ldarg.0
@ -1891,43 +2094,44 @@ @@ -1891,43 +2094,44 @@
IL_0050: brtrue.s IL_0055
IL_0052: nop
IL_0053: br.s IL_0073
IL_0053: br.s IL_0074
IL_0055: ldarg.0
IL_0056: ldstr "break"
IL_005b: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0060: stloc.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: ldstr "End of loop body"
IL_006c: call void [mscorlib]System.Console::WriteLine(string)
IL_0071: nop
IL_0067: nop
IL_0068: ldstr "End of loop body"
IL_006d: call void [mscorlib]System.Console::WriteLine(string)
IL_0072: nop
IL_0073: ldarg.0
IL_0074: ldstr "while"
IL_0079: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_007e: stloc.0
IL_007f: ldloc.0
IL_0080: brtrue.s IL_0021
IL_0082: ldstr "After loop"
IL_0087: call void [mscorlib]System.Console::WriteLine(string)
IL_008c: nop
IL_0073: nop
IL_0074: ldarg.0
IL_0075: ldstr "while"
IL_007a: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_007f: stloc.0
IL_0080: ldloc.0
IL_0081: brtrue.s IL_0021
IL_0083: ldstr "After loop"
IL_0088: call void [mscorlib]System.Console::WriteLine(string)
IL_008d: nop
IL_008e: ldstr "End of method"
IL_0093: call void [mscorlib]System.Console::WriteLine(string)
IL_0098: nop
IL_0099: ret
IL_008e: nop
IL_008f: ldstr "End of method"
IL_0094: call void [mscorlib]System.Console::WriteLine(string)
IL_0099: nop
IL_009a: ret
} // end of method Loops::WhileLoop
.method public hidebysig instance void
ForLoop() cil managed
{
// Code size 160 (0xa0)
// Code size 161 (0xa1)
.maxstack 2
.locals init (int32 V_0,
bool V_1)
@ -1942,12 +2146,12 @@ @@ -1942,12 +2146,12 @@
IL_0018: ceq
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: brtrue.s IL_0094
IL_001c: brtrue.s IL_0095
IL_001e: nop
IL_001f: ldc.i4.0
IL_0020: stloc.0
IL_0021: br.s IL_0079
IL_0021: br.s IL_007a
IL_0023: nop
IL_0024: ldstr "Loop Body"
@ -1960,7 +2164,7 @@ @@ -1960,7 +2164,7 @@
IL_003b: ceq
IL_003d: stloc.1
IL_003e: ldloc.1
IL_003f: brtrue.s IL_0069
IL_003f: brtrue.s IL_006a
IL_0041: nop
IL_0042: ldarg.0
@ -1973,41 +2177,42 @@ @@ -1973,41 +2177,42 @@
IL_0052: brtrue.s IL_0057
IL_0054: nop
IL_0055: br.s IL_0075
IL_0055: br.s IL_0076
IL_0057: ldarg.0
IL_0058: ldstr "not-break"
IL_005d: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0062: stloc.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: ldstr "End of loop body"
IL_006e: call void [mscorlib]System.Console::WriteLine(string)
IL_0073: nop
IL_0069: nop
IL_006a: ldstr "End of loop body"
IL_006f: call void [mscorlib]System.Console::WriteLine(string)
IL_0074: nop
IL_0075: ldloc.0
IL_0076: ldc.i4.1
IL_0077: add
IL_0078: stloc.0
IL_0079: ldarg.0
IL_007a: ldstr "for"
IL_007f: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0084: stloc.1
IL_0085: ldloc.1
IL_0086: brtrue.s IL_0023
IL_0088: ldstr "After loop"
IL_008d: call void [mscorlib]System.Console::WriteLine(string)
IL_0092: nop
IL_0075: nop
IL_0076: ldloc.0
IL_0077: ldc.i4.1
IL_0078: add
IL_0079: stloc.0
IL_007a: ldarg.0
IL_007b: ldstr "for"
IL_0080: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0085: stloc.1
IL_0086: ldloc.1
IL_0087: brtrue.s IL_0023
IL_0089: ldstr "After loop"
IL_008e: call void [mscorlib]System.Console::WriteLine(string)
IL_0093: nop
IL_0094: ldstr "End of method"
IL_0099: call void [mscorlib]System.Console::WriteLine(string)
IL_009e: nop
IL_009f: ret
IL_0094: nop
IL_0095: ldstr "End of method"
IL_009a: call void [mscorlib]System.Console::WriteLine(string)
IL_009f: nop
IL_00a0: ret
} // end of method Loops::ForLoop
.method public hidebysig specialname rtspecialname

172
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.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.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module spdzj2hg.dll
// MVID: {D8CD3A33-FD06-4791-A4E6-AC836DA34D06}
.module trg3dx5v.dll
// MVID: {39502A20-4431-466D-88D2-F47B21FB8C58}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x002F0000
// Image base: 0x00B30000
// =============== CLASS MEMBERS DECLARATION ===================
@ -506,6 +506,49 @@ @@ -506,6 +506,49 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // 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'
extends [mscorlib]System.Object
{
@ -1336,6 +1379,127 @@ @@ -1336,6 +1379,127 @@
IL_0056: ret
} // 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
ForOverArray(string[] 'array') cil managed
{

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

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.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 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02550000
// Image base: 0x03460000
// =============== CLASS MEMBERS DECLARATION ===================
@ -510,7 +510,50 @@ @@ -510,7 +510,50 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // 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
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
@ -523,7 +566,7 @@ @@ -523,7 +566,7 @@
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method '<>c__DisplayClass25_0'::.ctor
} // end of method '<>c__DisplayClass26_0'::.ctor
.method assembly hidebysig instance bool
'<ForeachWithCapturedVariable>b__0'() cil managed
@ -531,13 +574,13 @@ @@ -531,13 +574,13 @@
// Code size 10 (0xa)
.maxstack 8
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_0007: ceq
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
.method private hidebysig static void Operation(int32& item) cil managed
@ -1101,11 +1144,11 @@ @@ -1101,11 +1144,11 @@
IL_0009: ldloca.s V_0
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
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_0017: ldloc.1
IL_0018: stfld int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::c
IL_001d: ldftn instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops/'<>c__DisplayClass25_0'::'<ForeachWithCapturedVariable>b__0'()
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__DisplayClass26_0'::'<ForeachWithCapturedVariable>b__0'()
IL_0023: newobj instance void class [mscorlib]System.Func`1<bool>::.ctor(object,
native int)
IL_0028: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>)
@ -1295,6 +1338,121 @@ @@ -1295,6 +1338,121 @@
IL_0058: ret
} // 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
ForOverArray(string[] 'array') cil managed
{

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

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.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 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00720000
// Image base: 0x00C80000
// =============== CLASS MEMBERS DECLARATION ===================
@ -592,7 +592,52 @@ @@ -592,7 +592,52 @@
} // end of property CustomStructEnumeratorWithIDisposable`1::Current
} // 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
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
@ -606,7 +651,7 @@ @@ -606,7 +651,7 @@
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method '<>c__DisplayClass25_0'::.ctor
} // end of method '<>c__DisplayClass26_0'::.ctor
.method assembly hidebysig instance bool
'<ForeachWithCapturedVariable>b__0'() cil managed
@ -614,13 +659,13 @@ @@ -614,13 +659,13 @@
// Code size 10 (0xa)
.maxstack 8
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_0007: ceq
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
.method private hidebysig static void Operation(int32& item) cil managed
@ -1189,7 +1234,7 @@ @@ -1189,7 +1234,7 @@
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{
// Code size 109 (0x6d)
// Code size 111 (0x6f)
.maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
bool V_1,
@ -1227,7 +1272,7 @@ @@ -1227,7 +1272,7 @@
IL_0041: nop
IL_0042: nop
IL_0043: nop
IL_0044: leave.s IL_0061
IL_0044: leave.s IL_0063
} // end .try
finally
@ -1241,18 +1286,20 @@ @@ -1241,18 +1286,20 @@
IL_0050: cgt.un
IL_0052: stloc.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_0059: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_005e: nop
IL_0058: nop
IL_0059: ldloc.3
IL_005a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_005f: nop
IL_0060: endfinally
IL_0060: nop
IL_0061: nop
IL_0062: endfinally
} // end handler
IL_0061: ldstr "After finally!"
IL_0066: call void [mscorlib]System.Console::WriteLine(string)
IL_006b: nop
IL_006c: ret
IL_0063: ldstr "After finally!"
IL_0068: call void [mscorlib]System.Console::WriteLine(string)
IL_006d: nop
IL_006e: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig static void ForeachWithRefUsage(class [mscorlib]System.Collections.Generic.List`1<int32> items) cil managed
@ -1305,7 +1352,7 @@ @@ -1305,7 +1352,7 @@
.maxstack 2
.locals init (valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> V_0,
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_0001: nop
IL_0002: ldarg.0
@ -1318,14 +1365,14 @@ @@ -1318,14 +1365,14 @@
IL_000b: ldloca.s V_0
IL_000d: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
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_0019: nop
IL_001a: ldloc.2
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_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,
native int)
IL_002d: call void ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Operation(class [mscorlib]System.Func`1<bool>)
@ -1554,6 +1601,146 @@ @@ -1554,6 +1601,146 @@
IL_0060: ret
} // 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
ForOverArray(string[] 'array') cil managed
{
@ -1732,7 +1919,7 @@ @@ -1732,7 +1919,7 @@
.method public hidebysig instance void
WhileLoop() cil managed
{
// Code size 150 (0x96)
// Code size 151 (0x97)
.maxstack 2
.locals init (bool V_0,
bool V_1,
@ -1748,10 +1935,10 @@ @@ -1748,10 +1935,10 @@
IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0017: stloc.0
IL_0018: ldloc.0
IL_0019: brfalse.s IL_008a
IL_0019: brfalse.s IL_008b
IL_001b: nop
IL_001c: br.s IL_006d
IL_001c: br.s IL_006e
IL_001e: nop
IL_001f: ldstr "Loop Body"
@ -1762,7 +1949,7 @@ @@ -1762,7 +1949,7 @@
IL_0030: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0035: stloc.1
IL_0036: ldloc.1
IL_0037: brfalse.s IL_0061
IL_0037: brfalse.s IL_0062
IL_0039: nop
IL_003a: ldarg.0
@ -1773,7 +1960,7 @@ @@ -1773,7 +1960,7 @@
IL_0047: brfalse.s IL_004c
IL_0049: nop
IL_004a: br.s IL_006d
IL_004a: br.s IL_006e
IL_004c: ldarg.0
IL_004d: ldstr "break"
@ -1782,36 +1969,37 @@ @@ -1782,36 +1969,37 @@
IL_0058: ceq
IL_005a: stloc.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: ldstr "End of loop body"
IL_0066: call void [mscorlib]System.Console::WriteLine(string)
IL_006b: nop
IL_0061: nop
IL_0062: ldstr "End of loop body"
IL_0067: call void [mscorlib]System.Console::WriteLine(string)
IL_006c: nop
IL_006d: ldarg.0
IL_006e: ldstr "while"
IL_0073: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0078: stloc.s V_4
IL_007a: ldloc.s V_4
IL_007c: brtrue.s IL_001e
IL_007e: ldstr "After loop"
IL_0083: call void [mscorlib]System.Console::WriteLine(string)
IL_0088: nop
IL_006d: nop
IL_006e: ldarg.0
IL_006f: ldstr "while"
IL_0074: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0079: stloc.s V_4
IL_007b: ldloc.s V_4
IL_007d: brtrue.s IL_001e
IL_007f: ldstr "After loop"
IL_0084: call void [mscorlib]System.Console::WriteLine(string)
IL_0089: nop
IL_008a: ldstr "End of method"
IL_008f: call void [mscorlib]System.Console::WriteLine(string)
IL_0094: nop
IL_0095: ret
IL_008a: nop
IL_008b: ldstr "End of method"
IL_0090: call void [mscorlib]System.Console::WriteLine(string)
IL_0095: nop
IL_0096: ret
} // end of method Loops::WhileLoop
.method public hidebysig instance void
ForLoop() cil managed
{
// Code size 158 (0x9e)
// Code size 159 (0x9f)
.maxstack 2
.locals init (bool V_0,
int32 V_1,
@ -1828,12 +2016,12 @@ @@ -1828,12 +2016,12 @@
IL_0012: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0017: stloc.0
IL_0018: ldloc.0
IL_0019: brfalse.s IL_0092
IL_0019: brfalse.s IL_0093
IL_001b: nop
IL_001c: ldc.i4.0
IL_001d: stloc.1
IL_001e: br.s IL_0075
IL_001e: br.s IL_0076
IL_0020: nop
IL_0021: ldstr "Loop Body"
@ -1844,7 +2032,7 @@ @@ -1844,7 +2032,7 @@
IL_0032: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0037: stloc.2
IL_0038: ldloc.2
IL_0039: brfalse.s IL_0065
IL_0039: brfalse.s IL_0066
IL_003b: nop
IL_003c: ldarg.0
@ -1855,7 +2043,7 @@ @@ -1855,7 +2043,7 @@
IL_0049: brfalse.s IL_004e
IL_004b: nop
IL_004c: br.s IL_0071
IL_004c: br.s IL_0072
IL_004e: ldarg.0
IL_004f: ldstr "not-break"
@ -1864,34 +2052,35 @@ @@ -1864,34 +2052,35 @@
IL_005a: ceq
IL_005c: stloc.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: ldstr "End of loop body"
IL_006a: call void [mscorlib]System.Console::WriteLine(string)
IL_006f: nop
IL_0065: nop
IL_0066: ldstr "End of loop body"
IL_006b: call void [mscorlib]System.Console::WriteLine(string)
IL_0070: nop
IL_0071: ldloc.1
IL_0072: ldc.i4.1
IL_0073: add
IL_0074: stloc.1
IL_0075: ldarg.0
IL_0076: ldstr "for"
IL_007b: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0080: stloc.s V_5
IL_0082: ldloc.s V_5
IL_0084: brtrue.s IL_0020
IL_0086: ldstr "After loop"
IL_008b: call void [mscorlib]System.Console::WriteLine(string)
IL_0090: nop
IL_0071: nop
IL_0072: ldloc.1
IL_0073: ldc.i4.1
IL_0074: add
IL_0075: stloc.1
IL_0076: ldarg.0
IL_0077: ldstr "for"
IL_007c: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0081: stloc.s V_5
IL_0083: ldloc.s V_5
IL_0085: brtrue.s IL_0020
IL_0087: ldstr "After loop"
IL_008c: call void [mscorlib]System.Console::WriteLine(string)
IL_0091: nop
IL_0092: ldstr "End of method"
IL_0097: call void [mscorlib]System.Console::WriteLine(string)
IL_009c: nop
IL_009d: ret
IL_0092: nop
IL_0093: ldstr "End of method"
IL_0098: call void [mscorlib]System.Console::WriteLine(string)
IL_009d: nop
IL_009e: ret
} // end of method Loops::ForLoop
.method public hidebysig specialname rtspecialname

1
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -152,6 +152,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -152,6 +152,7 @@ namespace ICSharpCode.Decompiler.CSharp
new IntroduceExtensionMethods(), // must run after IntroduceUsingDeclarations
new IntroduceQueryExpressions(), // must run after IntroduceExtensionMethods
new CombineQueryExpressions(),
new NormalizeBlockStatements(),
new FlattenSwitchBlocks(),
new FixNameCollisions(),
new AddXmlDocumentationTransform(),

68
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -471,6 +471,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -471,6 +471,19 @@ namespace ICSharpCode.Decompiler.CSharp
instToReplace.ReplaceWith(new LdLoc(foreachVariable));
body.Instructions.Insert(0, new StLoc(foreachVariable, instToReplace));
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:
var whileLoop = (WhileStatement)ConvertAsBlock(container).First();
@ -563,7 +576,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -563,7 +576,20 @@ namespace ICSharpCode.Decompiler.CSharp
/// ... (ldloc foreachVar) ...
/// </code>
/// </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>
@ -603,6 +629,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -603,6 +629,11 @@ namespace ICSharpCode.Decompiler.CSharp
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.
return RequiredGetCurrentTransformation.IntroduceNewVariable;
}
@ -616,13 +647,46 @@ namespace ICSharpCode.Decompiler.CSharp @@ -616,13 +647,46 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(usingContainer)))
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;
if (storeInst.Variable.StoreInstructions.OfType<ILInstruction>().Any(st => st != storeInst))
return false;
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)
{
return inst.Parent is CallInstruction cv && cv.Method.IsAccessor &&

120
ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs

@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.CSharp.Syntax;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
class NormalizeBlockStatements : DepthFirstAstVisitor, IAstTransform
{
TransformContext context;
public override void VisitIfElseStatement(IfElseStatement ifElseStatement)
{
base.VisitIfElseStatement(ifElseStatement);
DoTransform(ifElseStatement.TrueStatement, ifElseStatement);
DoTransform(ifElseStatement.FalseStatement, ifElseStatement);
}
public override void VisitWhileStatement(WhileStatement whileStatement)
{
base.VisitWhileStatement(whileStatement);
InsertBlock(whileStatement.EmbeddedStatement);
}
public override void VisitDoWhileStatement(DoWhileStatement doWhileStatement)
{
base.VisitDoWhileStatement(doWhileStatement);
InsertBlock(doWhileStatement.EmbeddedStatement);
}
public override void VisitForeachStatement(ForeachStatement foreachStatement)
{
base.VisitForeachStatement(foreachStatement);
InsertBlock(foreachStatement.EmbeddedStatement);
}
public override void VisitForStatement(ForStatement forStatement)
{
base.VisitForStatement(forStatement);
InsertBlock(forStatement.EmbeddedStatement);
}
public override void VisitFixedStatement(FixedStatement fixedStatement)
{
base.VisitFixedStatement(fixedStatement);
InsertBlock(fixedStatement.EmbeddedStatement);
}
public override void VisitLockStatement(LockStatement lockStatement)
{
base.VisitLockStatement(lockStatement);
InsertBlock(lockStatement.EmbeddedStatement);
}
public override void VisitUsingStatement(UsingStatement usingStatement)
{
base.VisitUsingStatement(usingStatement);
DoTransform(usingStatement.EmbeddedStatement, usingStatement);
}
void DoTransform(Statement statement, Statement parent)
{
if (statement.IsNull) return;
if (context.Settings.AlwaysUseBraces) {
if (!IsElseIf(statement, parent)) {
InsertBlock(statement);
}
} else {
if (statement is BlockStatement b && b.Statements.Count == 1 && IsAllowedAsEmbeddedStatement(b.Statements.First(), parent)) {
statement.ReplaceWith(b.Statements.First().Detach());
} else if (!IsAllowedAsEmbeddedStatement(statement, parent)) {
InsertBlock(statement);
}
}
}
bool IsElseIf(Statement statement, Statement parent)
{
return parent is IfElseStatement && statement.Role == IfElseStatement.FalseRole;
}
static void InsertBlock(Statement statement)
{
if (statement.IsNull) return;
if (!(statement is BlockStatement)) {
var b = new BlockStatement();
statement.ReplaceWith(b);
b.Add(statement);
}
}
bool IsAllowedAsEmbeddedStatement(Statement statement, Statement parent)
{
switch (statement) {
case IfElseStatement ies:
return parent is IfElseStatement && ies.Role == IfElseStatement.FalseRole;
case VariableDeclarationStatement vds:
case WhileStatement ws:
case DoWhileStatement dws:
case SwitchStatement ss:
case ForeachStatement fes:
case ForStatement fs:
case LockStatement ls:
case FixedStatement fxs:
return false;
case UsingStatement us:
return parent is UsingStatement;
default:
return !(parent?.Parent is IfElseStatement);
}
}
void IAstTransform.Run(AstNode rootNode, TransformContext context)
{
this.context = context;
rootNode.AcceptVisitor(this);
}
}
}

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -178,6 +178,21 @@ namespace ICSharpCode.Decompiler @@ -178,6 +178,21 @@ namespace ICSharpCode.Decompiler
}
}
bool alwaysUseBraces = true;
/// <summary>
/// Gets/Sets whether to use braces for single-statement-blocks.
/// </summary>
public bool AlwaysUseBraces {
get { return alwaysUseBraces; }
set {
if (alwaysUseBraces != value) {
alwaysUseBraces = value;
OnPropertyChanged();
}
}
}
bool forEachStatement = true;
/// <summary>

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -230,6 +230,7 @@ @@ -230,6 +230,7 @@
<Compile Include="CSharp\Transforms\FlattenSwitchBlocks.cs" />
<Compile Include="CSharp\Transforms\IntroduceExtensionMethods.cs" />
<Compile Include="CSharp\Transforms\IntroduceQueryExpressions.cs" />
<Compile Include="CSharp\Transforms\NormalizeBlockStatements.cs" />
<Compile Include="CSharp\Transforms\PrettifyAssignments.cs" />
<Compile Include="CSharp\Transforms\RemoveCLSCompliantAttribute.cs" />
<Compile Include="CSharp\TranslationContext.cs" />

69
ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs

@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
bool MatchWhileLoop(BlockContainer loop, out ILInstruction condition, out Block loopBody)
bool MatchWhileLoop(BlockContainer loop, out IfInstruction condition, out Block loopBody)
{
// while-loop:
// if (loop-condition) br loop-content-block
@ -64,7 +64,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -64,7 +64,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!ifInstruction.FalseInst.MatchNop())
return false;
condition = ifInstruction.Condition;
if (UsesVariableCapturedInLoop(loop, ifInstruction.Condition))
return false;
condition = ifInstruction;
var trueInst = ifInstruction.TrueInst;
if (!loop.EntryPoint.Instructions[1].MatchLeave(loop))
return false;
@ -90,13 +92,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -90,13 +92,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
void SplitConditions(ILInstruction expression, List<ILInstruction> conditions)
{
if (expression.MatchLogicAnd(out var l, out var r)) {
SplitConditions(l, conditions);
SplitConditions(r, conditions);
} else {
conditions.Add(expression);
}
}
/// <summary>
/// Matches a do-while loop and performs the following transformations:
/// - combine all compatible conditions into one IfInstruction.
/// - extract conditions into a condition block, or move the existing condition block to the end.
/// </summary>
/// <param name="loop"></param>
/// <returns></returns>
bool MatchDoWhileLoop(BlockContainer loop)
{
(List<IfInstruction> conditions, ILInstruction exit, bool swap, bool split) = AnalyzeDoWhileConditions(loop);
@ -180,6 +190,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -180,6 +190,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
while (i >= 0 && block.Instructions[i] is IfInstruction ifInst) {
if (!ifInst.FalseInst.MatchNop())
break;
if (UsesVariableCapturedInLoop(loop, ifInst.Condition))
break;
if (swap) {
if (!ifInst.TrueInst.MatchLeave(loop))
break;
@ -195,6 +207,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -195,6 +207,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return list;
}
static bool UsesVariableCapturedInLoop(BlockContainer loop, ILInstruction condition)
{
foreach (var inst in condition.Descendants.OfType<IInstructionWithVariableOperand>()) {
if (inst.Variable.CaptureScope == loop)
return true;
}
return false;
}
static bool MatchDoWhileConditionBlock(BlockContainer loop, Block block, out bool swapBranches)
{
// match the end of the block:
@ -230,7 +251,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -230,7 +251,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
bool MatchForLoop(BlockContainer loop, ILInstruction condition, Block whileLoopBody)
bool MatchForLoop(BlockContainer loop, IfInstruction whileCondition, Block whileLoopBody)
{
// for loops have exactly two incoming edges at the entry point.
if (loop.EntryPoint.IncomingEdgeCount != 2)
@ -267,10 +288,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -267,10 +288,35 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// the increment variable must be local/stack variable
if (incrementVariable.Kind == VariableKind.Parameter)
return false;
// the increment variable must be checked in the condition
if (!condition.Descendants.Any(inst => inst.MatchLdLoc(incrementVariable)))
// split conditions:
var conditions = new List<ILInstruction>();
SplitConditions(whileCondition.Condition, conditions);
IfInstruction forCondition = null;
int numberOfConditions = 0;
foreach (var condition in conditions) {
// the increment variable must be used in the condition
if (!condition.Descendants.Any(inst => inst.MatchLdLoc(incrementVariable)))
break;
// condition should not contain an assignment
if (condition.Descendants.Any(IsAssignment))
break;
if (forCondition == null) {
forCondition = new IfInstruction(condition, whileCondition.TrueInst, whileCondition.FalseInst);
} else {
forCondition.Condition = IfInstruction.LogicAnd(forCondition.Condition, condition);
}
numberOfConditions++;
}
if (numberOfConditions == 0)
return false;
context.Step("Transform to for loop", loop);
// split condition block:
whileCondition.ReplaceWith(forCondition);
new ExpressionTransforms().Run(loop.EntryPoint, forCondition.ChildIndex, new StatementTransformContext(new BlockTransformContext(context)));
for (int i = conditions.Count - 1; i >= numberOfConditions; i--) {
whileLoopBody.Instructions.Insert(0, new IfInstruction(Comp.LogicNot(conditions[i]), new Leave(loop)));
new ExpressionTransforms().Run(whileLoopBody, 0, new StatementTransformContext(new BlockTransformContext(context)));
}
// create a new increment block and add it at the end:
int secondToLastIndex = secondToLast.ChildIndex;
var newIncremenBlock = new Block();
@ -287,6 +333,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -287,6 +333,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
bool IsAssignment(ILInstruction inst)
{
if (inst is StLoc)
return true;
if (inst is CompoundAssignmentInstruction)
return true;
return false;
}
/// <summary>
/// Returns true if the instruction is stloc v(add(ldloc v, arg))
/// or stloc v(compound.assign(ldloc v, arg))

1
ILSpy/Options/DecompilerSettingsPanel.xaml

@ -17,5 +17,6 @@ @@ -17,5 +17,6 @@
<CheckBox IsChecked="{Binding RemoveDeadCode}">Remove dead and side effect free code</CheckBox>
<CheckBox IsChecked="{Binding UsingDeclarations}">Insert using declarations</CheckBox>
<CheckBox IsChecked="{Binding FullyQualifyAmbiguousTypeNames}">Fully qualify ambiguous type names</CheckBox>
<CheckBox IsChecked="{Binding AlwaysUseBraces}">Always use braces</CheckBox>
</StackPanel>
</UserControl>

2
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

@ -63,6 +63,7 @@ namespace ICSharpCode.ILSpy.Options @@ -63,6 +63,7 @@ namespace ICSharpCode.ILSpy.Options
s.FoldBraces = (bool?)e.Attribute("foldBraces") ?? s.FoldBraces;
s.UsingDeclarations = (bool?)e.Attribute("usingDeclarations") ?? s.UsingDeclarations;
s.FullyQualifyAmbiguousTypeNames = (bool?)e.Attribute("fullyQualifyAmbiguousTypeNames") ?? s.FullyQualifyAmbiguousTypeNames;
s.AlwaysUseBraces = (bool?)e.Attribute("alwaysUseBraces") ?? s.AlwaysUseBraces;
return s;
}
@ -84,6 +85,7 @@ namespace ICSharpCode.ILSpy.Options @@ -84,6 +85,7 @@ namespace ICSharpCode.ILSpy.Options
section.SetAttributeValue("foldBraces", s.RemoveDeadCode);
section.SetAttributeValue("usingDeclarations", s.UsingDeclarations);
section.SetAttributeValue("fullyQualifyAmbiguousTypeNames", s.FullyQualifyAmbiguousTypeNames);
section.SetAttributeValue("alwaysUseBraces", s.AlwaysUseBraces);
XElement existingElement = root.Element("DecompilerSettings");
if (existingElement != null)

Loading…
Cancel
Save