diff --git a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
index dd96b7da59e..de6827d530a 100644
--- a/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
+++ b/src/fsharp/FSharp.Compiler.Service/FSharp.Compiler.Service.fsproj
@@ -826,6 +826,12 @@
Service/SemanticClassificationKey.fs
+
+ Service/FSharpDocument.fsi
+
+
+ Service/FSharpDocument.fs
+
Service/IncrementalBuild.fsi
diff --git a/src/fsharp/ParseAndCheckInputs.fs b/src/fsharp/ParseAndCheckInputs.fs
index ffe1bfe4a97..c0dc950da73 100644
--- a/src/fsharp/ParseAndCheckInputs.fs
+++ b/src/fsharp/ParseAndCheckInputs.fs
@@ -402,6 +402,22 @@ let checkInputFile (tcConfig: TcConfig) filename =
else
error(Error(FSComp.SR.buildInvalidSourceFileExtension(SanitizeFileName filename tcConfig.implicitIncludeDir), rangeStartup))
+let parseInputStreamAux (tcConfig: TcConfig, lexResourceManager, conditionalCompilationDefines, filename, isLastCompiland, errorLogger, retryLocked, stream: Stream) =
+ use reader = stream.GetReader(tcConfig.inputCodePage, retryLocked)
+
+ // Set up the LexBuffer for the file
+ let lexbuf = UnicodeLexing.StreamReaderAsLexbuf(not tcConfig.compilingFslib, tcConfig.langVersion.SupportsFeature, reader)
+
+ // Parse the file drawing tokens from the lexbuf
+ ParseOneInputLexbuf(tcConfig, lexResourceManager, conditionalCompilationDefines, lexbuf, filename, isLastCompiland, errorLogger)
+
+let parseInputSourceTextAux (tcConfig: TcConfig, lexResourceManager, conditionalCompilationDefines, filename, isLastCompiland, errorLogger, sourceText: ISourceText) =
+ // Set up the LexBuffer for the file
+ let lexbuf = UnicodeLexing.SourceTextAsLexbuf(not tcConfig.compilingFslib, tcConfig.langVersion.SupportsFeature, sourceText)
+
+ // Parse the file drawing tokens from the lexbuf
+ ParseOneInputLexbuf(tcConfig, lexResourceManager, conditionalCompilationDefines, lexbuf, filename, isLastCompiland, errorLogger)
+
let parseInputFileAux (tcConfig: TcConfig, lexResourceManager, conditionalCompilationDefines, filename, isLastCompiland, errorLogger, retryLocked) =
// Get a stream reader for the file
use fileStream = FileSystem.OpenFileForReadShim(filename)
@@ -422,6 +438,22 @@ let ParseOneInputFile (tcConfig: TcConfig, lexResourceManager, conditionalCompil
errorRecovery e rangeStartup
EmptyParsedInput(filename, isLastCompiland)
+/// Parse an input from stream
+let ParseOneInputStream (tcConfig: TcConfig, lexResourceManager, conditionalCompilationDefines, filename, isLastCompiland, errorLogger, retryLocked, stream: Stream) =
+ try
+ parseInputStreamAux(tcConfig, lexResourceManager, conditionalCompilationDefines, filename, isLastCompiland, errorLogger, retryLocked, stream)
+ with e ->
+ errorRecovery e rangeStartup
+ EmptyParsedInput(filename, isLastCompiland)
+
+/// Parse an input from source text
+let ParseOneInputSourceText (tcConfig: TcConfig, lexResourceManager, conditionalCompilationDefines, filename, isLastCompiland, errorLogger, sourceText: ISourceText) =
+ try
+ parseInputSourceTextAux(tcConfig, lexResourceManager, conditionalCompilationDefines, filename, isLastCompiland, errorLogger, sourceText)
+ with e ->
+ errorRecovery e rangeStartup
+ EmptyParsedInput(filename, isLastCompiland)
+
/// Parse multiple input files from disk
let ParseInputFiles (tcConfig: TcConfig, lexResourceManager, conditionalCompilationDefines, sourceFiles, errorLogger: ErrorLogger, exiter: Exiter, createErrorLogger: (Exiter -> CapturingErrorLogger), retryLocked) =
try
diff --git a/src/fsharp/ParseAndCheckInputs.fsi b/src/fsharp/ParseAndCheckInputs.fsi
index 207d41c878b..ba995a5a988 100644
--- a/src/fsharp/ParseAndCheckInputs.fsi
+++ b/src/fsharp/ParseAndCheckInputs.fsi
@@ -3,6 +3,7 @@
/// Contains logic to coordinate the parsing and checking of one or a group of files
module internal FSharp.Compiler.ParseAndCheckInputs
+open System.IO
open Internal.Utilities.Library
open FSharp.Compiler.CheckExpressions
open FSharp.Compiler.CheckDeclarations
@@ -49,6 +50,12 @@ val ApplyNoWarnsToTcConfig: TcConfig * ParsedInput * string -> TcConfig
/// Parse one input file
val ParseOneInputFile: TcConfig * Lexhelp.LexResourceManager * conditionalCompilationDefines: string list * string * isLastCompiland: (bool * bool) * ErrorLogger * retryLocked: bool -> ParsedInput
+/// Parse one input stream
+val ParseOneInputStream: TcConfig * Lexhelp.LexResourceManager * conditionalCompilationDefines: string list * string * isLastCompiland: (bool * bool) * ErrorLogger * retryLocked: bool * stream: Stream -> ParsedInput
+
+/// Parse one input source text
+val ParseOneInputSourceText: TcConfig * Lexhelp.LexResourceManager * conditionalCompilationDefines: string list * string * isLastCompiland: (bool * bool) * ErrorLogger * sourceText: ISourceText -> ParsedInput
+
/// Parse multiple input files from disk
val ParseInputFiles: TcConfig * Lexhelp.LexResourceManager * conditionalCompilationDefines: string list * string list * ErrorLogger * Exiter * createErrorLogger: (Exiter -> CapturingErrorLogger) * retryLocked: bool -> (ParsedInput * string) list
diff --git a/src/fsharp/absil/ilread.fs b/src/fsharp/absil/ilread.fs
index b89cccd82c3..37af98f0014 100644
--- a/src/fsharp/absil/ilread.fs
+++ b/src/fsharp/absil/ilread.fs
@@ -3913,7 +3913,6 @@ let createByteFileChunk opts fileName chunk =
let getBinaryFile fileName useMemoryMappedFile =
let stream = FileSystem.OpenFileForReadShim(fileName, useMemoryMappedFile = useMemoryMappedFile)
- let byteMem = stream.AsByteMemory()
let safeHolder =
{ new obj() with
@@ -3927,7 +3926,7 @@ let getBinaryFile fileName useMemoryMappedFile =
stats.memoryMapFileOpenedCount <- stats.memoryMapFileOpenedCount + 1
- safeHolder, RawMemoryFile(fileName, safeHolder, byteMem) :> BinaryFile
+ safeHolder, RawMemoryFile(fileName, safeHolder, stream.AsByteMemory()) :> BinaryFile
let OpenILModuleReaderFromBytes fileName assemblyContents options =
let pefile = ByteFile(fileName, assemblyContents) :> BinaryFile
diff --git a/src/fsharp/service/FSharpCheckerResults.fsi b/src/fsharp/service/FSharpCheckerResults.fsi
index 1858e4b24db..377166d3717 100644
--- a/src/fsharp/service/FSharpCheckerResults.fsi
+++ b/src/fsharp/service/FSharpCheckerResults.fsi
@@ -50,7 +50,7 @@ type public FSharpProjectOptions =
/// This is the unique identifier for the project, it is case sensitive. If it's None, will key off of ProjectFileName in our caching.
ProjectId: string option
- /// The files in the project
+ /// The source files in the project
SourceFiles: string[]
/// Additional command line argument options for the project. These can include additional files and references.
diff --git a/src/fsharp/service/FSharpDocument.fs b/src/fsharp/service/FSharpDocument.fs
new file mode 100644
index 00000000000..330546324b0
--- /dev/null
+++ b/src/fsharp/service/FSharpDocument.fs
@@ -0,0 +1,135 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace FSharp.Compiler.CodeAnalysis
+
+open System
+open System.Collections.Generic
+open System.Collections.Immutable
+open System.IO
+open System.IO.MemoryMappedFiles
+open System.Xml
+open System.Runtime.InteropServices
+open System.Threading
+open Internal.Utilities.Library
+open Internal.Utilities.Library.Extras
+open FSharp.Compiler
+open FSharp.Compiler.AbstractIL
+open FSharp.Compiler.AbstractIL.IL
+open FSharp.Compiler.AbstractIL.ILBinaryReader
+open FSharp.Compiler.CheckExpressions
+open FSharp.Compiler.CheckDeclarations
+open FSharp.Compiler.CompilerConfig
+open FSharp.Compiler.CompilerDiagnostics
+open FSharp.Compiler.CompilerGlobalState
+open FSharp.Compiler.CompilerImports
+open FSharp.Compiler.CompilerOptions
+open FSharp.Compiler.CreateILModule
+open FSharp.Compiler.DependencyManager
+open FSharp.Compiler.Diagnostics
+open FSharp.Compiler.EditorServices
+open FSharp.Compiler.ErrorLogger
+open FSharp.Compiler.IO
+open FSharp.Compiler.CodeAnalysis
+open FSharp.Compiler.NameResolution
+open FSharp.Compiler.ParseAndCheckInputs
+open FSharp.Compiler.ScriptClosure
+open FSharp.Compiler.Syntax
+open FSharp.Compiler.TcGlobals
+open FSharp.Compiler.Text
+open FSharp.Compiler.Text.Range
+open FSharp.Compiler.Xml
+open FSharp.Compiler.TypedTree
+open FSharp.Compiler.TypedTreeOps
+
+[]
+type DocumentText =
+ | OnDisk
+ | Stream of Stream
+ | SourceText of ISourceText
+
+ interface IDisposable with
+
+ member this.Dispose() =
+ match this with
+ | Stream stream -> stream.Dispose()
+ | _ -> ()
+
+[]
+type FSharpDocument internal () =
+
+ abstract FilePath : string
+
+ abstract TimeStamp : DateTime
+
+ abstract IsOpen : bool
+
+ abstract GetText : unit -> DocumentText
+
+type private FSharpDocumentMemoryMappedFile(filePath: string, timeStamp: DateTime, isOpen, openStream: unit -> Stream) =
+ inherit FSharpDocument()
+
+ override _.FilePath = filePath
+
+ override _.TimeStamp = timeStamp
+
+ override _.IsOpen = isOpen
+
+ override _.GetText() =
+ openStream () |> DocumentText.Stream
+
+type private FSharpDocumentByteArray(filePath: string, timeStamp: DateTime, isOpen, bytes: byte[]) =
+ inherit FSharpDocument()
+
+ override _.FilePath = filePath
+
+ override _.TimeStamp = timeStamp
+
+ override _.IsOpen = isOpen
+
+ override _.GetText() =
+ DocumentText.Stream(new MemoryStream(bytes, 0, bytes.Length, false) :> Stream)
+
+type private FSharpDocumentFromFile(filePath: string) =
+ inherit FSharpDocument()
+
+ override _.FilePath = filePath
+
+ override _.TimeStamp = FileSystem.GetLastWriteTimeShim(filePath)
+
+ override _.IsOpen = false
+
+ override _.GetText() = DocumentText.OnDisk
+
+type private FSharpDocumentCustom(filePath: string, isOpen, getTimeStamp, getSourceText) =
+ inherit FSharpDocument()
+
+ override _.FilePath = filePath
+
+ override _.TimeStamp = getTimeStamp()
+
+ override _.IsOpen = isOpen
+
+ override _.GetText() =
+ DocumentText.SourceText(getSourceText())
+
+type FSharpDocument with
+
+ static member Create(filePath, isOpen, getTimeStamp, getSourceText) =
+ FSharpDocumentCustom(filePath, isOpen, getTimeStamp, getSourceText) :> FSharpDocument
+
+ static member CreateFromFile(filePath: string) =
+ FSharpDocumentFromFile(filePath) :> FSharpDocument
+
+ static member CreateCopyFromFile(filePath: string, isOpen) =
+ let timeStamp = FileSystem.GetLastWriteTimeShim(filePath)
+
+ // We want to use mmaped documents only when
+ // not running on mono, since its MemoryMappedFile implementation throws when "mapName" is not provided (is null), (see: https://github.com/mono/mono/issues/10245)
+ if runningOnMono then
+ let bytes = FileSystem.OpenFileForReadShim(filePath, useMemoryMappedFile = false).ReadAllBytes()
+ FSharpDocumentByteArray(filePath, timeStamp, isOpen, bytes) :> FSharpDocument
+ else
+ let openStream = fun () ->
+ FileSystem.OpenFileForReadShim(filePath, useMemoryMappedFile = true, shouldShadowCopy = true)
+ FSharpDocumentMemoryMappedFile(filePath, timeStamp, isOpen, openStream) :> FSharpDocument
+
diff --git a/src/fsharp/service/FSharpDocument.fsi b/src/fsharp/service/FSharpDocument.fsi
new file mode 100644
index 00000000000..42dfb672556
--- /dev/null
+++ b/src/fsharp/service/FSharpDocument.fsi
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
+
+namespace FSharp.Compiler.CodeAnalysis
+
+open System
+open System.IO
+open FSharp.Compiler.Text
+
+[]
+type internal DocumentText =
+ | OnDisk
+ | Stream of Stream
+ | SourceText of ISourceText
+
+ interface IDisposable
+
+[]
+type FSharpDocument =
+
+ /// The file path of the document.
+ abstract FilePath : string
+
+ /// The timestamp of the document.
+ abstract TimeStamp : DateTime
+
+ /// Is the document open in an editor?
+ /// This is used to allow the background build to provide rich information on the document.
+ abstract IsOpen : bool
+
+ abstract internal GetText : unit -> DocumentText
+
+ static member internal CreateFromFile : filePath: string -> FSharpDocument
+
+ static member CreateCopyFromFile : filePath: string * isOpen: bool -> FSharpDocument
+
+ static member Create : filePath: string * isOpen: bool * getTimeStamp: (unit -> DateTime) * getSourceText: (unit -> ISourceText) -> FSharpDocument
\ No newline at end of file
diff --git a/src/fsharp/service/IncrementalBuild.fs b/src/fsharp/service/IncrementalBuild.fs
index ddcfefd2a5a..d99c695f06f 100644
--- a/src/fsharp/service/IncrementalBuild.fs
+++ b/src/fsharp/service/IncrementalBuild.fs
@@ -98,9 +98,10 @@ module IncrementalBuildSyntaxTree =
/// Information needed to lazily parse a file to get a ParsedInput. Internally uses a weak cache.
[]
- type SyntaxTree (tcConfig: TcConfig, fileParsed: Event, lexResourceManager, sourceRange: range, filename: string, isLastCompiland) =
+ type SyntaxTree (tcConfig: TcConfig, fileParsed: Event, lexResourceManager, sourceRange: range, doc: FSharpDocument, isLastCompiland) =
let mutable weakCache: WeakReference<_> option = None
+ let filename = doc.FilePath
let parse(sigNameOpt: QualifiedNameOfFile option) =
let errorLogger = CompilationErrorLogger("Parse", tcConfig.errorSeverityOptions)
@@ -125,7 +126,14 @@ module IncrementalBuildSyntaxTree =
)
)
else
- ParseOneInputFile(tcConfig, lexResourceManager, [], filename, isLastCompiland, errorLogger, (*retryLocked*)true)
+ use text = doc.GetText()
+ match text with
+ | DocumentText.Stream(stream) ->
+ ParseOneInputStream(tcConfig, lexResourceManager, [], filename, isLastCompiland, errorLogger, (*retryLocked*)false, stream)
+ | DocumentText.SourceText(sourceText) ->
+ ParseOneInputSourceText(tcConfig, lexResourceManager, [], filename, isLastCompiland, errorLogger, sourceText)
+ | DocumentText.OnDisk ->
+ ParseOneInputFile(tcConfig, lexResourceManager, [], filename, isLastCompiland, errorLogger, (*retryLocked*)true)
fileParsed.Trigger filename
@@ -149,10 +157,12 @@ module IncrementalBuildSyntaxTree =
| _ -> parse sigNameOpt
member _.Invalidate() =
- SyntaxTree(tcConfig, fileParsed, lexResourceManager, sourceRange, filename, isLastCompiland)
+ SyntaxTree(tcConfig, fileParsed, lexResourceManager, sourceRange, doc, isLastCompiland)
member _.FileName = filename
+ member _.Document = doc
+
/// Accumulated results of type checking. The minimum amount of state in order to continue type-checking following files.
[]
type TcInfo =
@@ -255,6 +265,10 @@ type BoundModel private (tcConfig: TcConfig,
prevTcInfo: TcInfo,
syntaxTreeOpt: SyntaxTree option,
tcInfoStateOpt: TcInfoState option) as this =
+ let isDocOpen =
+ match syntaxTreeOpt with
+ | Some syntaxTree -> syntaxTree.Document.IsOpen
+ | _ -> false
let tcInfoNode =
match tcInfoStateOpt with
@@ -269,7 +283,7 @@ type BoundModel private (tcConfig: TcConfig,
let partialGraphNode =
GraphNode(node {
- if enablePartialTypeChecking then
+ if enablePartialTypeChecking && not isDocOpen then
// Optimization so we have less of a chance to duplicate work.
if fullGraphNode.IsComputing then
let! tcInfo, _ = fullGraphNode.GetOrComputeValue()
@@ -310,14 +324,10 @@ type BoundModel private (tcConfig: TcConfig,
| _ ->
None
- /// If partial type-checking is enabled,
- /// this will create a new bound-model that will only have the partial state if the
+ /// This will create a new bound-model that will only have the partial state if the
/// the current bound-model has the full state.
member this.ClearTcInfoExtras() =
- let hasSig = this.BackingSignature.IsSome
-
- // If partial checking is enabled and we have a backing sig file, then use the partial state. The partial state contains the sig state.
- if tcInfoNode.HasFull && enablePartialTypeChecking && hasSig then
+ if tcInfoNode.HasFull then
// Always invalidate the syntax tree cache.
let newSyntaxTreeOpt =
syntaxTreeOpt
@@ -539,8 +549,8 @@ type BoundModel private (tcConfig: TcConfig,
{
/// Only keep the typed interface files when doing a "full" build for fsc.exe, otherwise just throw them away
latestImplFile = if keepAssemblyContents then implFile else None
- tcResolutions = (if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty)
- tcSymbolUses = (if keepAllBackgroundSymbolUses then sink.GetSymbolUses() else TcSymbolUses.Empty)
+ tcResolutions = (if keepAllBackgroundResolutions || syntaxTree.Document.IsOpen then sink.GetResolutions() else TcResolutions.Empty)
+ tcSymbolUses = (if keepAllBackgroundSymbolUses || syntaxTree.Document.IsOpen then sink.GetSymbolUses() else TcSymbolUses.Empty)
tcOpenDeclarations = sink.GetOpenDeclarations()
itemKeyStore = itemKeyStore
semanticClassificationKeyStore = semanticClassification
@@ -705,52 +715,48 @@ type IncrementalBuilderState =
{
// stampedFileNames represent the real stamps of the files.
// logicalStampedFileNames represent the stamps of the files that are used to calculate the project's logical timestamp.
+ documents: ImmutableArray<(range * FSharpDocument * (bool * bool))>
stampedFileNames: ImmutableArray
logicalStampedFileNames: ImmutableArray
stampedReferencedAssemblies: ImmutableArray
- initialBoundModel: GraphNode
boundModels: ImmutableArray>
finalizedBoundModel: GraphNode<((ILAssemblyRef * IRawFSharpAssemblyData option * TypedImplFile list option * BoundModel) * DateTime)>
}
-/// Manages an incremental build graph for the build of a single F# project
-type IncrementalBuilder(
- initialBoundModel: BoundModel,
- tcGlobals,
- nonFrameworkAssemblyInputs,
- tcConfig: TcConfig,
- outfile,
- assemblyName,
- lexResourceManager,
- sourceFiles,
- enablePartialTypeChecking,
- beforeFileChecked: Event,
- fileChecked: Event,
+type IncrementalBuilderMainState =
+ {
+ mutable isImportsInvalidated: bool
+ initialBoundModel: BoundModel
+ initialBoundModelNode: GraphNode
+ tcGlobals: TcGlobals
+ nonFrameworkAssemblyInputs: (Choice * (TimeStampCache -> DateTime)) list
+ tcConfig: TcConfig
+ outfile: string
+ assemblyName: string
+ lexResourceManager: Lexhelp.LexResourceManager
+ sourceFiles: ImmutableArray<(range * string * (bool * bool))>
+ enablePartialTypeChecking: bool
+ allDependencies: string []
+ beforeFileChecked: Event
+ fileChecked: Event
+ fileParsed: Event
+ projectChecked: Event
#if !NO_EXTENSIONTYPING
- importsInvalidatedByTypeProvider: Event,
+ importsInvalidatedByTypeProvider: Event
#endif
- allDependencies) =
-
- let fileParsed = new Event()
- let projectChecked = new Event()
-
- let defaultTimeStamp = DateTime.UtcNow
-
- let mutable isImportsInvalidated = false
+ }
-#if !NO_EXTENSIONTYPING
- do importsInvalidatedByTypeProvider.Publish.Add(fun () -> isImportsInvalidated <- true)
-#endif
+/// Manages an incremental build graph for the build of a single F# project
+type IncrementalBuilder(mainState: IncrementalBuilderMainState, state: IncrementalBuilderState) =
- //----------------------------------------------------
- // START OF BUILD TASK FUNCTIONS
+ static let defaultTimeStamp = DateTime.UtcNow
/// Get the timestamp of the given file name.
- let StampFileNameTask (cache: TimeStampCache) (_m: range, filename: string, _isLastCompiland) =
- cache.GetFileTimeStamp filename
+ static let StampFileNameTask (_m: range, doc: FSharpDocument, _isLastCompiland) =
+ doc.TimeStamp
/// Timestamps of referenced assemblies are taken from the file's timestamp.
- let StampReferencedAssemblyTask (cache: TimeStampCache) (_ref, timeStamper) =
+ static let StampReferencedAssemblyTask (cache: TimeStampCache) (_ref, timeStamper) =
timeStamper cache
// Link all the assemblies together and produce the input typecheck accumulator
@@ -848,7 +854,7 @@ type IncrementalBuilder(
None) }
/// Type check all files eagerly.
- let TypeCheckTask partialCheck (prevBoundModel: BoundModel) syntaxTree: NodeCode =
+ static let TypeCheckTask partialCheck (prevBoundModel: BoundModel) syntaxTree: NodeCode =
node {
let! tcInfo = prevBoundModel.GetOrComputeTcInfo()
let boundModel = prevBoundModel.Next(syntaxTree, tcInfo)
@@ -866,15 +872,15 @@ type IncrementalBuilder(
}
/// Finish up the typechecking to produce outputs for the rest of the compilation process
- let FinalizeTypeCheckTask (boundModels: ImmutableArray) =
+ static let FinalizeTypeCheckTask mainState (boundModels: ImmutableArray) =
node {
- let errorLogger = CompilationErrorLogger("FinalizeTypeCheckTask", tcConfig.errorSeverityOptions)
+ let errorLogger = CompilationErrorLogger("FinalizeTypeCheckTask", mainState.tcConfig.errorSeverityOptions)
use _ = new CompilationGlobalsScope(errorLogger, BuildPhase.TypeCheck)
let! results =
boundModels
|> Seq.map (fun boundModel -> node {
- if enablePartialTypeChecking then
+ if mainState.enablePartialTypeChecking then
let! tcInfo = boundModel.GetOrComputeTcInfo()
return tcInfo, None
else
@@ -911,22 +917,22 @@ type IncrementalBuilder(
let ilAssemRef =
let publicKey =
try
- let signingInfo = ValidateKeySigningAttributes (tcConfig, tcGlobals, topAttrs)
+ let signingInfo = ValidateKeySigningAttributes (mainState.tcConfig, mainState.tcGlobals, topAttrs)
match GetStrongNameSigner signingInfo with
| None -> None
| Some s -> Some (PublicKey.KeyAsToken(s.PublicKey))
with e ->
errorRecoveryNoRange e
None
- let locale = TryFindFSharpStringAttribute tcGlobals (tcGlobals.FindSysAttrib "System.Reflection.AssemblyCultureAttribute") topAttrs.assemblyAttrs
+ let locale = TryFindFSharpStringAttribute mainState.tcGlobals (mainState.tcGlobals.FindSysAttrib "System.Reflection.AssemblyCultureAttribute") topAttrs.assemblyAttrs
let assemVerFromAttrib =
- TryFindFSharpStringAttribute tcGlobals (tcGlobals.FindSysAttrib "System.Reflection.AssemblyVersionAttribute") topAttrs.assemblyAttrs
+ TryFindFSharpStringAttribute mainState.tcGlobals (mainState.tcGlobals.FindSysAttrib "System.Reflection.AssemblyVersionAttribute") topAttrs.assemblyAttrs
|> Option.bind (fun v -> try Some (parseILVersion v) with _ -> None)
let ver =
match assemVerFromAttrib with
- | None -> tcConfig.version.GetVersionInfo(tcConfig.implicitIncludeDir)
+ | None -> mainState.tcConfig.version.GetVersionInfo(mainState.tcConfig.implicitIncludeDir)
| Some v -> v
- ILAssemblyRef.Create(assemblyName, None, publicKey, false, Some ver, locale)
+ ILAssemblyRef.Create(mainState.assemblyName, None, publicKey, false, Some ver, locale)
let tcAssemblyDataOpt =
try
@@ -940,46 +946,36 @@ type IncrementalBuilder(
if tcState.CreatesGeneratedProvidedTypes || hasTypeProviderAssemblyAttrib then
None
else
- Some (RawFSharpAssemblyDataBackedByLanguageService (tcConfig, tcGlobals, generatedCcu, outfile, topAttrs, assemblyName, ilAssemRef) :> IRawFSharpAssemblyData)
+ Some (RawFSharpAssemblyDataBackedByLanguageService (mainState.tcConfig, mainState.tcGlobals, generatedCcu, mainState.outfile, topAttrs, mainState.assemblyName, ilAssemRef) :> IRawFSharpAssemblyData)
with e ->
errorRecoveryNoRange e
None
ilAssemRef, tcAssemblyDataOpt, Some tcAssemblyExpr
with e ->
errorRecoveryNoRange e
- mkSimpleAssemblyRef assemblyName, None, None
+ mkSimpleAssemblyRef mainState.assemblyName, None, None
let diagnostics = errorLogger.GetDiagnostics() :: finalInfo.tcErrorsRev
let! finalBoundModelWithErrors = finalBoundModel.Finish(diagnostics, Some topAttrs)
return ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt, finalBoundModelWithErrors
}
- // END OF BUILD TASK FUNCTIONS
- // ---------------------------------------------------------------------------------------------
+ static let GetSyntaxTree (mainState: IncrementalBuilderMainState) (sourceRange: range, doc: FSharpDocument, isLastCompiland) =
+ SyntaxTree(mainState.tcConfig, mainState.fileParsed, mainState.lexResourceManager, sourceRange, doc, isLastCompiland)
- // ---------------------------------------------------------------------------------------------
- // START OF BUILD DESCRIPTION
-
- let GetSyntaxTree (sourceRange: range, filename: string, isLastCompiland) =
- SyntaxTree(tcConfig, fileParsed, lexResourceManager, sourceRange, filename, isLastCompiland)
-
- // Inputs
- let fileNames = sourceFiles |> Array.ofList // TODO: This should be an immutable array.
- let referencedAssemblies = nonFrameworkAssemblyInputs |> Array.ofList // TODO: This should be an immutable array.
-
- let createBoundModelGraphNode initialBoundModel (boundModels: ImmutableArray>.Builder) i =
- let fileInfo = fileNames.[i]
+ static let createBoundModelGraphNode mainState (documents: ImmutableArray<_>) (boundModels: ImmutableArray>.Builder) i =
+ let fileInfo = documents.[i]
let prevBoundModelGraphNode =
match i with
- | 0 (* first file *) -> initialBoundModel
+ | 0 (* first file *) -> mainState.initialBoundModelNode
| _ -> boundModels.[i - 1]
- let syntaxTree = GetSyntaxTree fileInfo
+ let syntaxTree = GetSyntaxTree mainState fileInfo
GraphNode(node {
let! prevBoundModel = prevBoundModelGraphNode.GetOrComputeValue()
- return! TypeCheckTask enablePartialTypeChecking prevBoundModel syntaxTree
+ return! TypeCheckTask (mainState.enablePartialTypeChecking && not syntaxTree.Document.IsOpen) prevBoundModel syntaxTree
})
- let rec createFinalizeBoundModelGraphNode (boundModels: ImmutableArray>.Builder) =
+ static let rec createFinalizeBoundModelGraphNode mainState (boundModels: ImmutableArray>.Builder) =
GraphNode(node {
// Compute last bound model then get all the evaluated models.
let! _ = boundModels.[boundModels.Count - 1].GetOrComputeValue()
@@ -988,63 +984,94 @@ type IncrementalBuilder(
|> Seq.map (fun x -> x.TryPeekValue().Value)
|> ImmutableArray.CreateRange
- let! result = FinalizeTypeCheckTask boundModels
+ let! result = FinalizeTypeCheckTask mainState boundModels
let result = (result, DateTime.UtcNow)
return result
})
- and computeStampedFileName (state: IncrementalBuilderState) (cache: TimeStampCache) slot fileInfo =
+ and computeStampedFileName mainState (state: IncrementalBuilderState) slot fileInfo =
let currentStamp = state.stampedFileNames.[slot]
- let stamp = StampFileNameTask cache fileInfo
+ let stamp = StampFileNameTask fileInfo
if currentStamp <> stamp then
+ let boundModels = state.boundModels.ToBuilder()
+ let newDocuments = state.documents.RemoveAt(slot).Insert(slot, fileInfo)
match state.boundModels.[slot].TryPeekValue() with
// This prevents an implementation file that has a backing signature file from invalidating the rest of the build.
- | ValueSome(boundModel) when enablePartialTypeChecking && boundModel.BackingSignature.IsSome ->
- let newBoundModel = boundModel.ClearTcInfoExtras()
+ | ValueSome(boundModel) when mainState.enablePartialTypeChecking && boundModel.BackingSignature.IsSome ->
+ let newBoundModelNode =
+ match fileInfo with
+ | _, doc, _ when doc.IsOpen ->
+ createBoundModelGraphNode mainState newDocuments boundModels slot
+ | _ ->
+ let newBoundModel = boundModel.ClearTcInfoExtras()
+ GraphNode(node { return newBoundModel })
{ state with
- boundModels = state.boundModels.RemoveAt(slot).Insert(slot, GraphNode(node { return newBoundModel }))
- stampedFileNames = state.stampedFileNames.SetItem(slot, StampFileNameTask cache fileInfo)
+ documents = newDocuments
+ boundModels = state.boundModels.RemoveAt(slot).Insert(slot, newBoundModelNode)
+ stampedFileNames = state.stampedFileNames.SetItem(slot, stamp)
}
| _ ->
let stampedFileNames = state.stampedFileNames.ToBuilder()
let logicalStampedFileNames = state.logicalStampedFileNames.ToBuilder()
- let boundModels = state.boundModels.ToBuilder()
// Invalidate the file and all files below it.
for j = 0 to stampedFileNames.Count - slot - 1 do
- let stamp = StampFileNameTask cache fileNames.[slot + j]
+ let stamp = StampFileNameTask newDocuments.[slot + j]
stampedFileNames.[slot + j] <- stamp
logicalStampedFileNames.[slot + j] <- stamp
- boundModels.[slot + j] <- createBoundModelGraphNode state.initialBoundModel boundModels (slot + j)
+ boundModels.[slot + j] <- createBoundModelGraphNode mainState newDocuments boundModels (slot + j)
{ state with
// Something changed, the finalized view of the project must be invalidated.
- finalizedBoundModel = createFinalizeBoundModelGraphNode boundModels
+ finalizedBoundModel = createFinalizeBoundModelGraphNode mainState boundModels
+ documents = newDocuments
stampedFileNames = stampedFileNames.ToImmutable()
logicalStampedFileNames = logicalStampedFileNames.ToImmutable()
boundModels = boundModels.ToImmutable()
}
else
- state
+ let _, doc, _ = fileInfo
+ let _, currentDoc, _ = state.documents.[slot]
+ if currentDoc.IsOpen && not doc.IsOpen then
+ let state =
+ { state with
+ documents = state.documents.RemoveAt(slot).Insert(slot, fileInfo)
+ }
+ let currentBoundModel = state.boundModels.[slot]
+ match currentBoundModel.TryPeekValue() with
+ | ValueSome currentBoundModel ->
+ let boundModel = currentBoundModel.ClearTcInfoExtras()
+ { state with
+ boundModels = state.boundModels.RemoveAt(slot).Insert(slot, GraphNode(node { return boundModel }))
+ }
+ | _ ->
+ state
+ elif not currentDoc.IsOpen && doc.IsOpen then
+ { state with
+ documents = state.documents.RemoveAt(slot).Insert(slot, fileInfo)
+ }
+ else
+ state
- and computeStampedFileNames state (cache: TimeStampCache) =
+ and computeStampedFileNames mainState state =
let mutable i = 0
- (state, fileNames)
- ||> Array.fold (fun state fileInfo ->
- let newState = computeStampedFileName state cache i fileInfo
+ (state, state.documents)
+ ||> Seq.fold (fun state fileInfo ->
+ let newState = computeStampedFileName mainState state i fileInfo
i <- i + 1
newState
)
- and computeStampedReferencedAssemblies state canTriggerInvalidation (cache: TimeStampCache) =
+ and computeStampedReferencedAssemblies (mainState: IncrementalBuilderMainState) state canTriggerInvalidation =
+ let cache = TimeStampCache(defaultTimeStamp)
let stampedReferencedAssemblies = state.stampedReferencedAssemblies.ToBuilder()
let mutable referencesUpdated = false
- referencedAssemblies
- |> Array.iteri (fun i asmInfo ->
+ mainState.nonFrameworkAssemblyInputs
+ |> List.iteri (fun i asmInfo ->
let currentStamp = state.stampedReferencedAssemblies.[i]
let stamp = StampReferencedAssemblyTask cache asmInfo
@@ -1056,15 +1083,15 @@ type IncrementalBuilder(
if referencesUpdated then
// Build is invalidated. The build must be rebuilt with the newly updated references.
- if not isImportsInvalidated && canTriggerInvalidation then
- isImportsInvalidated <- true
+ if not mainState.isImportsInvalidated && canTriggerInvalidation then
+ mainState.isImportsInvalidated <- true
{ state with
stampedReferencedAssemblies = stampedReferencedAssemblies.ToImmutable()
}
else
state
- let tryGetSlot (state: IncrementalBuilderState) slot =
+ static let tryGetSlot (state: IncrementalBuilderState) slot =
match state.boundModels.[slot].TryPeekValue() with
| ValueSome boundModel ->
(boundModel, state.stampedFileNames.[slot])
@@ -1072,114 +1099,85 @@ type IncrementalBuilder(
| _ ->
None
- let tryGetBeforeSlot (state: IncrementalBuilderState) slot =
+ static let tryGetBeforeSlot mainState (state: IncrementalBuilderState) slot =
match slot with
| 0 (* first file *) ->
- (initialBoundModel, DateTime.MinValue)
+ (mainState.initialBoundModel, DateTime.MinValue)
|> Some
| _ ->
tryGetSlot state (slot - 1)
- let evalUpToTargetSlot (state: IncrementalBuilderState) targetSlot =
+ static let evalUpToTargetSlot mainState (state: IncrementalBuilderState) targetSlot =
node {
if targetSlot < 0 then
- return Some(initialBoundModel, DateTime.MinValue)
+ return Some(mainState.initialBoundModel, DateTime.MinValue)
else
let! boundModel = state.boundModels.[targetSlot].GetOrComputeValue()
return Some(boundModel, state.stampedFileNames.[targetSlot])
}
- let MaxTimeStampInDependencies stamps =
+ static let MaxTimeStampInDependencies stamps =
if Seq.isEmpty stamps then
DateTime.MinValue
else
stamps
|> Seq.max
- // END OF BUILD DESCRIPTION
- // ---------------------------------------------------------------------------------------------
-
- (*
- The data below represents a dependency graph.
-
- ReferencedAssembliesStamps => FileStamps => BoundModels => FinalizedBoundModel
- *)
-
- let gate = obj ()
- let mutable currentState =
- let cache = TimeStampCache(defaultTimeStamp)
- let initialBoundModel = GraphNode(node { return initialBoundModel })
- let boundModels = ImmutableArray.CreateBuilder(fileNames.Length)
-
- for slot = 0 to fileNames.Length - 1 do
- boundModels.Add(createBoundModelGraphNode initialBoundModel boundModels slot)
-
- let state =
- {
- stampedFileNames = Array.init fileNames.Length (fun _ -> DateTime.MinValue) |> ImmutableArray.CreateRange
- logicalStampedFileNames = Array.init fileNames.Length (fun _ -> DateTime.MinValue) |> ImmutableArray.CreateRange
- stampedReferencedAssemblies = Array.init referencedAssemblies.Length (fun _ -> DateTime.MinValue) |> ImmutableArray.CreateRange
- initialBoundModel = initialBoundModel
- boundModels = boundModels.ToImmutable()
- finalizedBoundModel = createFinalizeBoundModelGraphNode boundModels
- }
- let state = computeStampedReferencedAssemblies state false cache
- let state = computeStampedFileNames state cache
- state
-
- let computeProjectTimeStamp (state: IncrementalBuilderState) =
+ static let computeProjectTimeStamp (state: IncrementalBuilderState) =
let t1 = MaxTimeStampInDependencies state.stampedReferencedAssemblies
let t2 = MaxTimeStampInDependencies state.logicalStampedFileNames
max t1 t2
- let setCurrentState state cache (ct: CancellationToken) =
+ let gate = obj ()
+ let mutable currentState = state
+
+ let setCurrentState state (ct: CancellationToken) =
lock gate (fun () ->
ct.ThrowIfCancellationRequested()
- currentState <- computeStampedFileNames state cache
+ currentState <- computeStampedFileNames mainState state
)
- let checkFileTimeStamps (cache: TimeStampCache) =
+ let checkFileTimeStamps () =
node {
let! ct = NodeCode.CancellationToken
- setCurrentState currentState cache ct
+ setCurrentState currentState ct
}
do IncrementalBuilderEventTesting.MRU.Add(IncrementalBuilderEventTesting.IBECreated)
- member _.TcConfig = tcConfig
+ member _.TcConfig = mainState.tcConfig
- member _.FileParsed = fileParsed.Publish
+ member _.FileParsed = mainState.fileParsed.Publish
- member _.BeforeFileChecked = beforeFileChecked.Publish
+ member _.BeforeFileChecked = mainState.beforeFileChecked.Publish
- member _.FileChecked = fileChecked.Publish
+ member _.FileChecked = mainState.fileChecked.Publish
- member _.ProjectChecked = projectChecked.Publish
+ member _.ProjectChecked = mainState.projectChecked.Publish
#if !NO_EXTENSIONTYPING
- member _.ImportsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider.Publish
+ member _.ImportsInvalidatedByTypeProvider = mainState.importsInvalidatedByTypeProvider.Publish
#endif
member _.IsReferencesInvalidated =
// fast path
- if isImportsInvalidated then true
+ if mainState.isImportsInvalidated then true
else
- computeStampedReferencedAssemblies currentState true (TimeStampCache(defaultTimeStamp)) |> ignore
- isImportsInvalidated
+ computeStampedReferencedAssemblies mainState currentState true |> ignore
+ mainState.isImportsInvalidated
- member _.AllDependenciesDeprecated = allDependencies
+ member _.AllDependenciesDeprecated = mainState.allDependencies
member _.PopulatePartialCheckingResults () =
node {
- let cache = TimeStampCache defaultTimeStamp // One per step
- do! checkFileTimeStamps cache
+ do! checkFileTimeStamps ()
let! _ = currentState.finalizedBoundModel.GetOrComputeValue()
- projectChecked.Trigger()
+ mainState.projectChecked.Trigger()
}
member builder.GetCheckResultsBeforeFileInProjectEvenIfStale filename: PartialCheckResults option =
let slotOfFile = builder.GetSlotOfFileName filename
- let result = tryGetBeforeSlot currentState slotOfFile
+ let result = tryGetBeforeSlot mainState currentState slotOfFile
match result with
| Some (boundModel, timestamp) -> Some (PartialCheckResults (boundModel, timestamp))
@@ -1194,11 +1192,10 @@ type IncrementalBuilder(
| _ -> None
member builder.TryGetCheckResultsBeforeFileInProject (filename) =
- let cache = TimeStampCache defaultTimeStamp
- let tmpState = computeStampedFileNames currentState cache
+ let tmpState = computeStampedFileNames mainState currentState
let slotOfFile = builder.GetSlotOfFileName filename
- match tryGetBeforeSlot tmpState slotOfFile with
+ match tryGetBeforeSlot mainState tmpState slotOfFile with
| Some(boundModel, timestamp) -> PartialCheckResults(boundModel, timestamp) |> Some
| _ -> None
@@ -1207,9 +1204,8 @@ type IncrementalBuilder(
member _.GetCheckResultsBeforeSlotInProject (slotOfFile) =
node {
- let cache = TimeStampCache defaultTimeStamp
- do! checkFileTimeStamps cache
- let! result = evalUpToTargetSlot currentState (slotOfFile - 1)
+ do! checkFileTimeStamps()
+ let! result = evalUpToTargetSlot mainState currentState (slotOfFile - 1)
match result with
| Some (boundModel, timestamp) -> return PartialCheckResults(boundModel, timestamp)
| None -> return! failwith "Expected results to be ready. (GetCheckResultsBeforeSlotInProject)."
@@ -1217,9 +1213,8 @@ type IncrementalBuilder(
member _.GetFullCheckResultsBeforeSlotInProject (slotOfFile) =
node {
- let cache = TimeStampCache defaultTimeStamp
- do! checkFileTimeStamps cache
- let! result = evalUpToTargetSlot currentState (slotOfFile - 1)
+ do! checkFileTimeStamps()
+ let! result = evalUpToTargetSlot mainState currentState (slotOfFile - 1)
match result with
| Some (boundModel, timestamp) ->
let! _ = boundModel.GetOrComputeTcInfoExtras()
@@ -1251,8 +1246,7 @@ type IncrementalBuilder(
member _.GetCheckResultsAndImplementationsForProject() =
node {
- let cache = TimeStampCache(defaultTimeStamp)
- do! checkFileTimeStamps cache
+ do! checkFileTimeStamps()
let! result = currentState.finalizedBoundModel.GetOrComputeValue()
match result with
| ((ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt, boundModel), timestamp) ->
@@ -1267,18 +1261,17 @@ type IncrementalBuilder(
return result
}
- member _.GetLogicalTimeStampForProject(cache) =
- let tmpState = computeStampedFileNames currentState cache
+ member _.GetLogicalTimeStampForProject(_cache: TimeStampCache) =
+ let tmpState = computeStampedFileNames mainState currentState
computeProjectTimeStamp tmpState
member _.TryGetSlotOfFileName(filename: string) =
- // Get the slot of the given file and force it to build.
- let CompareFileNames (_, f2, _) =
+ let CompareFileNames (_, f2: string, _) =
let result =
String.Compare(filename, f2, StringComparison.CurrentCultureIgnoreCase)=0
|| String.Compare(FileSystem.GetFullPathShim filename, FileSystem.GetFullPathShim f2, StringComparison.CurrentCultureIgnoreCase)=0
result
- match fileNames |> Array.tryFindIndex CompareFileNames with
+ match mainState.sourceFiles |> Seq.tryFindIndex CompareFileNames with
| Some slot -> Some slot
| None -> None
@@ -1287,22 +1280,38 @@ type IncrementalBuilder(
| Some slot -> slot
| None -> failwith (sprintf "The file '%s' was not part of the project. Did you call InvalidateConfiguration when the list of files in the project changed?" filename)
- member _.GetSlotsCount () = fileNames.Length
+ member _.GetSlotsCount () = mainState.sourceFiles.Length
member this.ContainsFile(filename: string) =
(this.TryGetSlotOfFileName filename).IsSome
member builder.GetParseResultsForFile (filename) =
+ let state = currentState
let slotOfFile = builder.GetSlotOfFileName filename
- let fileInfo = fileNames.[slotOfFile]
+ let fileInfo = state.documents.[slotOfFile]
// re-parse on demand instead of retaining
- let syntaxTree = GetSyntaxTree fileInfo
+ let syntaxTree = GetSyntaxTree mainState fileInfo
syntaxTree.Parse None
- member _.SourceFiles = sourceFiles |> List.map (fun (_, f, _) -> f)
+ member _.SourceFiles = mainState.sourceFiles |> Seq.map (fun (_, f, _) -> f) |> List.ofSeq
+
+ member this.UpdateDocuments(docs: FSharpDocument seq) =
+ let state = currentState
+
+ let newState =
+ // Sort the documents by slot in order to update in ascending order.
+ let docsWithSlotSorted =
+ docs
+ |> Seq.map (fun doc -> doc, this.GetSlotOfFileName(doc.FilePath))
+ |> Seq.sortBy snd
+ (state, docsWithSlotSorted)
+ ||> Seq.fold (fun state (doc, slot) ->
+ let m, _, isLastCompiland = mainState.sourceFiles.[slot]
+ computeStampedFileName mainState state slot (m, doc, isLastCompiland)
+ )
+
+ setCurrentState newState CancellationToken.None
- /// CreateIncrementalBuilder (for background type checking). Note that fsc.fs also
- /// creates an incremental builder used by the command line compiler.
static member TryCreateIncrementalBuilderForProjectOptions
(legacyReferenceResolver, defaultFSharpBinariesDir,
frameworkTcImportsCache: FrameworkImportsCache,
@@ -1524,22 +1533,32 @@ type IncrementalBuilder(
)
let builder =
- new IncrementalBuilder(
- initialBoundModel,
- tcGlobals,
- nonFrameworkAssemblyInputs,
- tcConfig,
- outfile,
- assemblyName,
- resourceManager,
- sourceFiles,
- enablePartialTypeChecking,
- beforeFileChecked,
- fileChecked,
+ let mainState =
+ {
+ isImportsInvalidated = false
+ initialBoundModel = initialBoundModel
+ initialBoundModelNode = GraphNode(node { return initialBoundModel })
+ tcGlobals = tcGlobals
+ nonFrameworkAssemblyInputs = nonFrameworkAssemblyInputs
+ tcConfig = tcConfig
+ outfile = outfile
+ assemblyName = assemblyName
+ lexResourceManager = resourceManager
+ sourceFiles = ImmutableArray.CreateRange(sourceFiles)
+ enablePartialTypeChecking = enablePartialTypeChecking
+ allDependencies = allDependencies
+ beforeFileChecked = beforeFileChecked
+ fileChecked = fileChecked
+ fileParsed = Event<_>()
+ projectChecked = Event<_>()
+#if !NO_EXTENSIONTYPING
+ importsInvalidatedByTypeProvider = importsInvalidatedByTypeProvider
+#endif
+ }
#if !NO_EXTENSIONTYPING
- importsInvalidatedByTypeProvider,
+ importsInvalidatedByTypeProvider.Publish.Add(fun () -> mainState.isImportsInvalidated <- true)
#endif
- allDependencies)
+ new IncrementalBuilder(mainState)
return Some builder
with e ->
errorRecoveryNoRange e
@@ -1559,3 +1578,31 @@ type IncrementalBuilder(
return builderOpt, diagnostics
}
+
+
+ new(mainState) =
+ let sourceFiles = mainState.sourceFiles
+
+ let boundModels = ImmutableArray.CreateBuilder(sourceFiles.Length)
+ let documents =
+ sourceFiles
+ |> Seq.map (fun (m, f, isLastCompiland) -> (m, FSharpDocument.CreateFromFile(f), isLastCompiland))
+ |> ImmutableArray.CreateRange
+
+ for slot = 0 to sourceFiles.Length - 1 do
+ boundModels.Add(createBoundModelGraphNode mainState documents boundModels slot)
+
+ let referencedAssemblies = mainState.nonFrameworkAssemblyInputs |> Array.ofList
+
+ let state =
+ {
+ documents = documents
+ stampedFileNames = Array.init sourceFiles.Length (fun _ -> DateTime.MinValue) |> ImmutableArray.CreateRange
+ logicalStampedFileNames = Array.init sourceFiles.Length (fun _ -> DateTime.MinValue) |> ImmutableArray.CreateRange
+ stampedReferencedAssemblies = Array.init referencedAssemblies.Length (fun _ -> DateTime.MinValue) |> ImmutableArray.CreateRange
+ boundModels = boundModels.ToImmutable()
+ finalizedBoundModel = createFinalizeBoundModelGraphNode mainState boundModels
+ }
+ let state = computeStampedReferencedAssemblies mainState state false
+ let state = computeStampedFileNames mainState state
+ IncrementalBuilder(mainState, state)
diff --git a/src/fsharp/service/IncrementalBuild.fsi b/src/fsharp/service/IncrementalBuild.fsi
index c8c5c26da6a..c3852309beb 100755
--- a/src/fsharp/service/IncrementalBuild.fsi
+++ b/src/fsharp/service/IncrementalBuild.fsi
@@ -237,6 +237,8 @@ type internal IncrementalBuilder =
/// This may be a marginally long-running operation (parses are relatively quick, only one file needs to be parsed)
member GetParseResultsForFile: filename:string -> ParsedInput * range * string * (PhasedDiagnostic * FSharpDiagnosticSeverity)[]
+ member UpdateDocuments: docs: FSharpDocument seq -> unit
+
/// Create the incremental builder
static member TryCreateIncrementalBuilderForProjectOptions:
LegacyReferenceResolver *
diff --git a/src/fsharp/service/SemanticClassificationKey.fs b/src/fsharp/service/SemanticClassificationKey.fs
index 960d3fade56..42962053074 100644
--- a/src/fsharp/service/SemanticClassificationKey.fs
+++ b/src/fsharp/service/SemanticClassificationKey.fs
@@ -56,8 +56,9 @@ type SemanticClassificationKeyStoreBuilder() =
let b = BlobBuilder()
member _.WriteAll (semanticClassification: SemanticClassificationItem[]) =
- use ptr = fixed semanticClassification
- b.WriteBytes(NativePtr.ofNativeInt (NativePtr.toNativeInt ptr), semanticClassification.Length * sizeof)
+ if semanticClassification.Length > 0 then
+ use ptr = fixed semanticClassification
+ b.WriteBytes(NativePtr.ofNativeInt (NativePtr.toNativeInt ptr), semanticClassification.Length * sizeof)
member _.TryBuildAndReset() =
if b.Count > 0 then
diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs
index 1ed29a76651..7d767c2dbd4 100644
--- a/src/fsharp/service/service.fs
+++ b/src/fsharp/service/service.fs
@@ -303,7 +303,7 @@ type BackgroundCompiler(
let! builderOpt, diagnostics =
IncrementalBuilder.TryCreateIncrementalBuilderForProjectOptions
- (legacyReferenceResolver, FSharpCheckerResultsSettings.defaultFSharpBinariesDir, frameworkTcImportsCache, loadClosure, Array.toList options.SourceFiles,
+ (legacyReferenceResolver, FSharpCheckerResultsSettings.defaultFSharpBinariesDir, frameworkTcImportsCache, loadClosure, List.ofArray options.SourceFiles,
Array.toList options.OtherOptions, projectReferences, options.ProjectDirectory,
options.UseScriptResolutionRules, keepAssemblyContents, keepAllBackgroundResolutions,
tryGetMetadataSnapshot, suggestNamesForErrors, keepAllBackgroundSymbolUses,
@@ -919,6 +919,16 @@ type BackgroundCompiler(
let _ = createBuilderNode (options, userOpName, CancellationToken.None)
()
+ member bc.UpdateDocuments(options: FSharpProjectOptions, docs) =
+ let builderNode = getOrCreateBuilder(options, "UpdateDocuments")
+ node {
+ match! builderNode with
+ | Some builder, _ ->
+ builder.UpdateDocuments(docs)
+ | _ ->
+ ()
+ }
+
member bc.ClearCache(options: seq, _userOpName) =
lock gate (fun () ->
options
@@ -1217,6 +1227,10 @@ type FSharpChecker(legacyReferenceResolver,
let userOpName = defaultArg userOpName "Unknown"
backgroundCompiler.InvalidateConfiguration(options, userOpName)
+ member _.UpdateBackgroundDocuments(options: FSharpProjectOptions, docs) =
+ backgroundCompiler.UpdateDocuments(options, docs)
+ |> Async.AwaitNodeCode
+
/// Clear the internal cache of the given projects.
member _.ClearCache(options: FSharpProjectOptions seq, ?userOpName: string) =
let userOpName = defaultArg userOpName "Unknown"
diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi
index 97b6f9f7983..8134e7715e7 100644
--- a/src/fsharp/service/service.fsi
+++ b/src/fsharp/service/service.fsi
@@ -362,6 +362,13 @@ type public FSharpChecker =
/// An optional string used for tracing compiler operations associated with this request.
member InvalidateConfiguration: options: FSharpProjectOptions * ?userOpName: string -> unit
+ ///
+ /// This function is called when the documents of a particular project need to be updated in a batch for the background build.
+ ///
+ /// The options for the project or script, used to determine active --define conditionals and other options relevant to parsing.
+ /// FSharp documents
+ member UpdateBackgroundDocuments: options: FSharpProjectOptions * docs: FSharpDocument seq -> Async
+
/// Clear the internal cache of the given projects.
/// The given project options.
/// An optional string used for tracing compiler operations associated with this request.
diff --git a/src/fsharp/utils/FileSystem.fs b/src/fsharp/utils/FileSystem.fs
index 9346e6ab1a8..5deb1176e25 100644
--- a/src/fsharp/utils/FileSystem.fs
+++ b/src/fsharp/utils/FileSystem.fs
@@ -640,7 +640,7 @@ module public StreamExtensions =
member s.Write (data: 'a) : unit =
use sw = s.GetWriter()
sw.Write(data)
-
+
member s.GetReader(codePage: int option, ?retryLocked: bool) =
let retryLocked = defaultArg retryLocked false
let retryDelayMilliseconds = 50
diff --git a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
index 18b6fd7e05d..63af099ba31 100644
--- a/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
+++ b/tests/FSharp.Compiler.Service.Tests/SurfaceArea.netstandard.fs
@@ -1992,6 +1992,7 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] CheckFileInProjectAllowingStaleCachedResults(FSharp.Compiler.CodeAnalysis.FSharpParseFileResults, System.String, Int32, System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.EditorServices.SemanticClassificationView]] GetBackgroundSemanticClassificationForFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] NotifyProjectCleaned(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
+FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[Microsoft.FSharp.Core.Unit] UpdateBackgroundDocuments(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, System.Collections.Generic.IEnumerable`1[FSharp.Compiler.CodeAnalysis.FSharpDocument])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Collections.Generic.IEnumerable`1[FSharp.Compiler.Text.Range]] FindBackgroundReferencesInFile(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, FSharp.Compiler.Symbols.FSharpSymbol, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileAnswer]] ParseAndCheckFileInProject(System.String, Int32, FSharp.Compiler.Text.ISourceText, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Microsoft.FSharp.Control.FSharpAsync`1[System.Tuple`2[FSharp.Compiler.CodeAnalysis.FSharpParseFileResults,FSharp.Compiler.CodeAnalysis.FSharpCheckFileResults]] GetBackgroundCheckResultsForFileInProject(System.String, FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
@@ -2022,6 +2023,16 @@ FSharp.Compiler.CodeAnalysis.FSharpChecker: Void ClearLanguageServiceRootCachesA
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void InvalidateAll()
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void InvalidateConfiguration(FSharp.Compiler.CodeAnalysis.FSharpProjectOptions, Microsoft.FSharp.Core.FSharpOption`1[System.String])
FSharp.Compiler.CodeAnalysis.FSharpChecker: Void set_MaxMemory(Int32)
+FSharp.Compiler.CodeAnalysis.FSharpDocument
+FSharp.Compiler.CodeAnalysis.FSharpDocument: Boolean IsOpen
+FSharp.Compiler.CodeAnalysis.FSharpDocument: Boolean get_IsOpen()
+FSharp.Compiler.CodeAnalysis.FSharpDocument: FSharp.Compiler.CodeAnalysis.DocumentText GetText()
+FSharp.Compiler.CodeAnalysis.FSharpDocument: FSharp.Compiler.CodeAnalysis.FSharpDocument Create(System.String, Boolean, Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,System.DateTime], Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,FSharp.Compiler.Text.ISourceText])
+FSharp.Compiler.CodeAnalysis.FSharpDocument: FSharp.Compiler.CodeAnalysis.FSharpDocument CreateCopyFromFile(System.String, Boolean)
+FSharp.Compiler.CodeAnalysis.FSharpDocument: System.DateTime TimeStamp
+FSharp.Compiler.CodeAnalysis.FSharpDocument: System.DateTime get_TimeStamp()
+FSharp.Compiler.CodeAnalysis.FSharpDocument: System.String FilePath
+FSharp.Compiler.CodeAnalysis.FSharpDocument: System.String get_FilePath()
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsBindingALambdaAtPosition(FSharp.Compiler.Text.Position)
FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: Boolean IsPosContainedInApplication(FSharp.Compiler.Text.Position)
@@ -5154,6 +5165,7 @@ FSharp.Compiler.Syntax.DebugPointAtBinding: Int32 Tag
FSharp.Compiler.Syntax.DebugPointAtBinding: Int32 get_Tag()
FSharp.Compiler.Syntax.DebugPointAtBinding: System.String ToString()
FSharp.Compiler.Syntax.DebugPointAtFinally
+FSharp.Compiler.Syntax.DebugPointAtFinally+Tags: Int32 Body
FSharp.Compiler.Syntax.DebugPointAtFinally+Tags: Int32 No
FSharp.Compiler.Syntax.DebugPointAtFinally+Tags: Int32 Yes
FSharp.Compiler.Syntax.DebugPointAtFinally+Yes: FSharp.Compiler.Text.Range get_range()
@@ -5161,12 +5173,16 @@ FSharp.Compiler.Syntax.DebugPointAtFinally+Yes: FSharp.Compiler.Text.Range range
FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean Equals(FSharp.Compiler.Syntax.DebugPointAtFinally)
FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean Equals(System.Object)
FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
+FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean IsBody
FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean IsNo
FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean IsYes
+FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean get_IsBody()
FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean get_IsNo()
FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean get_IsYes()
+FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally Body
FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally NewYes(FSharp.Compiler.Text.Range)
FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally No
+FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally get_Body()
FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally get_No()
FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally+Tags
FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally+Yes
@@ -5175,11 +5191,6 @@ FSharp.Compiler.Syntax.DebugPointAtFinally: Int32 GetHashCode(System.Collections
FSharp.Compiler.Syntax.DebugPointAtFinally: Int32 Tag
FSharp.Compiler.Syntax.DebugPointAtFinally: Int32 get_Tag()
FSharp.Compiler.Syntax.DebugPointAtFinally: System.String ToString()
-FSharp.Compiler.Syntax.DebugPointAtFinally+Tags: Int32 Body
-FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean IsBody
-FSharp.Compiler.Syntax.DebugPointAtFinally: Boolean get_IsBody()
-FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally Body
-FSharp.Compiler.Syntax.DebugPointAtFinally: FSharp.Compiler.Syntax.DebugPointAtFinally get_Body()
FSharp.Compiler.Syntax.DebugPointAtFor
FSharp.Compiler.Syntax.DebugPointAtFor+Tags: Int32 No
FSharp.Compiler.Syntax.DebugPointAtFor+Tags: Int32 Yes
diff --git a/tests/fsharp/tools/fsharp41/net45/providerDesigner.dll b/tests/fsharp/tools/fsharp41/net45/providerDesigner.dll
index cb79536e157..3d36c659c05 100644
Binary files a/tests/fsharp/tools/fsharp41/net45/providerDesigner.dll and b/tests/fsharp/tools/fsharp41/net45/providerDesigner.dll differ
diff --git a/tests/fsharp/tools/fsharp41/net461/providerDesigner.dll b/tests/fsharp/tools/fsharp41/net461/providerDesigner.dll
index 1b581c260dc..a1196e9ddea 100644
Binary files a/tests/fsharp/tools/fsharp41/net461/providerDesigner.dll and b/tests/fsharp/tools/fsharp41/net461/providerDesigner.dll differ
diff --git a/tests/fsharp/tools/fsharp41/netstandard2.0/providerDesigner.dll b/tests/fsharp/tools/fsharp41/netstandard2.0/providerDesigner.dll
index 1b6a4ded584..d304e2a81c6 100644
Binary files a/tests/fsharp/tools/fsharp41/netstandard2.0/providerDesigner.dll and b/tests/fsharp/tools/fsharp41/netstandard2.0/providerDesigner.dll differ
diff --git a/tests/fsharp/typeProviders/fsharp41/net45/providerDesigner.dll b/tests/fsharp/typeProviders/fsharp41/net45/providerDesigner.dll
index c033697fd00..76adae056cb 100644
Binary files a/tests/fsharp/typeProviders/fsharp41/net45/providerDesigner.dll and b/tests/fsharp/typeProviders/fsharp41/net45/providerDesigner.dll differ
diff --git a/tests/fsharp/typeProviders/fsharp41/net461/providerDesigner.dll b/tests/fsharp/typeProviders/fsharp41/net461/providerDesigner.dll
index a26e114cc74..665d51e85e3 100644
Binary files a/tests/fsharp/typeProviders/fsharp41/net461/providerDesigner.dll and b/tests/fsharp/typeProviders/fsharp41/net461/providerDesigner.dll differ
diff --git a/tests/fsharp/typeProviders/fsharp41/netstandard2.0/providerDesigner.dll b/tests/fsharp/typeProviders/fsharp41/netstandard2.0/providerDesigner.dll
index 4f0c61b8cea..244f2329815 100644
Binary files a/tests/fsharp/typeProviders/fsharp41/netstandard2.0/providerDesigner.dll and b/tests/fsharp/typeProviders/fsharp41/netstandard2.0/providerDesigner.dll differ
diff --git a/tests/service/EditorTests.fs b/tests/service/EditorTests.fs
index ab3a1f8e492..bc30ae2dfd7 100644
--- a/tests/service/EditorTests.fs
+++ b/tests/service/EditorTests.fs
@@ -1206,7 +1206,7 @@ let _ = RegexTypedStatic.IsMatch<"ABC" >( (*$*) ) // TEST: no assert on Ctrl-sp
"""
FileSystem.OpenFileForWriteShim(fileName1).Write(fileSource1)
- let fileLines1 = FileSystem.OpenFileForReadShim(fileName1).AsStream().ReadLines()
+ let fileLines1 = FileSystem.OpenFileForReadShim(fileName1).ReadLines()
let fileNames = [fileName1]
let args = Array.append (mkProjectCommandLineArgs (dllName, fileNames)) [| "-r:" + PathRelativeToTestAssembly(@"DummyProviderForLanguageServiceTesting.dll") |]
diff --git a/tests/service/FileSystemTests.fs b/tests/service/FileSystemTests.fs
index a6dd94fcc45..115a6409494 100644
--- a/tests/service/FileSystemTests.fs
+++ b/tests/service/FileSystemTests.fs
@@ -40,8 +40,7 @@ type internal MyFileSystem() =
let shouldShadowCopy = defaultArg shouldShadowCopy false
let useMemoryMappedFile = defaultArg useMemoryMappedFile false
match MyFileSystem.FilesCache.TryGetValue filePath with
- | true, text ->
- new MemoryStream(Encoding.UTF8.GetBytes(text)) :> Stream
+ | true, text -> new MemoryStream(Encoding.UTF8.GetBytes(text)) :> Stream
| _ -> base.OpenFileForReadShim(filePath, useMemoryMappedFile, shouldShadowCopy)
override _.FileExistsShim(fileName) = MyFileSystem.FilesCache.ContainsKey(fileName) || base.FileExistsShim(fileName)
diff --git a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs
index a3844ae749e..b6683c4e24a 100644
--- a/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs
+++ b/vsintegration/src/FSharp.Editor/Classification/ClassificationService.fs
@@ -167,7 +167,7 @@ type internal FSharpClassificationService
let! sourceText = document.GetTextAsync(cancellationToken)
// If we are trying to get semantic classification for a document that is not open, get the results from the background and cache it.
- // We do this for find all references when it is populating results.
+ // We do this for find all references when it is populating results.
// We cache it temporarily so we do not have to continously call into the checker and perform a background operation.
if not (document.Project.Solution.Workspace.IsDocumentOpen document.Id) then
match! semanticClassificationCache.TryGetValueAsync document |> liftAsync with
@@ -179,10 +179,10 @@ type internal FSharpClassificationService
do! semanticClassificationCache.SetAsync(document, classificationDataLookup) |> liftAsync
addSemanticClassificationByLookup sourceText textSpan classificationDataLookup result
else
- let! _, _, checkResults = checkerProvider.Checker.ParseAndCheckDocument(document, projectOptions, allowStaleResults = false, userOpName=userOpName)
- let targetRange = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, textSpan, sourceText)
- let classificationData = checkResults.GetSemanticClassification (Some targetRange)
- addSemanticClassification sourceText textSpan classificationData result
+ let! _ = checkerProvider.Checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
+ let! classificationData = checkerProvider.Checker.GetBackgroundSemanticClassificationForFile(document.FilePath, projectOptions, userOpName=userOpName) |> liftAsync
+ let classificationDataLookup = toSemanticClassificationLookup classificationData
+ addSemanticClassificationByLookup sourceText textSpan classificationDataLookup result
}
|> Async.Ignore |> RoslynHelpers.StartAsyncUnitAsTask cancellationToken
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs
index 3890eba616f..d341ea30e80 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/AddOpenCodeFixProvider.fs
@@ -90,7 +90,7 @@ type internal FSharpAddOpenCodeFixProvider
let document = context.Document
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
- let! _, parsedInput, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName)
+ let! parseResults, checkResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
let line = sourceText.Lines.GetLineFromPosition(context.Span.End)
let linePos = sourceText.Lines.GetLinePosition(context.Span.End)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
@@ -110,7 +110,7 @@ type internal FSharpAddOpenCodeFixProvider
let endPos = Position.fromZ endLinePos.Line endLinePos.Character
Range.mkRange context.Document.FilePath startPos endPos
- let isAttribute = ParsedInput.GetEntityKind(unresolvedIdentRange.Start, parsedInput) = Some EntityKind.Attribute
+ let isAttribute = ParsedInput.GetEntityKind(unresolvedIdentRange.Start, parseResults.ParseTree) = Some EntityKind.Attribute
let entities =
assemblyContentProvider.GetAllEntitiesInProjectAndReferencedAssemblies checkResults
@@ -126,7 +126,7 @@ type internal FSharpAddOpenCodeFixProvider
s.CleanedIdents
|> Array.replace (s.CleanedIdents.Length - 1) (lastIdent.Substring(0, lastIdent.Length - 9)) ])
- let longIdent = ParsedInput.GetLongIdentAt parsedInput unresolvedIdentRange.End
+ let longIdent = ParsedInput.GetLongIdentAt parseResults.ParseTree unresolvedIdentRange.End
let! maybeUnresolvedIdents =
longIdent
@@ -141,7 +141,7 @@ type internal FSharpAddOpenCodeFixProvider
if document.FSharpOptions.CodeFixes.AlwaysPlaceOpensAtTopLevel then OpenStatementInsertionPoint.TopLevel
else OpenStatementInsertionPoint.Nearest
- let createEntity = ParsedInput.TryFindInsertionContext unresolvedIdentRange.StartLine parsedInput maybeUnresolvedIdents insertionPoint
+ let createEntity = ParsedInput.TryFindInsertionContext unresolvedIdentRange.StartLine parseResults.ParseTree maybeUnresolvedIdents insertionPoint
return entities |> Seq.map createEntity |> Seq.concat |> Seq.toList |> addSuggestionsAsCodeFixes context
}
|> Async.Ignore
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs b/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs
index cbf1b645648..9dbf8d7f16d 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/AddTypeAnnotationToObjectOfIndeterminateType.fs
@@ -47,7 +47,7 @@ type internal FSharpAddTypeAnnotationToObjectOfIndeterminateTypeFixProvider
let textLine = sourceText.Lines.GetLineFromPosition position
let textLinePos = sourceText.Lines.GetLinePosition position
let fcsTextLineNumber = Line.fromZ textLinePos.Line
- let! _, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, userOpName=userOpName)
+ let! _, checkFileResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false)
let decl = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, false)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ChangeRefCellDerefToNotExpression.fs b/vsintegration/src/FSharp.Editor/CodeFix/ChangeRefCellDerefToNotExpression.fs
index b595cc21e55..5a320d6f5d4 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ChangeRefCellDerefToNotExpression.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/ChangeRefCellDerefToNotExpression.fs
@@ -27,7 +27,7 @@ type internal FSharpChangeRefCellDerefToNotExpressionCodeFixProvider
let document = context.Document
let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
- let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions, userOpName=userOpName)
+ let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions) |> liftAsync
let errorRange = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText)
let! derefRange = parseResults.TryRangeOfRefCellDereferenceContainingPos errorRange.Start
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs b/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs
index 169588e1c84..a6627e71df5 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/ConvertCSharpLambdaToFSharpLambda.fs
@@ -24,7 +24,7 @@ type internal FSharpConvertCSharpLambdaToFSharpLambdaCodeFixProvider
override _.RegisterCodeFixesAsync context =
asyncMaybe {
let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName)
- let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions, userOpName)
+ let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions) |> liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let errorRange = RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs b/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs
index 3710101ed4e..62f9c741421 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/ConvertToAnonymousRecord.fs
@@ -29,7 +29,7 @@ type internal FSharpConvertToAnonymousRecordCodeFixProvider
asyncMaybe {
let document = context.Document
let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
- let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions, userOpName=userOpName)
+ let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions) |> liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let errorRange = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs
index c21a1123380..580bfefe909 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/ImplementInterfaceCodeFixProvider.fs
@@ -145,7 +145,7 @@ type internal FSharpImplementInterfaceCodeFixProvider
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName)
let cancellationToken = context.CancellationToken
let! sourceText = context.Document.GetTextAsync(cancellationToken)
- let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(context.Document, projectOptions, userOpName = userOpName)
+ let! parseResults, checkFileResults = checker.CheckDocumentInProject(context.Document, projectOptions) |> liftAsync
let textLine = sourceText.Lines.GetLineFromPosition context.Span.Start
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
// Notice that context.Span doesn't return reliable ranges to find tokens at exact positions.
@@ -172,7 +172,7 @@ type internal FSharpImplementInterfaceCodeFixProvider
| '}' -> None
| _ ->
Some context.Span.End
- let! interfaceState = queryInterfaceState appendBracketAt interfacePos tokens parsedInput
+ let! interfaceState = queryInterfaceState appendBracketAt interfacePos tokens parseResults.ParseTree
let! symbol = Tokenizer.getSymbolAtPosition(context.Document.Id, sourceText, fixupPosition, context.Document.FilePath, defines, SymbolLookupKind.Greedy, false, false)
let fcsTextLineNumber = textLine.LineNumber + 1
let lineContents = textLine.ToString()
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs b/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs
index 9aab9475320..27dce9cb0c2 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/MakeDeclarationMutable.fs
@@ -46,7 +46,7 @@ type internal FSharpMakeDeclarationMutableFixProvider
let textLine = sourceText.Lines.GetLineFromPosition position
let textLinePos = sourceText.Lines.GetLinePosition position
let fcsTextLineNumber = Line.fromZ textLinePos.Line
- let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, userOpName=userOpName)
+ let! parseFileResults, checkFileResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Greedy, false, false)
let decl = checkFileResults.GetDeclarationLocation (fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland, false)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs b/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs
index 67b586688e5..8c54567942b 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/MakeOuterBindingRecursive.fs
@@ -25,7 +25,7 @@ type internal FSharpMakeOuterBindingRecursiveCodeFixProvider
override _.RegisterCodeFixesAsync context =
asyncMaybe {
let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName)
- let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions, userOpName)
+ let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions) |> liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let diagnosticRange = RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs
index 59e6ff102c1..95b5377b504 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveReturnOrYield.fs
@@ -24,7 +24,7 @@ type internal FSharpRemoveReturnOrYieldCodeFixProvider
override _.RegisterCodeFixesAsync context =
asyncMaybe {
let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(context.Document, context.CancellationToken, userOpName)
- let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions, userOpName=userOpName)
+ let! parseResults = checkerProvider.Checker.ParseDocument(context.Document, parsingOptions) |> liftAsync
let! sourceText = context.Document.GetTextAsync(context.CancellationToken)
let errorRange = RoslynHelpers.TextSpanToFSharpRange(context.Document.FilePath, context.Span, sourceText)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedBinding.fs b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedBinding.fs
index 35e489e8675..7ac03d8f4a8 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedBinding.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/RemoveUnusedBinding.fs
@@ -32,7 +32,7 @@ type internal FSharpRemoveUnusedBindingCodeFixProvider
let! sourceText = document.GetTextAsync(context.CancellationToken)
let! parsingOptions, _ = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
- let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions, userOpName=userOpName)
+ let! parseResults = checkerProvider.Checker.ParseDocument(document, parsingOptions) |> liftAsync
let diagnostics =
context.Diagnostics
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs
index 96ecbcd4351..93ee2c3e57e 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/RenameUnusedValue.fs
@@ -42,7 +42,7 @@ type internal FSharpRenameUnusedValueCodeFixProvider
// where backtickes are replaced with parens.
if not (PrettyNaming.IsOperatorOrBacktickedName ident) && not (ident.StartsWith "``") then
let! parsingOptions, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
- let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName=userOpName)
+ let! _, checkResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
let m = RoslynHelpers.TextSpanToFSharpRange(document.FilePath, context.Span, sourceText)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, context.Span.Start, document.FilePath, defines, SymbolLookupKind.Greedy, false, false)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs b/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs
index fdbd65bd228..0c9787e70e1 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/ReplaceWithSuggestion.fs
@@ -35,7 +35,7 @@ type internal FSharpReplaceWithSuggestionCodeFixProvider
let document = context.Document
let! _, projectOptions = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, context.CancellationToken, userOpName)
- let! parseFileResults, _, checkFileResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName=userOpName)
+ let! parseFileResults, checkFileResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
// This is all needed to get a declaration list
let! sourceText = document.GetTextAsync(context.CancellationToken)
diff --git a/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs b/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs
index 44a1fa5682d..100383057b1 100644
--- a/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs
+++ b/vsintegration/src/FSharp.Editor/CodeFix/UseMutationWhenValueIsMutable.fs
@@ -56,7 +56,7 @@ type internal FSharpUseMutationWhenValueIsMutableFixProvider
let textLine = sourceText.Lines.GetLineFromPosition adjustedPosition
let textLinePos = sourceText.Lines.GetLinePosition adjustedPosition
let fcsTextLineNumber = Line.fromZ textLinePos.Line
- let! _, _, checkFileResults = checker.ParseAndCheckDocument (document, projectOptions, userOpName=userOpName)
+ let! _, checkFileResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
let! lexerSymbol = Tokenizer.getSymbolAtPosition (document.Id, sourceText, adjustedPosition, document.FilePath, defines, SymbolLookupKind.Greedy, false, false)
let! symbolUse = checkFileResults.GetSymbolUseAtLocation(fcsTextLineNumber, lexerSymbol.Ident.idRange.EndColumn, textLine.ToString(), lexerSymbol.FullIsland)
diff --git a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs
index a9b1fc84584..867d93c48d6 100644
--- a/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs
+++ b/vsintegration/src/FSharp.Editor/CodeLens/FSharpCodeLensService.fs
@@ -158,7 +158,7 @@ type internal FSharpCodeLensService
#endif
let! document = workspace.CurrentSolution.GetDocument(documentId.Value) |> Option.ofObj
let! _, options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, bufferChangedCts.Token, userOpName)
- let! _, parsedInput, checkFileResults = checker.ParseAndCheckDocument(document, options, "LineLens", allowStaleResults=true)
+ let! parseResults, checkFileResults = checker.CheckDocumentInProject(document, options) |> liftAsync
#if DEBUG
logInfof "Getting uses of all symbols!"
#endif
@@ -236,7 +236,7 @@ type internal FSharpCodeLensService
oldResults.Remove funcID |> ignore
else
let declarationLine, range =
- match visit func.DeclarationLocation.Start parsedInput with
+ match visit func.DeclarationLocation.Start parseResults.ParseTree with
| Some range -> range.StartLine - 1, range
| _ -> func.DeclarationLocation.StartLine - 1, func.DeclarationLocation
// Track the old element for removal
@@ -267,7 +267,7 @@ type internal FSharpCodeLensService
for unattachedSymbol in unattachedSymbols do
let symbolUse, func, funcID, fullTypeSignature = unattachedSymbol
let declarationLine, range =
- match visit func.DeclarationLocation.Start parsedInput with
+ match visit func.DeclarationLocation.Start parseResults.ParseTree with
| Some range -> range.StartLine - 1, range
| _ -> func.DeclarationLocation.StartLine - 1, func.DeclarationLocation
diff --git a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs
index 1f77bba3428..e13b840644c 100644
--- a/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs
+++ b/vsintegration/src/FSharp.Editor/Commands/HelpContextService.fs
@@ -25,9 +25,9 @@ type internal FSharpHelpContextService
) =
static let userOpName = "ImplementInterfaceCodeFix"
- static member GetHelpTerm(checker: FSharpChecker, document: Document, options, span: TextSpan, tokens: List, perfOptions) : Async =
+ static member GetHelpTerm(checker: FSharpChecker, document: Document, options, span: TextSpan, tokens: List, _perfOptions) : Async =
asyncMaybe {
- let! _, _, check = checker.ParseAndCheckDocument(document, options, perfOptions, userOpName)
+ let! _, check = checker.CheckDocumentInProject(document, options) |> liftAsync
let! sourceText = document.GetTextAsync() |> liftTaskAsync
let textLines = sourceText.Lines
let lineInfo = textLines.GetLineFromPosition(span.Start)
diff --git a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs
index 4dd22f0ffa1..70a402290d6 100644
--- a/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs
+++ b/vsintegration/src/FSharp.Editor/Commands/XmlDocCommandService.fs
@@ -70,7 +70,7 @@ type internal XmlDocCommandFilter
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, CancellationToken.None, userOpName)
let! cancellationToken = Async.CancellationToken |> liftAsync
let! sourceText = document.GetTextAsync(cancellationToken)
- let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName)
+ let! parseResults = checker.ParseDocument(document, parsingOptions) |> liftAsync
let xmlDocables = XmlDocParser.GetXmlDocables (sourceText.ToFSharpSourceText(), parseResults.ParseTree)
let xmlDocablesBelowThisLine =
// +1 because looking below current line for e.g. a 'member'
diff --git a/vsintegration/src/FSharp.Editor/Common/Extensions.fs b/vsintegration/src/FSharp.Editor/Common/Extensions.fs
index 825a010f387..40ac2c767d3 100644
--- a/vsintegration/src/FSharp.Editor/Common/Extensions.fs
+++ b/vsintegration/src/FSharp.Editor/Common/Extensions.fs
@@ -14,6 +14,7 @@ open Microsoft.CodeAnalysis.Host
open FSharp.Compiler.EditorServices
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text
+open FSharp.Compiler.CodeAnalysis
open Microsoft.VisualStudio.FSharp.Editor
@@ -289,3 +290,27 @@ module Exception =
| _ -> root
|> flattenInner
|> String.concat " ---> "
+
+type Document with
+
+ member this.ToFSharpDocument() =
+ let dt = DateTime.UtcNow
+ let getTimeStamp = fun () -> dt
+
+ let mutable weakFSharpText = Unchecked.defaultof<_>
+ let getSourceText = fun () ->
+ match weakFSharpText with
+ | null ->
+ let fsharpText = this.GetTextAsync().Result.ToFSharpSourceText()
+ weakFSharpText <- WeakReference<_>(fsharpText)
+ fsharpText
+ | _ ->
+ match weakFSharpText.TryGetTarget() with
+ | true, fsharpText -> fsharpText
+ | _ ->
+ let fsharpText = this.GetTextAsync().Result.ToFSharpSourceText()
+ weakFSharpText <- WeakReference<_>(fsharpText)
+ fsharpText
+
+ let isOpen = this.Project.Solution.Workspace.IsDocumentOpen(this.Id)
+ FSharpDocument.Create(this.FilePath, isOpen, getTimeStamp, getSourceText)
diff --git a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs
index f99d696c62e..fe73a425179 100644
--- a/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs
+++ b/vsintegration/src/FSharp.Editor/Completion/CompletionProvider.fs
@@ -108,10 +108,10 @@ type internal FSharpCompletionProvider
static member ProvideCompletionsAsyncAux(checker: FSharpChecker, document: Document, caretPosition: int, options: FSharpProjectOptions,
- getAllSymbols: FSharpCheckFileResults -> AssemblySymbol list, languageServicePerformanceOptions: LanguageServicePerformanceOptions, intellisenseOptions: IntelliSenseOptions) =
+ getAllSymbols: FSharpCheckFileResults -> AssemblySymbol list, _languageServicePerformanceOptions: LanguageServicePerformanceOptions, intellisenseOptions: IntelliSenseOptions) =
asyncMaybe {
- let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(document, options, languageServicePerformanceOptions, userOpName = userOpName)
+ let! parseResults, checkFileResults = checker.CheckDocumentInProject(document, options) |> liftAsync
let! sourceText = document.GetTextAsync() |> liftTaskAsync
let textLines = sourceText.Lines
let caretLinePos = textLines.GetLinePosition(caretPosition)
@@ -292,7 +292,7 @@ type internal FSharpCompletionProvider
let textWithItemCommitted = sourceText.WithChanges(TextChange(item.Span, nameInCode))
let line = sourceText.Lines.GetLineFromPosition(item.Span.Start)
let! parsingOptions, _options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document, cancellationToken, userOpName)
- let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName)
+ let! parseResults = checker.ParseDocument(document, parsingOptions) |> liftAsync
let fullNameIdents = fullName |> Option.map (fun x -> x.Split '.') |> Option.defaultValue [||]
let insertionPoint =
diff --git a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs
index 96ff3b2d7a2..a4fb179ca18 100644
--- a/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs
+++ b/vsintegration/src/FSharp.Editor/Completion/SignatureHelp.fs
@@ -508,15 +508,14 @@ type internal FSharpSignatureHelpProvider
possibleCurrentSignatureHelpSessionKind: CurrentSignatureHelpSessionKind option
) =
asyncMaybe {
+ let! parseResults, checkFileResults = checker.CheckDocumentInProject(document, options) |> liftAsync
+
let! sourceText = document.GetTextAsync() |> liftTaskAsync
let textLines = sourceText.Lines
- let perfOptions = document.FSharpOptions.LanguageServicePerformance
let caretLinePos = textLines.GetLinePosition(caretPosition)
let caretLineColumn = caretLinePos.Character
- let! parseResults, _, checkFileResults = checker.ParseAndCheckDocument(document, options, perfOptions, userOpName = userOpName)
-
let adjustedColumnInSource =
let rec loop ch pos =
if Char.IsWhiteSpace(ch) then
diff --git a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs
index 77f3081d879..f3b26332c5c 100644
--- a/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs
+++ b/vsintegration/src/FSharp.Editor/Debugging/BreakpointResolutionService.fs
@@ -40,10 +40,8 @@ type internal FSharpBreakpointResolutionService
else
let textLineColumn = textLinePos.Character
let fcsTextLineNumber = Line.fromZ textLinePos.Line // Roslyn line numbers are zero-based, FSharp.Compiler.Service line numbers are 1-based
- let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName)
- match parseResults with
- | Some parseResults -> return parseResults.ValidateBreakpointLocation(mkPos fcsTextLineNumber textLineColumn)
- | _ -> return None
+ let! parseResults = checker.ParseDocument(document, parsingOptions)
+ return parseResults.ValidateBreakpointLocation(mkPos fcsTextLineNumber textLineColumn)
}
interface IFSharpBreakpointResolutionService with
diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs
index dd26fbf1026..5e4666f4e89 100644
--- a/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs
+++ b/vsintegration/src/FSharp.Editor/Diagnostics/DocumentDiagnosticAnalyzer.fs
@@ -58,31 +58,23 @@ type internal FSharpDocumentDiagnosticAnalyzer
static member GetDiagnostics(checker: FSharpChecker, document: Document, parsingOptions: FSharpParsingOptions, options: FSharpProjectOptions, diagnosticType: DiagnosticsType) =
async {
- let! ct = Async.CancellationToken
-
- let! parseResults = checker.ParseDocument(document, parsingOptions, userOpName)
- match parseResults with
- | None -> return ImmutableArray.Empty
- | Some parseResults ->
-
- let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask
- let filePath = document.FilePath
-
let! errors =
async {
match diagnosticType with
| DiagnosticsType.Semantic ->
- let! checkResultsAnswer = checker.CheckDocument(document, parseResults, options, userOpName)
- match checkResultsAnswer with
- | FSharpCheckFileAnswer.Aborted -> return [||]
- | FSharpCheckFileAnswer.Succeeded results ->
- // In order to eleminate duplicates, we should not return parse errors here because they are returned by `AnalyzeSyntaxAsync` method.
- let allErrors = HashSet(results.Diagnostics, errorInfoEqualityComparer)
- allErrors.ExceptWith(parseResults.Diagnostics)
- return Seq.toArray allErrors
+ let! parseResults, checkResults = checker.CheckDocumentInProject(document, options)
+ // In order to eleminate duplicates, we should not return parse errors here because they are returned by `AnalyzeSyntaxAsync` method.
+ let allErrors = HashSet(checkResults.Diagnostics, errorInfoEqualityComparer)
+ allErrors.ExceptWith(parseResults.Diagnostics)
+ return Seq.toArray allErrors
| DiagnosticsType.Syntax ->
+ let! parseResults = checker.ParseDocument(document, parsingOptions)
return parseResults.Diagnostics
}
+
+ let! ct = Async.CancellationToken
+ let! sourceText = document.GetTextAsync(ct) |> Async.AwaitTask
+ let filePath = document.FilePath
let results =
HashSet(errors, errorInfoEqualityComparer)
diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs
index 64007b19de8..c335caf30d4 100644
--- a/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs
+++ b/vsintegration/src/FSharp.Editor/Diagnostics/SimplifyNameDiagnosticAnalyzer.fs
@@ -51,7 +51,7 @@ type internal SimplifyNameDiagnosticAnalyzer
| _ ->
let! sourceText = document.GetTextAsync()
let checker = checkerProvider.Checker
- let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName=userOpName)
+ let! _, checkResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
let! result = SimplifyNames.getSimplifiableNames(checkResults, fun lineNumber -> sourceText.Lines.[Line.toZ lineNumber].ToString()) |> liftAsync
let mutable diag = ResizeArray()
for r in result do
diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs
index 094796c9e36..9448b62b4f0 100644
--- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs
+++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedDeclarationsAnalyzer.fs
@@ -35,7 +35,7 @@ type internal UnusedDeclarationsAnalyzer
| (_parsingOptions, projectOptions) ->
let! sourceText = document.GetTextAsync()
let checker = checkerProvider.Checker
- let! _, _, checkResults = checker.ParseAndCheckDocument(document, projectOptions, userOpName = userOpName)
+ let! _, checkResults = checker.CheckDocumentInProject(document, projectOptions) |> liftAsync
let! unusedRanges = UnusedDeclarations.getUnusedDeclarations( checkResults, (isScriptFile document.FilePath)) |> liftAsync
return
unusedRanges
diff --git a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs
index c63341ecd0a..d22d1627541 100644
--- a/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs
+++ b/vsintegration/src/FSharp.Editor/Diagnostics/UnusedOpensDiagnosticAnalyzer.fs
@@ -29,8 +29,9 @@ type internal UnusedOpensDiagnosticAnalyzer
static member GetUnusedOpenRanges(document: Document, options, checker: FSharpChecker) : Async