@@ -25,12 +25,12 @@ open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList
2525[<AutoOpen>]
2626module private FSharpProjectOptionsHelpers =
2727
28- let mapProjectToSite ( workspace : VisualStudioWorkspaceImpl , project : Project , serviceProvider : System.IServiceProvider , projectOptionsTable : FSharpProjectOptionsTable option ) =
28+ let mapCpsProjectToSite ( workspace : VisualStudioWorkspaceImpl , project : Project , serviceProvider : System.IServiceProvider , cpsCommandLineOptions : IDictionary < ProjectId , DateTime * string [] * string [] * string []> )=
2929let hier = workspace.GetHierarchy( project.Id)
3030let getCommandLineOptionsWithProjectId ( projectId ) =
31- match projectOptionsTable with
32- | Some ( options) -> options.GetCommandLineOptionsWithProjectId ( projectId )
33- | None -> [||], [||], [||]
31+ match cpsCommandLineOptions.TryGetValue ( projectId ) with
32+ | true , (_, sourcePaths , referencePaths , options) -> sourcePaths , referencePaths , options
33+ | false , _ -> [||], [||], [||]
3434{
3535new IProvideProjectSitewith
3636member x.GetProjectSite () =
@@ -88,9 +88,12 @@ type private FSharpProjectOptionsMessage =
8888| ClearOptionsof ProjectId
8989
9090[<Sealed>]
91- type private FSharpProjectOptionsReactor ( workspace : VisualStudioWorkspaceImpl , settings : EditorOptions , optionsTable : FSharpProjectOptionsTable , serviceProvider , checkerProvider : FSharpCheckerProvider ) =
91+ type private FSharpProjectOptionsReactor ( workspace : VisualStudioWorkspaceImpl , settings : EditorOptions , serviceProvider , checkerProvider : FSharpCheckerProvider ) =
9292let cancellationTokenSource = new CancellationTokenSource()
9393
94+ // Hack to store command line options from HandleCommandLineChanges
95+ let cpsCommandLineOptions = new ConcurrentDictionary< ProjectId, DateTime* string[] * string[] * string[]>()
96+
9497let cache = Dictionary< ProjectId, VersionStamp* FSharpParsingOptions* FSharpProjectOptions>()
9598
9699let rec tryComputeOptions ( project : Project ) =
@@ -130,9 +133,11 @@ type private FSharpProjectOptionsReactor (workspace: VisualStudioWorkspaceImpl,
130133let hier = workspace.GetHierarchy( projectId)
131134let projectSite =
132135match hierwith
136+ // Legacy
133137| (:? IProvideProjectSiteas provideSite) -> provideSite.GetProjectSite()
138+ // Cps
134139| _ ->
135- let provideSite = mapProjectToSite ( workspace, project, serviceProvider, Some ( optionsTable ) )
140+ let provideSite = mapCpsProjectToSite ( workspace, project, serviceProvider, cpsCommandLineOptions )
136141 provideSite.GetProjectSite()
137142
138143let projectOptions =
@@ -192,6 +197,14 @@ type private FSharpProjectOptionsReactor (workspace: VisualStudioWorkspaceImpl,
192197member __.ClearOptionsByProjectId ( projectId ) =
193198 agent.Post( FSharpProjectOptionsMessage.ClearOptions( projectId))
194199
200+ member __.SetCpsCommandLineOptions ( projectId , stamp , sourcePaths , referencePaths , options ) =
201+ cpsCommandLineOptions.[ projectId] <- ( stamp, sourcePaths, referencePaths, options)
202+
203+ member __.TryGetCachedOptionsByProjectId ( projectId ) =
204+ match cache.TryGetValue( projectId) with
205+ | true , result-> Some( result)
206+ | _ -> None
207+
195208interface IDisposablewith
196209member __.Dispose () =
197210 cancellationTokenSource.Cancel()
@@ -213,19 +226,12 @@ type internal FSharpProjectOptionsManager
213226 settings: EditorOptions
214227) =
215228
216- // A table of information about projects, excluding single-file projects.
217- let projectOptionsTable = FSharpProjectOptionsTable()
218-
219- let reactor = new FSharpProjectOptionsReactor( workspace, settings, projectOptionsTable, serviceProvider, checkerProvider)
229+ let reactor = new FSharpProjectOptionsReactor( workspace, settings, serviceProvider, checkerProvider)
220230
221231// A table of information about single-file projects. Currently we only need the load time of each such file, plus
222232// the original options for editing
223233let singleFileProjectTable = ConcurrentDictionary< ProjectId, DateTime* FSharpParsingOptions* FSharpProjectOptions>()
224234
225- let tryGetOrCreateProjectId ( projectFileName : string ) =
226- let projectDisplayName = projectDisplayNameOf projectFileName
227- Some( workspace.ProjectTracker.GetOrCreateProjectIdForPath( projectFileName, projectDisplayName))
228-
229235do
230236// We need to listen to this event for lifecycle purposes.
231237 workspace.WorkspaceChanged.Add( fun args ->
@@ -234,12 +240,8 @@ type internal FSharpProjectOptionsManager
234240| _ -> ()
235241)
236242
237- /// Retrieve the projectOptionsTable
238- member __.FSharpOptions = projectOptionsTable
239-
240243/// Clear a project from the project table
241244member this.ClearInfoForProject ( projectId : ProjectId ) =
242- projectOptionsTable.ClearInfoForProject( projectId)
243245 reactor.ClearOptionsByProjectId( projectId)
244246
245247/// Clear a project from the single file project table
@@ -262,40 +264,28 @@ type internal FSharpProjectOptionsManager
262264// compiled and #r will refer to files on disk
263265let referencedProjectFileNames = [| |]
264266let site = ProjectSitesAndFiles.CreateProjectSiteForScript( fileName, referencedProjectFileNames, options)
265- let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, options.ExtraProjectInfo, solution, Some projectOptionsTable )
267+ let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, options.ExtraProjectInfo, solution, None )
266268let parsingOptions , _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions( projectOptions)
267269return ( deps, parsingOptions, projectOptions)
268270else
269271let site = ProjectSitesAndFiles.ProjectSiteOfSingleFile( fileName)
270- let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, extraProjectInfo, solution, Some projectOptionsTable )
272+ let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, extraProjectInfo, solution, None )
271273let parsingOptions , _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions( projectOptions)
272274return ( deps, parsingOptions, projectOptions)
273275}
274276
275- /// Update the info for a project in the project table
276- member this.UpdateProjectInfo ( tryGetOrCreateProjectId , projectId , site , userOpName , invalidateConfig , solution ) =
277- Logger.Log LogEditorFunctionId.LanguageService_ UpdateProjectInfo
278- projectOptionsTable.AddOrUpdateProject( projectId, ( fun isRefresh ->
279- let extraProjectInfo = Some( box workspace)
280- let referencedProjects , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider, Some( projectId), site.ProjectFileName, extraProjectInfo, solution, Some projectOptionsTable)
281- if invalidateConfigthen checkerProvider.Checker.InvalidateConfiguration( projectOptions, startBackgroundCompileIfAlreadySeen= not isRefresh, userOpName= userOpName+ " .UpdateProjectInfo" )
282- let referencedProjectIds = referencedProjects|> Array.choose tryGetOrCreateProjectId
283- let parsingOptions , _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions( projectOptions)
284- referencedProjectIds, parsingOptions, Some site, projectOptions))
285-
286277/// Get compilation defines relevant for syntax processing.
287278/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project
288279/// options for a script.
289280member this.GetCompilationDefinesForEditingDocument ( document : Document ) =
290- let projectOptionsOpt = this.TryGetOptionsForProject( document.Project.Id)
291- let parsingOptions =
292- match projectOptionsOptwith
293- | Some( parsingOptions, _ site, _ projectOptions) -> parsingOptions
281+ let parsingOptions =
282+ match reactor.TryGetCachedOptionsByProjectId( document.Project.Id) with
283+ | Some(_, parsingOptions, _) -> parsingOptions
294284| _ -> { FSharpParsingOptions.Defaultwith IsInteractive= IsScript document.Name}
295- CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
285+ CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
296286
297- /// Try and get the Options for a project
298- member this.TryGetOptionsForProject ( projectId : ProjectId ) = projectOptionsTable.TryGetOptionsForProject ( projectId )
287+ member this.TryGetOptionsByProject ( project ) =
288+ reactor.TryGetOptionsByProjectAsync ( project )
299289
300290/// Get the exact options for a document or project
301291member this.TryGetOptionsForDocumentOrProject ( document : Document ) =
@@ -340,33 +330,11 @@ type internal FSharpProjectOptionsManager
340330return result|> Option.map( fun ( parsingOptions , _ , projectOptions ) -> parsingOptions, projectOptions)
341331}
342332
343- /// get a siteprovider
344- member this.ProvideProjectSiteProvider ( project : Project ) = provideProjectSiteProvider( workspace, project, serviceProvider, Some projectOptionsTable)
345-
346- /// Tell the checker to update the project info for the specified project id
347- member this.UpdateProjectInfoWithProjectId ( projectId : ProjectId , userOpName , invalidateConfig , solution ) =
348- let hier = workspace.GetHierarchy( projectId)
349- match hierwith
350- | null -> ()
351- | hwhen ( h.IsCapabilityMatch( " CPS" )) ->
352- let project = workspace.CurrentSolution.GetProject( projectId)
353- if not ( isNull project) then
354- let siteProvider = this.ProvideProjectSiteProvider( project)
355- let projectSite = siteProvider.GetProjectSite()
356- if projectSite.CompilationSourceFiles.Length<> 0 then
357- this.UpdateProjectInfo( tryGetOrCreateProjectId, projectId, projectSite, userOpName, invalidateConfig, solution)
358- | _ -> ()
359-
360- /// Tell the checker to update the project info for the specified project id
361- member this.UpdateDocumentInfoWithProjectId ( projectId : ProjectId , documentId : DocumentId , userOpName , invalidateConfig , solution ) =
362- if workspace.IsDocumentOpen( documentId) then
363- this.UpdateProjectInfoWithProjectId( projectId, userOpName, invalidateConfig, solution)
364-
365333[<Export>]
366334/// This handles commandline change notifications from the Dotnet Project-system
367335/// Prior to VS 15.7 path contained path to project file, post 15.7 contains target binpath
368336/// binpath is more accurate because a project file can have multiple in memory projects based on configuration
369- member this .HandleCommandLineChanges( path : string , sources : ImmutableArray < CommandLineSourceFile >, references : ImmutableArray < CommandLineReference >, options : ImmutableArray < string >) =
337+ member __ .HandleCommandLineChanges( path : string , sources : ImmutableArray < CommandLineSourceFile >, references : ImmutableArray < CommandLineReference >, options : ImmutableArray < string >) =
370338use _logBlock= Logger.LogBlock( LogEditorFunctionId.LanguageService_ HandleCommandLineArgs)
371339
372340let projectId =
@@ -381,6 +349,6 @@ type internal FSharpProjectOptionsManager
381349let sourcePaths = sources|> Seq.map( fun s -> fullPath s.Path) |> Seq.toArray
382350let referencePaths = references|> Seq.map( fun r -> fullPath r.Reference) |> Seq.toArray
383351
384- projectOptionsTable.SetOptionsWithProjectId ( projectId, sourcePaths, referencePaths, options.ToArray())
352+ reactor.SetCpsCommandLineOptions ( projectId, DateTime.UtcNow , sourcePaths, referencePaths, options.ToArray())
385353
386354member __.Checker = checkerProvider.Checker