From 2c8f9e38bf95ac35567edb7d9e327db1d780c8a3 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 3 May 2020 19:36:40 -0700 Subject: [PATCH 1/4] Clearing cache of projects that are not in the current solution --- src/fsharp/service/service.fs | 11 +++++++++++ src/fsharp/service/service.fsi | 5 +++++ .../FSharpProjectOptionsManager.fs | 19 ++++++++++++++++++- .../LanguageService/LanguageService.fs | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index d170a7a5b2d..d57dac8301f 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 list, userOpName) = + // This operation can't currently be cancelled nor awaited + reactor.EnqueueOp(userOpName, "ClearCache", String.Empty, fun ctok -> + options + |> List.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 list, ?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..e5457c0b83b 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 list * ?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..0bde5027492 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,23 @@ 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)) + |> List.ofSeq + + if not projectsToClearCache.IsEmpty then + projectsToClearCache + |> List.iter (fun pair -> cache.Remove pair.Key |> ignore) + let options = + projectsToClearCache + |> List.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) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index f02f4e344b4..90f0e5df60a 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -63,6 +63,7 @@ type private FSharpSolutionEvents(projectManager: FSharpProjectOptionsManager) = interface IVsSolutionEvents with member __.OnAfterCloseSolution(_) = + projectManager.Checker.StopBackgroundCompile() projectManager.Checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() VSConstants.S_OK From eb31840b21b3dd128eb0c630ead2d4319af4668a Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 3 May 2020 19:39:13 -0700 Subject: [PATCH 2/4] Update LanguageService.fs --- .../src/FSharp.Editor/LanguageService/LanguageService.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs index 90f0e5df60a..f02f4e344b4 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/LanguageService.fs @@ -63,7 +63,6 @@ type private FSharpSolutionEvents(projectManager: FSharpProjectOptionsManager) = interface IVsSolutionEvents with member __.OnAfterCloseSolution(_) = - projectManager.Checker.StopBackgroundCompile() projectManager.Checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() VSConstants.S_OK From be11cbef9990e10b53b68407c8c67519a9fda1fc Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 4 May 2020 12:20:16 -0700 Subject: [PATCH 3/4] Using seq instead of list --- src/fsharp/service/service.fs | 2 +- src/fsharp/service/service.fsi | 2 +- .../LanguageService/FSharpProjectOptionsManager.fs | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index d57dac8301f..b1a55aad4e5 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -846,7 +846,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC if startBackgroundCompileIfAlreadySeen then bc.CheckProjectInBackground(options, userOpName + ".StartBackgroundCompile")) - member bc.ClearCache(options : FSharpProjectOptions list, userOpName) = + 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 diff --git a/src/fsharp/service/service.fsi b/src/fsharp/service/service.fsi index e5457c0b83b..365805ca8c6 100755 --- a/src/fsharp/service/service.fsi +++ b/src/fsharp/service/service.fsi @@ -361,7 +361,7 @@ type public FSharpChecker = /// 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 list * ?userOpName: string -> unit + 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 0bde5027492..5818a5a1b16 100644 --- a/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs +++ b/vsintegration/src/FSharp.Editor/LanguageService/FSharpProjectOptionsManager.fs @@ -213,14 +213,13 @@ type private FSharpProjectOptionsReactor (workspace: Workspace, settings: Editor let projectsToClearCache = cache |> Seq.filter (fun pair -> not (currentSolution.ContainsProject pair.Key)) - |> List.ofSeq - if not projectsToClearCache.IsEmpty then + if not (Seq.isEmpty projectsToClearCache) then projectsToClearCache - |> List.iter (fun pair -> cache.Remove pair.Key |> ignore) + |> Seq.iter (fun pair -> cache.Remove pair.Key |> ignore) let options = projectsToClearCache - |> List.map (fun pair -> + |> Seq.map (fun pair -> let _, _, projectOptions = pair.Value projectOptions) checkerProvider.Checker.ClearCache(options, userOpName = "tryComputeOptions") From fdc9304a8116d527baaf5dc91c74a726dca162bb Mon Sep 17 00:00:00 2001 From: Will Smith Date: Mon, 4 May 2020 12:25:32 -0700 Subject: [PATCH 4/4] Fixed build --- src/fsharp/service/service.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fsharp/service/service.fs b/src/fsharp/service/service.fs index b1a55aad4e5..bfb074eede8 100644 --- a/src/fsharp/service/service.fs +++ b/src/fsharp/service/service.fs @@ -850,7 +850,7 @@ type BackgroundCompiler(legacyReferenceResolver, projectCacheSize, keepAssemblyC // This operation can't currently be cancelled nor awaited reactor.EnqueueOp(userOpName, "ClearCache", String.Empty, fun ctok -> options - |> List.iter (fun options -> incrementalBuildersCache.RemoveAnySimilar(ctok, options))) + |> Seq.iter (fun options -> incrementalBuildersCache.RemoveAnySimilar(ctok, options))) member __.NotifyProjectCleaned (options : FSharpProjectOptions, userOpName) = reactor.EnqueueAndAwaitOpAsync(userOpName, "NotifyProjectCleaned", options.ProjectFileName, fun ctok -> @@ -1149,7 +1149,7 @@ type FSharpChecker(legacyReferenceResolver, backgroundCompiler.InvalidateConfiguration(options, startBackgroundCompile, userOpName) /// Clear the internal cache of the given projects. - member __.ClearCache(options: FSharpProjectOptions list, ?userOpName: string) = + member __.ClearCache(options: FSharpProjectOptions seq, ?userOpName: string) = let userOpName = defaultArg userOpName "Unknown" backgroundCompiler.ClearCache(options, userOpName)