diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index d170a7a5b2d..bfb074eede8 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -846,6 +846,12 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC if startBackgroundCompileIfAlreadySeen then bc.CheckProjectInBackground(options, userOpName + ".StartBackgroundCompile")) + member bc.ClearCache(options : FSharpProjectOptions seq, userOpName) = + // This operation can't currently be cancelled nor awaited + reactor.EnqueueOp(userOpName, "ClearCache", String.Empty, fun ctok -> + options + |> Seq.iter (fun options -> incrementalBuildersCache.RemoveAnySimilar(ctok, options))) + member __.NotifyProjectCleaned (options : FSharpProjectOptions, userOpName) = reactor.EnqueueAndAwaitOpAsync(userOpName, "NotifyProjectCleaned", options.ProjectFileName, fun ctok -> cancellable { @@ -1142,6 +1148,11 @@ type FSharpChecker(legacyReferenceResolver, let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.InvalidateConfiguration(options, startBackgroundCompile, userOpName) + /// Clear the internal cache of the given projects. + member __.ClearCache(options: FSharpProjectOptions seq, ?userOpName: string) = + let userOpName = defaultArg userOpName "Unknown" + backgroundCompiler.ClearCache(options, userOpName) + /// This function is called when a project has been cleaned, and thus type providers should be refreshed. member __.NotifyProjectCleaned(options: FSharpProjectOptions, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi index 330a51adf38..365805ca8c6 100755 --- a/src/fsharp/service/service.fsi +++ b/src/fsharp/service/service.fsi @@ -358,6 +358,11 @@ type public FSharpChecker = /// An optional string used for tracing compiler operations associated with this request. member InvalidateConfiguration: options: FSharpProjectOptions * ?startBackgroundCompileIfAlreadySeen: bool * ?userOpName: string -> unit + /// Clear the internal cache of the given projects. + /// The given project options. + /// An optional string used for tracing compiler operations associated with this request. + member ClearCache: options: FSharpProjectOptions seq * ?userOpName: string -> unit + /// Set the project to be checked in the background. Overrides any previous call to CheckProjectInBackground member CheckProjectInBackground: options: FSharpProjectOptions * ?userOpName: string -> unit diff --git a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs index 085ccfcff9b..5818a5a1b16 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -81,7 +81,7 @@ type private FSharpProjectOptionsMessage = | ClearSingleFileOptionsCache of DocumentId [] -type private FSharpProjectOptionsReactor (_workspace: VisualStudioWorkspace, settings: EditorOptions, _serviceProvider, checkerProvider: FSharpCheckerProvider) = +type private FSharpProjectOptionsReactor (workspace: Workspace, settings: EditorOptions, _serviceProvider, checkerProvider: FSharpCheckerProvider) = let cancellationTokenSource = new CancellationTokenSource() // Hack to store command line options from HandleCommandLineChanges @@ -208,6 +208,22 @@ type private FSharpProjectOptionsReactor (_workspace: VisualStudioWorkspace, set if Array.isEmpty projectOptions.SourceFiles then return None else + // Clear any caches that need clearing and invalidate the project. + let currentSolution = workspace.CurrentSolution + let projectsToClearCache = + cache + |> Seq.filter (fun pair -> not (currentSolution.ContainsProject pair.Key)) + + if not (Seq.isEmpty projectsToClearCache) then + projectsToClearCache + |> Seq.iter (fun pair -> cache.Remove pair.Key |> ignore) + let options = + projectsToClearCache + |> Seq.map (fun pair -> + let _, _, projectOptions = pair.Value + projectOptions) + checkerProvider.Checker.ClearCache(options, userOpName = "tryComputeOptions") + checkerProvider.Checker.InvalidateConfiguration(projectOptions, startBackgroundCompileIfAlreadySeen = false, userOpName = "computeOptions") let parsingOptions, _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions)