-
Notifications
You must be signed in to change notification settings - Fork 851
Expand file tree
/
Copy pathScriptClosure.fs
More file actions
767 lines (617 loc) · 30.9 KB
/
ScriptClosure.fs
File metadata and controls
767 lines (617 loc) · 30.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
/// Compute the load closure of a set of script files
module internal FSharp.Compiler.ScriptClosure
open System
open System.Collections.Generic
open System.IO
open System.Text
open Internal.Utilities.Library
open Internal.Utilities.Library.Extras
open FSharp.Compiler
open FSharp.Compiler.AbstractIL.IL
open FSharp.Compiler.CompilerConfig
open FSharp.Compiler.CompilerDiagnostics
open FSharp.Compiler.CompilerImports
open FSharp.Compiler.DependencyManager
open FSharp.Compiler.Diagnostics
open FSharp.Compiler.DiagnosticsLogger
open FSharp.Compiler.IO
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.ParseAndCheckInputs
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text
open FSharp.Compiler.Text.Range
[<RequireQualifiedAccess>]
type LoadClosureInput =
{
FileName: string
SyntaxTree: ParsedInput option
ParseDiagnostics: PhasedDiagnostic list
MetaCommandDiagnostics: PhasedDiagnostic list
}
[<RequireQualifiedAccess>]
type LoadClosure =
{
/// The source files along with the ranges of the #load positions in each file.
SourceFiles: (string * range list) list
/// The resolved references along with the ranges of the #r positions in each file.
References: (string * AssemblyResolution list) list
/// The resolved package references along with the ranges of the #r positions in each file.
PackageReferences: (range * string list)[]
/// The raw package manager lines in the script
PackageManagerLines: Map<string, PackageManagerLine list>
/// Whether we're decided to use .NET Framework analysis for this script
UseDesktopFramework: bool
/// Was the SDK directory override given?
SdkDirOverride: string option
/// The list of references that were not resolved during load closure. These may still be extension references.
UnresolvedReferences: UnresolvedAssemblyReference list
/// The list of all sources in the closure with inputs when available
Inputs: LoadClosureInput list
/// The #load, including those that didn't resolve
OriginalLoadReferences: (range * string * string) list
/// Diagnostics seen while processing resolutions
ResolutionDiagnostics: PhasedDiagnostic list
/// Diagnostics seen while parsing root of closure
AllRootFileDiagnostics: PhasedDiagnostic list
/// Diagnostics seen while processing the compiler options implied root of closure
LoadClosureRootFileDiagnostics: PhasedDiagnostic list
}
[<RequireQualifiedAccess>]
type CodeContext =
| CompilationAndEvaluation // in fsi.exe
| Compilation // in fsc.exe
| Editing // in VS
module ScriptPreprocessClosure =
/// Represents an input to the closure finding process
type ClosureSource =
| ClosureSource of fileName: string * referenceRange: range * sourceText: ISourceText * Position option * parseRequired: bool
/// Represents an output of the closure finding process
type ClosureFile =
| ClosureFile of
fileName: string *
range: range *
parsedInput: ParsedInput option *
parseDiagnostics: PhasedDiagnostic list *
metaDiagnostics: PhasedDiagnostic list
type Observed() =
let seen = Dictionary<_, bool>()
member _.SetSeen check =
if not (seen.ContainsKey check) then
seen.Add(check, true)
member _.HaveSeen check = seen.ContainsKey check
/// Parse a script file (or any input file referenced by '#load')
let ParseScriptClosureInput
(
fileName: string,
sourceText: ISourceText,
tcConfig: TcConfig,
codeContext,
lexResourceManager: Lexhelp.LexResourceManager,
diagnosticsLogger: DiagnosticsLogger
) =
// fsc.exe -- COMPILED\!INTERACTIVE
// fsi.exe -- !COMPILED\INTERACTIVE
// Language service
// .fs -- EDITING + COMPILED\!INTERACTIVE
// .fsx -- EDITING + !COMPILED\INTERACTIVE
let defines =
match codeContext with
| CodeContext.CompilationAndEvaluation -> [ "INTERACTIVE" ]
| CodeContext.Compilation -> [ "COMPILED" ]
| CodeContext.Editing ->
"EDITING"
:: (if IsScript fileName then
[ "INTERACTIVE" ]
else
[ "COMPILED" ])
let tcConfigB = tcConfig.CloneToBuilder()
tcConfigB.conditionalDefines <- defines @ tcConfig.conditionalDefines
let tcConfig = TcConfig.Create(tcConfigB, false)
let lexbuf =
UnicodeLexing.SourceTextAsLexbuf(true, tcConfig.langVersion, tcConfig.strictIndentation, sourceText)
// The root compiland is last in the list of compilands.
let isLastCompiland = (IsScript fileName, tcConfig.target.IsExe)
ParseOneInputLexbuf(tcConfig, lexResourceManager, lexbuf, fileName, isLastCompiland, diagnosticsLogger)
/// Create a TcConfig for load closure starting from a single .fsx file
let CreateScriptTextTcConfig
(
legacyReferenceResolver,
defaultFSharpBinariesDir,
fileName: string,
codeContext,
useSimpleResolution,
useFsiAuxLib,
basicReferences,
applyCommandLineArgs,
assumeDotNetFramework,
useSdkRefs,
sdkDirOverride,
tryGetMetadataSnapshot,
reduceMemoryUsage
) =
let projectDir = !!Path.GetDirectoryName(fileName)
let isInteractive = (codeContext = CodeContext.CompilationAndEvaluation)
let isInvalidationSupported = (codeContext = CodeContext.Editing)
let rangeForErrors = mkFirstLineOfFile fileName
let tcConfigB =
TcConfigBuilder.CreateNew(
legacyReferenceResolver,
defaultFSharpBinariesDir,
reduceMemoryUsage,
projectDir,
isInteractive,
isInvalidationSupported,
CopyFSharpCoreFlag.No,
tryGetMetadataSnapshot,
sdkDirOverride,
rangeForErrors
)
let primaryAssembly =
if assumeDotNetFramework then
PrimaryAssembly.Mscorlib
else
PrimaryAssembly.System_Runtime
tcConfigB.SetPrimaryAssembly primaryAssembly
tcConfigB.SetUseSdkRefs useSdkRefs
applyCommandLineArgs tcConfigB
// Work out the references for the script in its location. This may produce diagnostics.
let scriptDefaultReferencesDiagnostics =
match basicReferences with
| None ->
let diagnosticsLogger = CapturingDiagnosticsLogger("ScriptDefaultReferences")
use _ = UseDiagnosticsLogger diagnosticsLogger
let references, useDotNetFramework =
tcConfigB.FxResolver.GetDefaultReferences useFsiAuxLib
// If the user requested .NET Core scripting but something went wrong and we reverted to
// .NET Framework scripting then we must adjust both the primaryAssembly and fxResolver
if useDotNetFramework <> assumeDotNetFramework then
let primaryAssembly =
if useDotNetFramework then
PrimaryAssembly.Mscorlib
else
PrimaryAssembly.System_Runtime
tcConfigB.SetPrimaryAssembly primaryAssembly
// Add script references
for reference in references do
tcConfigB.AddReferencedAssemblyByPath(range0, reference)
diagnosticsLogger.Diagnostics
| Some(rs, diagnostics) ->
for m, reference in rs do
tcConfigB.AddReferencedAssemblyByPath(m, reference)
diagnostics
tcConfigB.resolutionEnvironment <-
match codeContext with
| CodeContext.Editing -> LegacyResolutionEnvironment.EditingOrCompilation true
| CodeContext.Compilation -> LegacyResolutionEnvironment.EditingOrCompilation false
| CodeContext.CompilationAndEvaluation -> LegacyResolutionEnvironment.CompilationAndEvaluation
tcConfigB.implicitlyReferenceDotNetAssemblies <- false
tcConfigB.useSimpleResolution <- useSimpleResolution
// Indicates that there are some references not in basicReferencesForScriptLoadClosure which should
// be added conditionally once the relevant version of mscorlib.dll has been detected.
tcConfigB.implicitlyResolveAssemblies <- false
tcConfigB.SetUseSdkRefs useSdkRefs
TcConfig.Create(tcConfigB, validate = true), scriptDefaultReferencesDiagnostics
let ClosureSourceOfFilename (fileName, m, inputCodePage, parseRequired) =
try
let fileName = FileSystem.GetFullPathShim fileName
use stream = FileSystem.OpenFileForReadShim(fileName)
use reader =
match inputCodePage with
| None -> new StreamReader(stream, true)
| Some(n: int) -> new StreamReader(stream, Encoding.GetEncoding n)
let source = reader.ReadToEnd()
[ ClosureSource(fileName, m, SourceText.ofString source, None, parseRequired) ]
with RecoverableException exn ->
errorRecovery exn m
[]
let ApplyMetaCommandsFromInputToTcConfig (tcConfig: TcConfig, inp: ParsedInput, pathOfMetaCommandSource, dependencyProvider) =
let tcConfigB = tcConfig.CloneToBuilder()
let addReferenceDirective () (m, s, directive) =
tcConfigB.AddReferenceDirective(dependencyProvider, m, s, directive)
let addLoadedSource () (m, s) =
tcConfigB.AddLoadedSource(m, s, pathOfMetaCommandSource)
try
ProcessMetaCommandsFromInput (addReferenceDirective, addLoadedSource) (tcConfigB, inp, pathOfMetaCommandSource, ())
with ReportedError _ ->
// Recover by using whatever did end up in the tcConfig
()
try
TcConfig.Create(tcConfigB, validate = false)
with ReportedError _ ->
// Recover by using a default TcConfig.
let tcConfigB = tcConfig.CloneToBuilder()
TcConfig.Create(tcConfigB, validate = false)
let getDirective d =
match d with
| Directive.Resolution -> "r"
| Directive.Include -> "i"
let FindClosureFiles
(
mainFile,
closureSources,
origTcConfig: TcConfig,
codeContext,
lexResourceManager: Lexhelp.LexResourceManager,
dependencyProvider: DependencyProvider
) =
let mutable tcConfig = origTcConfig
let observedSources = Observed()
let loadScripts = HashSet<_>()
let packageReferences = Dictionary<range, string list>(HashIdentity.Structural)
// Resolve the packages
let rec resolveDependencyManagerSources scriptName (caret: Position option) =
let caretLine =
match caret with
| None -> Int32.MinValue
| Some pos -> pos.Line
let isEditorCursorInPackageLines (line: PackageManagerLine) =
caretLine >= line.Range.StartLine && caretLine <= line.Range.EndLine
[
if not (loadScripts.Contains scriptName) then
for kv in tcConfig.packageManagerLines do
let packageManagerKey, packageManagerLines = kv.Key, kv.Value
let packageManagerLines =
packageManagerLines |> List.filter (not << isEditorCursorInPackageLines)
match packageManagerLines with
| [] -> ()
| packageManagerLine :: _ ->
let m = packageManagerLine.Range
yield! processPackageManagerLines m packageManagerLines scriptName packageManagerKey
]
and reportError m =
ResolvingErrorReport(fun errorType err msg ->
let error = err, msg
match errorType with
| ErrorReportType.Warning -> warning (Error(error, m))
| ErrorReportType.Error -> errorR (Error(error, m)))
and processPackageManagerLines m packageManagerLines scriptName packageManagerKey =
[
match origTcConfig.packageManagerLines |> Map.tryFind packageManagerKey with
| Some oldDependencyManagerLines when oldDependencyManagerLines = packageManagerLines -> ()
| _ ->
let outputDir = tcConfig.outputDir |> Option.defaultValue ""
let managerOpt =
dependencyProvider.TryFindDependencyManagerByKey(
tcConfig.compilerToolPaths,
outputDir,
tcConfig.sdkDirOverride,
reportError m,
packageManagerKey
)
match managerOpt with
| Null ->
let err =
dependencyProvider.CreatePackageManagerUnknownError(
tcConfig.compilerToolPaths,
outputDir,
tcConfig.sdkDirOverride,
packageManagerKey,
reportError m
)
errorR (Error(err, m))
| NonNull dependencyManager ->
yield! resolvePackageManagerLines m packageManagerLines scriptName packageManagerKey dependencyManager
]
and resolvePackageManagerLines m packageManagerLines scriptName packageManagerKey dependencyManager =
[
let packageManagerTextLines =
packageManagerLines |> List.map (fun l -> getDirective l.Directive, l.Line)
let tfm, rid = tcConfig.FxResolver.GetTfmAndRid()
let result =
dependencyProvider.Resolve(
dependencyManager,
".fsx",
packageManagerTextLines,
reportError m,
tfm,
rid,
tcConfig.implicitIncludeDir,
mainFile,
scriptName
)
if result.Success then
// Resolution produced no errors
//Write outputs in F# Interactive and compiler
if codeContext <> CodeContext.Editing then
for line in result.StdOut do
Console.Out.WriteLine(line)
for line in result.StdError do
Console.Error.WriteLine(line)
packageReferences[m] <-
[
for script in result.SourceFiles do
yield! FileSystem.OpenFileForReadShim(script).ReadLines()
]
if not (Seq.isEmpty result.Roots) then
let tcConfigB = tcConfig.CloneToBuilder()
for folder in result.Roots do
tcConfigB.AddIncludePath(m, folder, "")
tcConfigB.packageManagerLines <-
PackageManagerLine.SetLinesAsProcessed packageManagerKey tcConfigB.packageManagerLines
tcConfig <- TcConfig.Create(tcConfigB, validate = false)
if not (Seq.isEmpty result.Resolutions) then
let tcConfigB = tcConfig.CloneToBuilder()
for resolution in result.Resolutions do
tcConfigB.AddReferencedAssemblyByPath(m, resolution)
tcConfig <- TcConfig.Create(tcConfigB, validate = false)
for script in result.SourceFiles do
use stream = FileSystem.OpenFileForReadShim(script)
let scriptText = stream.ReadAllText()
loadScripts.Add script |> ignore
let iSourceText = SourceText.ofString scriptText
yield! processClosureSource (ClosureSource(script, m, iSourceText, None, true))
else
// Send outputs via diagnostics
if (result.StdOut.Length > 0 || result.StdError.Length > 0) then
for line in Array.append result.StdOut result.StdError do
errorR (Error(FSComp.SR.packageManagerError line, m))
// Resolution produced errors update packagerManagerLines entries to note these failure
// failed resolutions will no longer be considered
let tcConfigB = tcConfig.CloneToBuilder()
tcConfigB.packageManagerLines <-
PackageManagerLine.RemoveUnprocessedLines packageManagerKey tcConfigB.packageManagerLines
tcConfig <- TcConfig.Create(tcConfigB, validate = false)
]
and processClosureSource (ClosureSource(fileName, m, sourceText, caret, parseRequired)) =
[
if not (observedSources.HaveSeen(fileName)) then
observedSources.SetSeen(fileName)
//printfn "visiting %s" fileName
if IsScript fileName || parseRequired then
let parseResult, parseDiagnostics =
let diagnosticsLogger = CapturingDiagnosticsLogger("FindClosureParse")
use _ = UseDiagnosticsLogger diagnosticsLogger
let result =
ParseScriptClosureInput(fileName, sourceText, tcConfig, codeContext, lexResourceManager, diagnosticsLogger)
result, diagnosticsLogger.Diagnostics
let diagnosticsLogger = CapturingDiagnosticsLogger("FindClosureMetaCommands")
use _ = UseDiagnosticsLogger diagnosticsLogger
let pathOfMetaCommandSource = !!Path.GetDirectoryName(fileName)
let preSources = tcConfig.GetAvailableLoadedSources()
let tcConfigResult =
ApplyMetaCommandsFromInputToTcConfig(tcConfig, parseResult, pathOfMetaCommandSource, dependencyProvider)
tcConfig <- tcConfigResult // We accumulate the tcConfig in order to collect assembly references
yield! resolveDependencyManagerSources fileName caret
let postSources = tcConfig.GetAvailableLoadedSources()
let sources =
if preSources.Length < postSources.Length then
postSources[preSources.Length ..]
else
[]
yield! resolveDependencyManagerSources fileName caret
for m, subFile in sources do
if IsScript subFile then
for subSource in ClosureSourceOfFilename(subFile, m, tcConfigResult.inputCodePage, false) do
yield! processClosureSource subSource
else
ClosureFile(subFile, m, None, [], [])
ClosureFile(fileName, m, Some parseResult, parseDiagnostics, diagnosticsLogger.Diagnostics)
else
// Don't traverse into .fs leafs.
printfn "yielding non-script source %s" fileName
ClosureFile(fileName, m, None, [], [])
]
let sources = closureSources |> List.collect processClosureSource
let packageReferences =
packageReferences |> Seq.map (fun kvp -> kvp.Key, kvp.Value) |> Seq.toArray
sources, tcConfig, packageReferences
/// Mark the last file as isLastCompiland.
let MarkLastCompiland (tcConfig: TcConfig, lastClosureFile) =
let (ClosureFile(fileName, m, lastParsedInput, parseDiagnostics, metaDiagnostics)) =
lastClosureFile
match lastParsedInput with
| Some(ParsedInput.ImplFile lastParsedImplFile) ->
let (ParsedImplFileInput(name, isScript, qualNameOfFile, hashDirectives, implFileFlags, _, trivia, identifiers)) =
lastParsedImplFile
let isLastCompiland = (true, tcConfig.target.IsExe)
let lastParsedImplFileR =
ParsedImplFileInput(name, isScript, qualNameOfFile, hashDirectives, implFileFlags, isLastCompiland, trivia, identifiers)
let lastClosureFileR =
ClosureFile(fileName, m, Some(ParsedInput.ImplFile lastParsedImplFileR), parseDiagnostics, metaDiagnostics)
lastClosureFileR
| _ -> lastClosureFile
/// Reduce the full directive closure into LoadClosure
let GetLoadClosure (rootFilename, closureFiles, tcConfig: TcConfig, codeContext, packageReferences, earlierDiagnostics) : LoadClosure =
// Mark the last file as isLastCompiland.
let closureFiles =
match List.tryFrontAndBack closureFiles with
| None -> closureFiles
| Some(rest, lastClosureFile) ->
let lastClosureFileR = MarkLastCompiland(tcConfig, lastClosureFile)
rest @ [ lastClosureFileR ]
// Get all source files.
let sourceFiles =
[ for ClosureFile(fileName, m, _, _, _) in closureFiles -> (fileName, m) ]
let sourceInputs =
[
for closureFile in closureFiles ->
let (ClosureFile(fileName, _, input, parseDiagnostics, metaDiagnostics)) =
closureFile
let closureInput: LoadClosureInput =
{
FileName = fileName
SyntaxTree = input
ParseDiagnostics = parseDiagnostics
MetaCommandDiagnostics = metaDiagnostics
}
closureInput
]
// Resolve all references.
let references, unresolvedReferences, resolutionDiagnostics =
let diagnosticsLogger = CapturingDiagnosticsLogger("GetLoadClosure")
use _ = UseDiagnosticsLogger diagnosticsLogger
let references, unresolvedReferences =
TcAssemblyResolutions.GetAssemblyResolutionInformation(tcConfig)
let references = references |> List.map (fun ar -> ar.resolvedPath, ar)
references, unresolvedReferences, diagnosticsLogger.Diagnostics
// Root errors and warnings - look at the last item in the closureFiles list
let loadClosureRootDiagnostics, allRootDiagnostics =
match List.rev closureFiles with
| ClosureFile(_, _, _, parseDiagnostics, metaDiagnostics) :: _ ->
(earlierDiagnostics @ metaDiagnostics @ resolutionDiagnostics),
(parseDiagnostics @ earlierDiagnostics @ metaDiagnostics @ resolutionDiagnostics)
| _ -> [], [] // When no file existed.
let isRootRange (diagnostic: PhasedDiagnostic) =
match diagnostic.Range with
| Some m ->
// Return true if the error was *not* from a #load-ed file.
let isArgParameterWhileNotEditing =
(codeContext <> CodeContext.Editing)
&& (equals m range0 || equals m rangeStartup || equals m rangeCmdArgs)
let isThisFileName =
(0 = String.Compare(rootFilename, m.FileName, StringComparison.OrdinalIgnoreCase))
isArgParameterWhileNotEditing || isThisFileName
| None -> true
// Filter out non-root errors and warnings
let allRootDiagnostics = allRootDiagnostics |> List.filter isRootRange
{
SourceFiles = List.groupBy fst sourceFiles |> List.map (map2Of2 (List.map snd))
References = List.groupBy fst references |> List.map (map2Of2 (List.map snd))
PackageReferences = packageReferences
PackageManagerLines = tcConfig.packageManagerLines
UseDesktopFramework = (tcConfig.primaryAssembly = PrimaryAssembly.Mscorlib)
SdkDirOverride = tcConfig.sdkDirOverride
UnresolvedReferences = unresolvedReferences
Inputs = sourceInputs
OriginalLoadReferences = tcConfig.loadedSources
ResolutionDiagnostics = resolutionDiagnostics
AllRootFileDiagnostics = allRootDiagnostics
LoadClosureRootFileDiagnostics = loadClosureRootDiagnostics
}
/// Given source text, find the full load closure. Used from service.fs, when editing a script file
let GetFullClosureOfScriptText
(
legacyReferenceResolver,
defaultFSharpBinariesDir,
fileName,
sourceText,
caret,
codeContext,
useSimpleResolution,
useFsiAuxLib,
useSdkRefs,
sdkDirOverride,
lexResourceManager: Lexhelp.LexResourceManager,
applyCommandLineArgs,
assumeDotNetFramework,
tryGetMetadataSnapshot,
reduceMemoryUsage,
dependencyProvider
) =
// Resolve the basic references such as FSharp.Core.dll first, before processing any #I directives in the script
//
// This is tries to mimic the action of running the script in F# Interactive - the initial context for scripting is created
// first, then #I and other directives are processed.
let references0, assumeDotNetFramework, scriptDefaultReferencesDiagnostics =
let tcConfig, scriptDefaultReferencesDiagnostics =
CreateScriptTextTcConfig(
legacyReferenceResolver,
defaultFSharpBinariesDir,
fileName,
codeContext,
useSimpleResolution,
useFsiAuxLib,
None,
applyCommandLineArgs,
assumeDotNetFramework,
useSdkRefs,
sdkDirOverride,
tryGetMetadataSnapshot,
reduceMemoryUsage
)
let resolutions0, _unresolvedReferences =
TcAssemblyResolutions.GetAssemblyResolutionInformation(tcConfig)
let references0 =
resolutions0
|> List.map (fun r -> r.originalReference.Range, r.resolvedPath)
|> Seq.distinct
|> List.ofSeq
references0, tcConfig.assumeDotNetFramework, scriptDefaultReferencesDiagnostics
let tcConfig, scriptDefaultReferencesDiagnostics =
CreateScriptTextTcConfig(
legacyReferenceResolver,
defaultFSharpBinariesDir,
fileName,
codeContext,
useSimpleResolution,
useFsiAuxLib,
Some(references0, scriptDefaultReferencesDiagnostics),
applyCommandLineArgs,
assumeDotNetFramework,
useSdkRefs,
sdkDirOverride,
tryGetMetadataSnapshot,
reduceMemoryUsage
)
let closureSources = [ ClosureSource(fileName, range0, sourceText, caret, true) ]
let closureFiles, tcConfig, packageReferences =
FindClosureFiles(fileName, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider)
GetLoadClosure(fileName, closureFiles, tcConfig, codeContext, packageReferences, scriptDefaultReferencesDiagnostics)
/// Given source file fileName, find the full load closure
/// Used from fsi.fs and fsc.fs, for #load and command line
let GetFullClosureOfScriptFiles
(tcConfig: TcConfig, files: (string * range) list, codeContext, lexResourceManager: Lexhelp.LexResourceManager, dependencyProvider)
=
let mainFile, _mainFileRange = List.last files
let closureSources =
files
|> List.collect (fun (fileName, m) -> ClosureSourceOfFilename(fileName, m, tcConfig.inputCodePage, true))
let closureFiles, tcConfig, packageReferences =
FindClosureFiles(mainFile, closureSources, tcConfig, codeContext, lexResourceManager, dependencyProvider)
GetLoadClosure(mainFile, closureFiles, tcConfig, codeContext, packageReferences, [])
type LoadClosure with
/// Analyze a script text and find the closure of its references.
/// Used from FCS, when editing a script file.
///
/// A temporary TcConfig is created along the way, is why this routine takes so many arguments. We want to be sure to use exactly the
/// same arguments as the rest of the application.
static member ComputeClosureOfScriptText
(
legacyReferenceResolver,
defaultFSharpBinariesDir,
fileName: string,
sourceText: ISourceText,
caret: Position option,
implicitDefines,
useSimpleResolution: bool,
useFsiAuxLib,
useSdkRefs,
sdkDir,
lexResourceManager: Lexhelp.LexResourceManager,
applyCompilerOptions,
assumeDotNetFramework,
tryGetMetadataSnapshot,
reduceMemoryUsage,
dependencyProvider
) =
use _ = UseBuildPhase BuildPhase.Parse
ScriptPreprocessClosure.GetFullClosureOfScriptText(
legacyReferenceResolver,
defaultFSharpBinariesDir,
fileName,
sourceText,
caret,
implicitDefines,
useSimpleResolution,
useFsiAuxLib,
useSdkRefs,
sdkDir,
lexResourceManager,
applyCompilerOptions,
assumeDotNetFramework,
tryGetMetadataSnapshot,
reduceMemoryUsage,
dependencyProvider
)
/// Analyze a set of script files and find the closure of their references.
static member ComputeClosureOfScriptFiles
(
tcConfig: TcConfig,
files: (string * range) list,
implicitDefines,
lexResourceManager: Lexhelp.LexResourceManager,
dependencyProvider
) =
use _ = UseBuildPhase BuildPhase.Parse
ScriptPreprocessClosure.GetFullClosureOfScriptFiles(tcConfig, files, implicitDefines, lexResourceManager, dependencyProvider)