From d059c02ba30a0194dc0b01edd541bc9356a1e7e0 Mon Sep 17 00:00:00 2001 From: lrieger Date: Sun, 10 Jan 2016 20:52:09 +0100 Subject: [PATCH] test that the "F# using" does not get applied if the 'disposable' variable is used afterwards add F# to C# decompilation unit tests --- .../FSharpPatterns/FSharpPatternTests.cs | 31 ++++++++ .../Tests/FSharpPatterns/FSharpUsing.fs | 38 ++++++++++ .../FSharpPatterns/FSharpUsing.fs.Debug.cs | 67 +++++++++++++++++ .../FSharpPatterns/FSharpUsing.fs.Release.cs | 67 +++++++++++++++++ .../Tests/FSharpPatterns/TestRunner.cs | 72 +++++++++++++++++++ .../Tests/ICSharpCode.Decompiler.Tests.csproj | 19 ++++- ICSharpCode.Decompiler/Tests/NotUsingBlock.cs | 28 ++++++++ ICSharpCode.Decompiler/Tests/TestRunner.cs | 11 ++- ICSharpCode.Decompiler/Tests/packages.config | 1 + 9 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs create mode 100644 ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs create mode 100644 ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs create mode 100644 ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs create mode 100644 ICSharpCode.Decompiler/Tests/FSharpPatterns/TestRunner.cs create mode 100644 ICSharpCode.Decompiler/Tests/NotUsingBlock.cs diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs new file mode 100644 index 000000000..72c5f7a80 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpPatternTests.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using static ICSharpCode.Decompiler.Tests.FS2CS.TestRunner; + +namespace ICSharpCode.Decompiler.Tests.FS2CS +{ + [TestFixture] + public class FSharpPatternTests + { + [Test] + public void FSharpUsingDecompilesToCSharpUsing_Debug() + { + var fsharpCode = FuzzyReadResource("FSharpUsing.fs"); + var csharpCode = FuzzyReadResource("FSharpUsing.fs.Debug.cs"); + Run(fsharpCode, csharpCode, false); + } + + [Test] + public void FSharpUsingDecompilesToCSharpUsing_Release() + { + var fsharpCode = FuzzyReadResource("FSharpUsing.fs"); + var csharpCode = FuzzyReadResource("FSharpUsing.fs.Release.cs"); + Run(fsharpCode, csharpCode, true); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs new file mode 100644 index 000000000..5db5939da --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs @@ -0,0 +1,38 @@ +module FSharpUsingPatterns + +open System +open System.IO + +let sample1() = + use fs = File.Create("x.txt") + fs.WriteByte(byte 1) + +let sample2() = + Console.WriteLine("some text") + use fs = File.Create("x.txt") + fs.WriteByte(byte 2) + Console.WriteLine("some text") + +let sample3() = + Console.WriteLine("some text") + do use fs = File.Create("x.txt") + fs.WriteByte(byte 3) + Console.WriteLine("some text") + +let sample4() = + Console.WriteLine("some text") + let firstByte = + use fs = File.OpenRead("x.txt") + fs.ReadByte() + Console.WriteLine("read:" + firstByte.ToString()) + +let sample5() = + Console.WriteLine("some text") + let firstByte = + use fs = File.OpenRead("x.txt") + fs.ReadByte() + let secondByte = + use fs = File.OpenRead("x.txt") + fs.ReadByte() |> ignore + fs.ReadByte() + Console.WriteLine("read: {0}, {1}", firstByte, secondByte) diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs new file mode 100644 index 000000000..49d7adcce --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Debug.cs @@ -0,0 +1,67 @@ +using Microsoft.FSharp.Core; +using System; +using System.IO; + +[assembly: FSharpInterfaceDataVersion(2, 0, 0)] +[CompilationMapping(SourceConstructFlags.Module)] +public static class FSharpUsingPatterns +{ + public static void sample1() + { + using (FileStream fs = File.Create("x.txt")) + { + fs.WriteByte((byte)1); + } + } + + public static void sample2() + { + Console.WriteLine("some text"); + using (FileStream fs = File.Create("x.txt")) + { + fs.WriteByte((byte)2); + Console.WriteLine("some text"); + } + } + + public static void sample3() + { + Console.WriteLine("some text"); + using (FileStream fs = File.Create("x.txt")) + { + fs.WriteByte((byte)3); + } + Console.WriteLine("some text"); + } + + public static void sample4() + { + Console.WriteLine("some text"); + int num; + using (FileStream fs = File.OpenRead("x.txt")) + { + num = fs.ReadByte(); + } + int firstByte = num; + Console.WriteLine("read:" + firstByte.ToString()); + } + + public static void sample5() + { + Console.WriteLine("some text"); + int num; + using (FileStream fs = File.OpenRead("x.txt")) + { + num = fs.ReadByte(); + } + int firstByte = num; + int num3; + using (FileStream fs2 = File.OpenRead("x.txt")) + { + int num2 = fs2.ReadByte(); + num3 = fs2.ReadByte(); + } + int secondByte = num3; + Console.WriteLine("read: {0}, {1}", firstByte, secondByte); + } +} diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs new file mode 100644 index 000000000..8a479908a --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/FSharpUsing.fs.Release.cs @@ -0,0 +1,67 @@ +using Microsoft.FSharp.Core; +using System; +using System.IO; + +[assembly: FSharpInterfaceDataVersion(2, 0, 0)] +[CompilationMapping(SourceConstructFlags.Module)] +public static class FSharpUsingPatterns +{ + public static void sample1() + { + using (FileStream fs = File.Create("x.txt")) + { + fs.WriteByte(1); + } + } + + public static void sample2() + { + Console.WriteLine("some text"); + using (FileStream fs = File.Create("x.txt")) + { + fs.WriteByte(2); + Console.WriteLine("some text"); + } + } + + public static void sample3() + { + Console.WriteLine("some text"); + using (FileStream fs = File.Create("x.txt")) + { + fs.WriteByte(3); + } + Console.WriteLine("some text"); + } + + public static void sample4() + { + Console.WriteLine("some text"); + int num; + using (FileStream fs = File.OpenRead("x.txt")) + { + num = fs.ReadByte(); + } + int firstByte = num; + Console.WriteLine("read:" + firstByte.ToString()); + } + + public static void sample5() + { + Console.WriteLine("some text"); + int secondByte; + using (FileStream fs = File.OpenRead("x.txt")) + { + secondByte = fs.ReadByte(); + } + int firstByte = secondByte; + int num2; + using (FileStream fs = File.OpenRead("x.txt")) + { + int num = fs.ReadByte(); + num2 = fs.ReadByte(); + } + secondByte = num2; + Console.WriteLine("read: {0}, {1}", firstByte, secondByte); + } +} diff --git a/ICSharpCode.Decompiler/Tests/FSharpPatterns/TestRunner.cs b/ICSharpCode.Decompiler/Tests/FSharpPatterns/TestRunner.cs new file mode 100644 index 000000000..e4c974a77 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/FSharpPatterns/TestRunner.cs @@ -0,0 +1,72 @@ +using ICSharpCode.Decompiler.Ast; +using ICSharpCode.Decompiler.Tests.Helpers; +using ICSharpCode.NRefactory.CSharp; +using Mono.Cecil; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace ICSharpCode.Decompiler.Tests.FS2CS +{ + public class TestRunner + { + public static string FuzzyReadResource(string resourceName) + { + var asm = Assembly.GetExecutingAssembly(); + var allResources = asm.GetManifestResourceNames(); + var fullResourceName = allResources.Single(r => r.ToLowerInvariant().EndsWith(resourceName.ToLowerInvariant())); + return new StreamReader(asm.GetManifestResourceStream(fullResourceName)).ReadToEnd(); + } + + // see https://fsharp.github.io/FSharp.Compiler.Service/compiler.html + public static string CompileFsToAssembly(string source, bool optimize) + { + var tmp = Path.GetTempFileName(); + File.Delete(tmp); + var sourceFile = Path.ChangeExtension(tmp, ".fs"); + 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 }); + File.Delete(sourceFile); + Assert.AreEqual(0, result.Item1.Length); + Assert.AreEqual(0, result.Item2); + Assert.True(File.Exists(asmFile), "Assembly File does not exist"); + return asmFile; + } + + public static void Run(string fsharpCode, string expectedCSharpCode, bool optimize) + { + var asmFilePath = CompileFsToAssembly(fsharpCode, optimize); + var assembly = AssemblyDefinition.ReadAssembly(asmFilePath); + try + { + assembly.MainModule.ReadSymbols(); + AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule)); + decompiler.AddAssembly(assembly); + 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(" ..\..\packages\DiffLib.1.0.0.55\lib\net35-Client\DiffLib.dll + + ..\..\packages\FSharp.Compiler.Service.2.0.0.2\lib\net45\FSharp.Compiler.Service.dll + True + ..\..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll False @@ -86,12 +90,16 @@ + + + + @@ -131,6 +139,10 @@ {d68133bd-1e63-496e-9ede-4fbdbf77b486} Mono.Cecil + + {63e6915c-7ea4-4d76-ab28-0d7191eea626} + Mono.Cecil.Pdb + {53dca265-3c3c-42f9-b647-f72ba678122b} ICSharpCode.NRefactory.CSharp @@ -144,12 +156,17 @@ ICSharpCode.Decompiler - + + + + + + \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Tests/NotUsingBlock.cs b/ICSharpCode.Decompiler/Tests/NotUsingBlock.cs new file mode 100644 index 000000000..b20750ac8 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/NotUsingBlock.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; + +namespace ICSharpCode.Decompiler.Tests +{ + public class NotUsingBlock + { + public void ThisIsNotAUsingBlock() + { + object obj = File.OpenRead("..."); + IDisposable disposable; + try + { + (obj as FileStream).WriteByte(2); + Console.WriteLine("some text"); + } + finally + { + disposable = (obj as IDisposable); + if (disposable != null) + { + disposable.Dispose(); + } + } + Console.WriteLine(disposable); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index 215725b0a..1af5bec0c 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -180,13 +180,20 @@ namespace ICSharpCode.Decompiler.Tests { TestFile(@"..\..\Tests\YieldReturn.cs"); } - + [Test] public void TypeAnalysis() { TestFile(@"..\..\Tests\TypeAnalysisTests.cs"); } - + + // see https://github.com/icsharpcode/ILSpy/pull/671 + [Test] + public void NotUsingBlock() + { + TestFile(@"..\..\Tests\NotUsingBlock.cs"); + } + static void TestFile(string fileName, bool useDebug = false, int compilerVersion = 4) { AssertRoundtripCode(fileName, optimize: false, useDebug: useDebug, compilerVersion: compilerVersion); diff --git a/ICSharpCode.Decompiler/Tests/packages.config b/ICSharpCode.Decompiler/Tests/packages.config index 44cab4495..6f43524a9 100644 --- a/ICSharpCode.Decompiler/Tests/packages.config +++ b/ICSharpCode.Decompiler/Tests/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file