diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs index 72c5f7a80..cf06fd39b 100644 --- a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs @@ -5,9 +5,9 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; -using static ICSharpCode.Decompiler.Tests.FS2CS.TestRunner; +using static ICSharpCode.Decompiler.Tests.FSharpPatterns.TestHelpers; -namespace ICSharpCode.Decompiler.Tests.FS2CS +namespace ICSharpCode.Decompiler.Tests.FSharpPatterns { [TestFixture] public class FSharpPatternTests @@ -15,17 +15,17 @@ namespace ICSharpCode.Decompiler.Tests.FS2CS [Test] public void FSharpUsingDecompilesToCSharpUsing_Debug() { - var fsharpCode = FuzzyReadResource("FSharpUsing.fs"); + var ilCode = FuzzyReadResource("FSharpUsing.fs.Debug.il"); var csharpCode = FuzzyReadResource("FSharpUsing.fs.Debug.cs"); - Run(fsharpCode, csharpCode, false); + RunIL(ilCode, csharpCode); } [Test] public void FSharpUsingDecompilesToCSharpUsing_Release() { - var fsharpCode = FuzzyReadResource("FSharpUsing.fs"); + var ilCode = FuzzyReadResource("FSharpUsing.fs.Release.il"); var csharpCode = FuzzyReadResource("FSharpUsing.fs.Release.cs"); - Run(fsharpCode, csharpCode, true); + RunIL(ilCode, csharpCode); } } } diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs index 49d7adcce..3c62c0cac 100644 --- a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs @@ -1,9 +1,6 @@ -using Microsoft.FSharp.Core; -using System; +using System; using System.IO; -[assembly: FSharpInterfaceDataVersion(2, 0, 0)] -[CompilationMapping(SourceConstructFlags.Module)] public static class FSharpUsingPatterns { public static void sample1() @@ -56,10 +53,10 @@ public static class FSharpUsingPatterns } int firstByte = num; int num3; - using (FileStream fs2 = File.OpenRead("x.txt")) + using (FileStream fs = File.OpenRead("x.txt")) { - int num2 = fs2.ReadByte(); - num3 = fs2.ReadByte(); + int num2 = fs.ReadByte(); + num3 = fs.ReadByte(); } int secondByte = num3; Console.WriteLine("read: {0}, {1}", firstByte, secondByte); diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.il b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.il new file mode 100644 index 000000000..3661238ac --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.il @@ -0,0 +1,344 @@ +.class public auto ansi abstract sealed FSharpUsingPatterns + extends [mscorlib]System.Object +{ + // Methods + .method public static + void sample1 () cil managed + { + // Method begins at RVA 0x2050 + // Code size 53 (0x35) + .maxstack 4 + .locals init ( + [0] class [mscorlib]System.IO.FileStream fs, + [1] class [mscorlib]System.Object, + [2] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "x.txt" + IL_0006: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Create(string) + IL_000b: stloc.0 + .try + { + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: conv.u1 + IL_000f: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8) + IL_0014: ldnull + IL_0015: stloc.1 + IL_0016: leave.s IL_0032 + } // end .try + finally + { + IL_0018: ldloc.0 + IL_0019: isinst [mscorlib]System.IDisposable + IL_001e: stloc.2 + IL_001f: ldloc.2 + IL_0020: brfalse.s IL_0024 + + IL_0022: br.s IL_0026 + + IL_0024: br.s IL_002f + + IL_0026: ldloc.2 + IL_0027: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_002c: ldnull + IL_002d: pop + IL_002e: endfinally + + IL_002f: ldnull + IL_0030: pop + IL_0031: endfinally + } // end handler + + IL_0032: ldloc.1 + IL_0033: pop + IL_0034: ret + } // end of method FSharpUsingPatterns::sample1 + + .method public static + void sample2 () cil managed + { + // Method begins at RVA 0x20a4 + // Code size 73 (0x49) + .maxstack 4 + .locals init ( + [0] class [mscorlib]System.IO.FileStream fs, + [1] class [mscorlib]System.Object, + [2] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: ldstr "x.txt" + IL_0010: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Create(string) + IL_0015: stloc.0 + .try + { + IL_0016: ldloc.0 + IL_0017: ldc.i4.2 + IL_0018: conv.u1 + IL_0019: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8) + IL_001e: ldstr "some text" + IL_0023: call void [mscorlib]System.Console::WriteLine(string) + IL_0028: ldnull + IL_0029: stloc.1 + IL_002a: leave.s IL_0046 + } // end .try + finally + { + IL_002c: ldloc.0 + IL_002d: isinst [mscorlib]System.IDisposable + IL_0032: stloc.2 + IL_0033: ldloc.2 + IL_0034: brfalse.s IL_0038 + + IL_0036: br.s IL_003a + + IL_0038: br.s IL_0043 + + IL_003a: ldloc.2 + IL_003b: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0040: ldnull + IL_0041: pop + IL_0042: endfinally + + IL_0043: ldnull + IL_0044: pop + IL_0045: endfinally + } // end handler + + IL_0046: ldloc.1 + IL_0047: pop + IL_0048: ret + } // end of method FSharpUsingPatterns::sample2 + + .method public static + void sample3 () cil managed + { + // Method begins at RVA 0x210c + // Code size 73 (0x49) + .maxstack 4 + .locals init ( + [0] class [mscorlib]System.IO.FileStream fs, + [1] class [mscorlib]System.Object, + [2] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: ldstr "x.txt" + IL_0010: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Create(string) + IL_0015: stloc.0 + .try + { + IL_0016: ldloc.0 + IL_0017: ldc.i4.3 + IL_0018: conv.u1 + IL_0019: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8) + IL_001e: ldnull + IL_001f: stloc.1 + IL_0020: leave.s IL_003c + } // end .try + finally + { + IL_0022: ldloc.0 + IL_0023: isinst [mscorlib]System.IDisposable + IL_0028: stloc.2 + IL_0029: ldloc.2 + IL_002a: brfalse.s IL_002e + + IL_002c: br.s IL_0030 + + IL_002e: br.s IL_0039 + + IL_0030: ldloc.2 + IL_0031: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0036: ldnull + IL_0037: pop + IL_0038: endfinally + + IL_0039: ldnull + IL_003a: pop + IL_003b: endfinally + } // end handler + + IL_003c: ldloc.1 + IL_003d: pop + IL_003e: ldstr "some text" + IL_0043: call void [mscorlib]System.Console::WriteLine(string) + IL_0048: ret + } // end of method FSharpUsingPatterns::sample3 + + .method public static + void sample4 () cil managed + { + // Method begins at RVA 0x2174 + // Code size 89 (0x59) + .maxstack 4 + .locals init ( + [0] int32 firstByte, + [1] class [mscorlib]System.IO.FileStream fs, + [2] int32, + [3] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldstr "x.txt" + IL_0011: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::OpenRead(string) + IL_0016: stloc.1 + .try + { + IL_0017: ldloc.1 + IL_0018: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_001d: stloc.2 + IL_001e: leave.s IL_003a + } // end .try + finally + { + IL_0020: ldloc.1 + IL_0021: isinst [mscorlib]System.IDisposable + IL_0026: stloc.3 + IL_0027: ldloc.3 + IL_0028: brfalse.s IL_002c + + IL_002a: br.s IL_002e + + IL_002c: br.s IL_0037 + + IL_002e: ldloc.3 + IL_002f: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0034: ldnull + IL_0035: pop + IL_0036: endfinally + + IL_0037: ldnull + IL_0038: pop + IL_0039: endfinally + } // end handler + + IL_003a: ldloc.2 + IL_003b: stloc.0 + IL_003c: ldstr "read:" + IL_0041: ldloca.s firstByte + IL_0043: constrained. [mscorlib]System.Int32 + IL_0049: callvirt instance string [mscorlib]System.Object::ToString() + IL_004e: call string [mscorlib]System.String::Concat(string, string) + IL_0053: call void [mscorlib]System.Console::WriteLine(string) + IL_0058: ret + } // end of method FSharpUsingPatterns::sample4 + + .method public static + void sample5 () cil managed + { + // Method begins at RVA 0x21ec + // Code size 155 (0x9b) + .maxstack 5 + .locals init ( + [0] int32 firstByte, + [1] class [mscorlib]System.IO.FileStream fs, + [2] int32, + [3] class [mscorlib]System.IDisposable, + [4] int32 secondByte, + [5] class [mscorlib]System.IO.FileStream fs, + [6] int32, + [7] int32, + [8] int32, + [9] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldstr "x.txt" + IL_0011: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::OpenRead(string) + IL_0016: stloc.1 + .try + { + IL_0017: ldloc.1 + IL_0018: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_001d: stloc.2 + IL_001e: leave.s IL_003a + } // end .try + finally + { + IL_0020: ldloc.1 + IL_0021: isinst [mscorlib]System.IDisposable + IL_0026: stloc.3 + IL_0027: ldloc.3 + IL_0028: brfalse.s IL_002c + + IL_002a: br.s IL_002e + + IL_002c: br.s IL_0037 + + IL_002e: ldloc.3 + IL_002f: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0034: ldnull + IL_0035: pop + IL_0036: endfinally + + IL_0037: ldnull + IL_0038: pop + IL_0039: endfinally + } // end handler + + IL_003a: ldloc.2 + IL_003b: stloc.0 + IL_003c: nop + IL_003d: ldstr "x.txt" + IL_0042: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::OpenRead(string) + IL_0047: stloc.s fs + .try + { + IL_0049: ldloc.s fs + IL_004b: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_0050: stloc.s 7 + IL_0052: ldloc.s 7 + IL_0054: stloc.s 8 + IL_0056: ldloc.s fs + IL_0058: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_005d: stloc.s 6 + IL_005f: leave.s IL_007f + } // end .try + finally + { + IL_0061: ldloc.s fs + IL_0063: isinst [mscorlib]System.IDisposable + IL_0068: stloc.s 9 + IL_006a: ldloc.s 9 + IL_006c: brfalse.s IL_0070 + + IL_006e: br.s IL_0072 + + IL_0070: br.s IL_007c + + IL_0072: ldloc.s 9 + IL_0074: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0079: ldnull + IL_007a: pop + IL_007b: endfinally + + IL_007c: ldnull + IL_007d: pop + IL_007e: endfinally + } // end handler + + IL_007f: ldloc.s 6 + IL_0081: stloc.s secondByte + IL_0083: ldstr "read: {0}, {1}" + IL_0088: ldloc.0 + IL_0089: box [mscorlib]System.Int32 + IL_008e: ldloc.s secondByte + IL_0090: box [mscorlib]System.Int32 + IL_0095: call void [mscorlib]System.Console::WriteLine(string, object, object) + IL_009a: ret + } // end of method FSharpUsingPatterns::sample5 + +} // end of class FSharpUsingPatterns diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs index 8a479908a..c9d091847 100644 --- a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs @@ -1,9 +1,6 @@ -using Microsoft.FSharp.Core; -using System; +using System; using System.IO; -[assembly: FSharpInterfaceDataVersion(2, 0, 0)] -[CompilationMapping(SourceConstructFlags.Module)] public static class FSharpUsingPatterns { public static void sample1() diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.il b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.il new file mode 100644 index 000000000..6299c9687 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.il @@ -0,0 +1,311 @@ +.class public auto ansi abstract sealed FSharpUsingPatterns + extends [mscorlib]System.Object +{ + // Methods + .method public static + void sample1 () cil managed + { + // Method begins at RVA 0x2050 + // Code size 48 (0x30) + .maxstack 4 + .locals init ( + [0] class [mscorlib]System.IO.FileStream fs, + [1] class [mscorlib]System.Object, + [2] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "x.txt" + IL_0006: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Create(string) + IL_000b: stloc.0 + .try + { + IL_000c: ldloc.0 + IL_000d: ldc.i4.1 + IL_000e: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8) + IL_0013: ldnull + IL_0014: stloc.1 + IL_0015: leave.s IL_002d + } // end .try + finally + { + IL_0017: ldloc.0 + IL_0018: isinst [mscorlib]System.IDisposable + IL_001d: stloc.2 + IL_001e: ldloc.2 + IL_001f: brfalse.s IL_002a + + IL_0021: ldloc.2 + IL_0022: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0027: ldnull + IL_0028: pop + IL_0029: endfinally + + IL_002a: ldnull + IL_002b: pop + IL_002c: endfinally + } // end handler + + IL_002d: ldloc.1 + IL_002e: pop + IL_002f: ret + } // end of method FSharpUsingPatterns::sample1 + + .method public static + void sample2 () cil managed + { + // Method begins at RVA 0x209c + // Code size 68 (0x44) + .maxstack 4 + .locals init ( + [0] class [mscorlib]System.IO.FileStream fs, + [1] class [mscorlib]System.Object, + [2] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: ldstr "x.txt" + IL_0010: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Create(string) + IL_0015: stloc.0 + .try + { + IL_0016: ldloc.0 + IL_0017: ldc.i4.2 + IL_0018: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8) + IL_001d: ldstr "some text" + IL_0022: call void [mscorlib]System.Console::WriteLine(string) + IL_0027: ldnull + IL_0028: stloc.1 + IL_0029: leave.s IL_0041 + } // end .try + finally + { + IL_002b: ldloc.0 + IL_002c: isinst [mscorlib]System.IDisposable + IL_0031: stloc.2 + IL_0032: ldloc.2 + IL_0033: brfalse.s IL_003e + + IL_0035: ldloc.2 + IL_0036: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_003b: ldnull + IL_003c: pop + IL_003d: endfinally + + IL_003e: ldnull + IL_003f: pop + IL_0040: endfinally + } // end handler + + IL_0041: ldloc.1 + IL_0042: pop + IL_0043: ret + } // end of method FSharpUsingPatterns::sample2 + + .method public static + void sample3 () cil managed + { + // Method begins at RVA 0x20fc + // Code size 68 (0x44) + .maxstack 4 + .locals init ( + [0] class [mscorlib]System.IO.FileStream fs, + [1] class [mscorlib]System.Object, + [2] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: ldstr "x.txt" + IL_0010: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Create(string) + IL_0015: stloc.0 + .try + { + IL_0016: ldloc.0 + IL_0017: ldc.i4.3 + IL_0018: callvirt instance void [mscorlib]System.IO.Stream::WriteByte(uint8) + IL_001d: ldnull + IL_001e: stloc.1 + IL_001f: leave.s IL_0037 + } // end .try + finally + { + IL_0021: ldloc.0 + IL_0022: isinst [mscorlib]System.IDisposable + IL_0027: stloc.2 + IL_0028: ldloc.2 + IL_0029: brfalse.s IL_0034 + + IL_002b: ldloc.2 + IL_002c: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0031: ldnull + IL_0032: pop + IL_0033: endfinally + + IL_0034: ldnull + IL_0035: pop + IL_0036: endfinally + } // end handler + + IL_0037: ldloc.1 + IL_0038: pop + IL_0039: ldstr "some text" + IL_003e: call void [mscorlib]System.Console::WriteLine(string) + IL_0043: ret + } // end of method FSharpUsingPatterns::sample3 + + .method public static + void sample4 () cil managed + { + // Method begins at RVA 0x215c + // Code size 85 (0x55) + .maxstack 4 + .locals init ( + [0] int32 firstByte, + [1] class [mscorlib]System.IO.FileStream fs, + [2] int32, + [3] class [mscorlib]System.IDisposable + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldstr "x.txt" + IL_0011: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::OpenRead(string) + IL_0016: stloc.1 + .try + { + IL_0017: ldloc.1 + IL_0018: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_001d: stloc.2 + IL_001e: leave.s IL_0036 + } // end .try + finally + { + IL_0020: ldloc.1 + IL_0021: isinst [mscorlib]System.IDisposable + IL_0026: stloc.3 + IL_0027: ldloc.3 + IL_0028: brfalse.s IL_0033 + + IL_002a: ldloc.3 + IL_002b: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0030: ldnull + IL_0031: pop + IL_0032: endfinally + + IL_0033: ldnull + IL_0034: pop + IL_0035: endfinally + } // end handler + + IL_0036: ldloc.2 + IL_0037: stloc.0 + IL_0038: ldstr "read:" + IL_003d: ldloca.s firstByte + IL_003f: constrained. [mscorlib]System.Int32 + IL_0045: callvirt instance string [mscorlib]System.Object::ToString() + IL_004a: call string [mscorlib]System.String::Concat(string, string) + IL_004f: call void [mscorlib]System.Console::WriteLine(string) + IL_0054: ret + } // end of method FSharpUsingPatterns::sample4 + + .method public static + void sample5 () cil managed + { + // Method begins at RVA 0x21d0 + // Code size 134 (0x86) + .maxstack 5 + .locals init ( + [0] int32 firstByte, + [1] class [mscorlib]System.IO.FileStream fs, + [2] int32 secondByte, + [3] class [mscorlib]System.IDisposable, + [4] int32, + [5] int32 + ) + + IL_0000: nop + IL_0001: ldstr "some text" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldstr "x.txt" + IL_0011: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::OpenRead(string) + IL_0016: stloc.1 + .try + { + IL_0017: ldloc.1 + IL_0018: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_001d: stloc.2 + IL_001e: leave.s IL_0036 + } // end .try + finally + { + IL_0020: ldloc.1 + IL_0021: isinst [mscorlib]System.IDisposable + IL_0026: stloc.3 + IL_0027: ldloc.3 + IL_0028: brfalse.s IL_0033 + + IL_002a: ldloc.3 + IL_002b: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0030: ldnull + IL_0031: pop + IL_0032: endfinally + + IL_0033: ldnull + IL_0034: pop + IL_0035: endfinally + } // end handler + + IL_0036: ldloc.2 + IL_0037: stloc.0 + IL_0038: nop + IL_0039: ldstr "x.txt" + IL_003e: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::OpenRead(string) + IL_0043: stloc.1 + .try + { + IL_0044: ldloc.1 + IL_0045: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_004a: stloc.s 5 + IL_004c: ldloc.1 + IL_004d: callvirt instance int32 [mscorlib]System.IO.Stream::ReadByte() + IL_0052: stloc.s 4 + IL_0054: leave.s IL_006c + } // end .try + finally + { + IL_0056: ldloc.1 + IL_0057: isinst [mscorlib]System.IDisposable + IL_005c: stloc.3 + IL_005d: ldloc.3 + IL_005e: brfalse.s IL_0069 + + IL_0060: ldloc.3 + IL_0061: callvirt instance void [mscorlib]System.IDisposable::Dispose() + IL_0066: ldnull + IL_0067: pop + IL_0068: endfinally + + IL_0069: ldnull + IL_006a: pop + IL_006b: endfinally + } // end handler + + IL_006c: ldloc.s 4 + IL_006e: stloc.2 + IL_006f: ldstr "read: {0}, {1}" + IL_0074: ldloc.0 + IL_0075: box [mscorlib]System.Int32 + IL_007a: ldloc.2 + IL_007b: box [mscorlib]System.Int32 + IL_0080: call void [mscorlib]System.Console::WriteLine(string, object, object) + IL_0085: ret + } // end of method FSharpUsingPatterns::sample5 + +} // end of class FSharpUsingPatterns diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/TestRunner.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/TestHelpers.cs similarity index 53% rename from ICSharpCode.Decompiler/Tests/FSharpPatterns/TestRunner.cs rename to ICSharpCode.Decompiler/Tests/FSharpPatterns/TestHelpers.cs index e4c974a77..9b7a5a25c 100644 --- a/ICSharpCode.Decompiler/Tests/FSharpPatterns/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/TestHelpers.cs @@ -5,15 +5,16 @@ using Mono.Cecil; using NUnit.Framework; using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; -namespace ICSharpCode.Decompiler.Tests.FS2CS +namespace ICSharpCode.Decompiler.Tests.FSharpPatterns { - public class TestRunner + public class TestHelpers { public static string FuzzyReadResource(string resourceName) { @@ -32,7 +33,7 @@ namespace ICSharpCode.Decompiler.Tests.FS2CS File.WriteAllText(sourceFile, source); var asmFile = Path.ChangeExtension(sourceFile, ".dll"); var sscs = new Microsoft.FSharp.Compiler.SimpleSourceCodeServices.SimpleSourceCodeServices(); - var result = sscs.Compile(new[] { "fsc.exe", "--debug:full", $"--optimize{(optimize?"+" :"-")}", "--target:library", "-o", asmFile, sourceFile }); + var result = sscs.Compile(new[] { "fsc.exe", "--debug:full", $"--optimize{(optimize ? "+" : "-")}", "--target:library", "-o", asmFile, sourceFile }); File.Delete(sourceFile); Assert.AreEqual(0, result.Item1.Length); Assert.AreEqual(0, result.Item2); @@ -40,22 +41,58 @@ namespace ICSharpCode.Decompiler.Tests.FS2CS return asmFile; } - public static void Run(string fsharpCode, string expectedCSharpCode, bool optimize) + static Lazy ilasm = new Lazy(() => ToolLocator.FindTool("ilasm.exe")); + static Lazy ildasm = new Lazy(() => ToolLocator.FindTool("ildasm.exe")); + + public static string CompileIL(string source) + { + if (ilasm.Value == null) + Assert.NotNull(ilasm.Value, "Could not find ILASM.exe"); + var tmp = Path.GetTempFileName(); + File.Delete(tmp); + var sourceFile = Path.ChangeExtension(tmp, ".il"); + File.WriteAllText(sourceFile, source); + var asmFile = Path.ChangeExtension(sourceFile, ".dll"); + + var args = $"{sourceFile} /dll /debug /output:{asmFile}"; + using (var proc = Process.Start(new ProcessStartInfo(ilasm.Value, args) { UseShellExecute = false, })) + { + proc.WaitForExit(); + Assert.AreEqual(0, proc.ExitCode); + } + + File.Delete(sourceFile); + Assert.True(File.Exists(asmFile), "Assembly File does not exist"); + return asmFile; + } + + public static void RunIL(string ilCode, string expectedCSharpCode) + { + var asmFilePath = CompileIL(ilCode); + CompareAssemblyAgainstCSharp(expectedCSharpCode, asmFilePath); + } + + public static void RunFSharp(string fsharpCode, string expectedCSharpCode, bool optimize) { var asmFilePath = CompileFsToAssembly(fsharpCode, optimize); - var assembly = AssemblyDefinition.ReadAssembly(asmFilePath); + CompareAssemblyAgainstCSharp(expectedCSharpCode, asmFilePath); + } + + private static void CompareAssemblyAgainstCSharp(string expectedCSharpCode, string asmFilePath) + { + var module = ModuleDefinition.ReadModule(asmFilePath); try { - assembly.MainModule.ReadSymbols(); - AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule)); - decompiler.AddAssembly(assembly); + try { module.ReadSymbols(); } catch { } + AstBuilder decompiler = new AstBuilder(new DecompilerContext(module)); + decompiler.AddAssembly(module); new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree); StringWriter output = new StringWriter(); // the F# assembly contains a namespace `` where the part after tmp is randomly generated. // remove this from the ast to simplify the diff - var startupCodeNode = decompiler.SyntaxTree.Children.Single(d => (d as NamespaceDeclaration)?.Name?.StartsWith(" (d as NamespaceDeclaration)?.Name?.StartsWith(" Path.Combine(dir, fileName)).FirstOrDefault(File.Exists); + } + + private static IEnumerable FindPathForWindowsSdk() + { + string[] windowsSdkPaths = new[] + { + @"Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\", + @"Microsoft SDKs\Windows\v8.0A\bin\", + @"Microsoft SDKs\Windows\v8.0\bin\NETFX 4.0 Tools\", + @"Microsoft SDKs\Windows\v8.0\bin\", + @"Microsoft SDKs\Windows\v7.1A\bin\NETFX 4.0 Tools\", + @"Microsoft SDKs\Windows\v7.1A\bin\", + @"Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\", + @"Microsoft SDKs\Windows\v7.0A\bin\", + @"Microsoft SDKs\Windows\v6.1A\bin\", + @"Microsoft SDKs\Windows\v6.0A\bin\", + @"Microsoft SDKs\Windows\v6.0\bin\", + @"Microsoft.NET\FrameworkSDK\bin" + }; + + foreach (var possiblePath in windowsSdkPaths) + { + string fullPath = string.Empty; + + // Check alternate program file paths as well as 64-bit versions. + if (Environment.Is64BitProcess) + { + fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), possiblePath, "x64"); + if (Directory.Exists(fullPath)) + { + yield return fullPath; + } + + fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), possiblePath, "x64"); + if (Directory.Exists(fullPath)) + { + yield return fullPath; + } + } + + fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), possiblePath); + if (Directory.Exists(fullPath)) + { + yield return fullPath; + } + + fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), possiblePath); + if (Directory.Exists(fullPath)) + { + yield return fullPath; + } + } + } + + private static IEnumerable FindPathForDotNetFramework() + { + string[] frameworkPaths = new[] + { + @"Microsoft.NET\Framework\v4.0.30319", + @"Microsoft.NET\Framework\v2.0.50727" + }; + + foreach (var possiblePath in frameworkPaths) + { + string fullPath = string.Empty; + + if (Environment.Is64BitProcess) + { + fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), possiblePath.Replace(@"\Framework\", @"\Framework64\")); + if (Directory.Exists(fullPath)) + { + yield return fullPath; + } + } + + fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), possiblePath); + if (Directory.Exists(fullPath)) + { + yield return fullPath; + } + } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 5fcd81823..2eef02c12 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -89,10 +89,12 @@ + - + + @@ -168,5 +170,8 @@ + + + \ No newline at end of file