1+ // Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
2+
3+ module FSharp.Compiler.UnitTests.Utilities
4+
5+ open System
6+ open System.IO
7+ open System.Collections .Immutable
8+ open Microsoft.CodeAnalysis
9+ open Microsoft.CodeAnalysis .CSharp
10+
11+ // This file mimics how Roslyn handles their compilation references for compilation testing
12+
13+ [<RequireQualifiedAccess>]
14+ type TargetFramework =
15+ | NetStandard20
16+ | NetCoreApp30
17+
18+ module private TestReferences =
19+
20+ [<RequireQualifiedAccess>]
21+ module NetStandard20 =
22+
23+ let netStandard = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netstandard20.netstandard) .GetReference( display = " netstandard.dll (netstandard 2.0 ref)" )
24+
25+ let mscorlibRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netstandard20.mscorlib) .GetReference( display = " mscorlib.dll (netstandard 2.0 ref)" )
26+
27+ let systemRuntimeRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netstandard20.System_ Runtime) .GetReference( display = " System.Runtime.dll (netstandard 2.0 ref)" )
28+
29+ let systemCoreRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netstandard20.System_ Core) .GetReference( display = " System.Core.dll (netstandard 2.0 ref)" )
30+
31+ let systemDynamicRuntimeRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netstandard20.System_ Dynamic_ Runtime) .GetReference( display = " System.Dynamic.Runtime.dll (netstandard 2.0 ref)" )
32+
33+ [<RequireQualifiedAccess>]
34+ module NetCoreApp30 =
35+
36+ let netStandard = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netcoreapp30.netstandard) .GetReference( display = " netstandard.dll (netcoreapp 3.0 ref)" )
37+
38+ let mscorlibRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netcoreapp30.mscorlib) .GetReference( display = " mscorlib.dll (netcoreapp 3.0 ref)" )
39+
40+ let systemRuntimeRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netcoreapp30.System_ Runtime) .GetReference( display = " System.Runtime.dll (netcoreapp 3.0 ref)" )
41+
42+ let systemCoreRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netcoreapp30.System_ Core) .GetReference( display = " System.Core.dll (netcoreapp 3.0 ref)" )
43+
44+ let systemDynamicRuntimeRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netcoreapp30.System_ Dynamic_ Runtime) .GetReference( display = " System.Dynamic.Runtime.dll (netcoreapp 3.0 ref)" )
45+
46+ let systemConsoleRef = lazy AssemblyMetadata.CreateFromImage( TestResources.NetFX.netcoreapp30.System_ Console) .GetReference( display = " System.Console.dll (netcoreapp 3.0 ref)" )
47+
48+
49+ [<RequireQualifiedAccess>]
50+ module private TargetFrameworkUtil =
51+
52+ open TestReferences
53+
54+ let private netStandard20References =
55+ lazy ImmutableArray.Create( NetStandard20.netStandard.Value, NetStandard20.mscorlibRef.Value, NetStandard20.systemRuntimeRef.Value, NetStandard20.systemCoreRef.Value, NetStandard20.systemDynamicRuntimeRef.Value)
56+
57+ let private netCoreApp30References =
58+ lazy ImmutableArray.Create( NetCoreApp30.netStandard.Value, NetCoreApp30.mscorlibRef.Value, NetCoreApp30.systemRuntimeRef.Value, NetCoreApp30.systemCoreRef.Value, NetCoreApp30.systemDynamicRuntimeRef.Value, NetCoreApp30.systemConsoleRef.Value)
59+
60+ let getReferences tf =
61+ match tf with
62+ | TargetFramework.NetStandard20 -> netStandard20References.Value
63+ | TargetFramework.NetCoreApp30 -> netCoreApp30References.Value
64+
65+ type RoslynLanguageVersion = LanguageVersion
66+
67+ [<Flags>]
68+ type CSharpCompilationFlags =
69+ | None = 0x0
70+ | InternalsVisibleTo = 0x1
71+
72+ [<RequireQualifiedAccess>]
73+ type TestCompilation =
74+ | CSharp of CSharpCompilation * CSharpCompilationFlags
75+ | IL of ilSource : string * result : Lazy<string * byte []>
76+
77+ member this.AssertNoErrorsOrWarnings () =
78+ match this with
79+ | TestCompilation.CSharp ( c, _) ->
80+ let diagnostics = c.GetDiagnostics ()
81+
82+ if not diagnostics.IsEmpty then
83+ NUnit.Framework.Assert.Fail ( " CSharp source diagnostics:\n " + ( diagnostics |> Seq.map ( fun x -> x.GetMessage () + " \n " ) |> Seq.reduce (+)))
84+
85+ | TestCompilation.IL (_, result) ->
86+ let errors , _ = result.Value
87+ if errors.Length > 0 then
88+ NUnit.Framework.Assert.Fail ( " IL source errors: " + errors)
89+
90+ member this.EmitAsFile ( outputPath : string ) =
91+ match this with
92+ | TestCompilation.CSharp ( c, _) ->
93+ let emitResult = c.Emit outputPath
94+ if not emitResult.Success then
95+ failwithf " Unable to emit C# compilation.\n %A " emitResult.Diagnostics
96+
97+ | TestCompilation.IL (_, result) ->
98+ let ( _ , data ) = result.Value
99+ File.WriteAllBytes ( outputPath, data)
100+
101+ type CSharpLanguageVersion =
102+ | CSharp8 = 0
103+
104+ [<AbstractClass; Sealed>]
105+ type CompilationUtil private () =
106+
107+ static member CreateCSharpCompilation ( source : string , lv : CSharpLanguageVersion , ? tf , ? additionalReferences , ? flags ) =
108+ let lv =
109+ match lv with
110+ | CSharpLanguageVersion.CSharp8 -> LanguageVersion.CSharp8
111+ | _ -> LanguageVersion.Default
112+
113+ let tf = defaultArg tf TargetFramework.NetStandard20
114+ let additionalReferences = defaultArg additionalReferences ImmutableArray.Empty
115+ let flags = defaultArg flags CSharpCompilationFlags.None
116+ let references = TargetFrameworkUtil.getReferences tf
117+ let c =
118+ CSharpCompilation.Create(
119+ Guid.NewGuid() .ToString (),
120+ [ CSharpSyntaxTree.ParseText ( source, CSharpParseOptions lv) ],
121+ references.As< MetadataReference>() .AddRange additionalReferences,
122+ CSharpCompilationOptions ( OutputKind.DynamicallyLinkedLibrary))
123+ Some ( TestCompilation.CSharp ( c, flags))
124+
125+ static member CreateILCompilation ( source : string ) =
126+ let compute =
127+ lazy
128+ let ilFilePath = Path.GetTempFileName ()
129+ let tmp = Path.GetTempFileName()
130+ let dllFilePath = Path.ChangeExtension ( tmp, " .dll" )
131+ try
132+ File.WriteAllText ( ilFilePath, source)
133+ let errors = ILChecker.reassembleIL ilFilePath dllFilePath
134+ try
135+ ( errors, File.ReadAllBytes dllFilePath)
136+ with
137+ | _ -> ( errors, [||])
138+ finally
139+ try File.Delete ilFilePath with | _ -> ()
140+ try File.Delete tmp with | _ -> ()
141+ try File.Delete dllFilePath with | _ -> ()
142+ Some ( TestCompilation.IL ( source, compute))
0 commit comments