@@ -15,17 +15,16 @@ open System.Linq
15
15
open System.Runtime .CompilerServices
16
16
open System.Runtime .InteropServices
17
17
open System.Threading
18
-
19
- open Microsoft.FSharp .Compiler .CompileOps
20
- open Microsoft.FSharp .Compiler .SourceCodeServices
21
- open Microsoft.VisualStudio .FSharp .LanguageService .SiteProvider
22
-
23
18
open Microsoft.CodeAnalysis
24
19
open Microsoft.CodeAnalysis .Diagnostics
25
20
open Microsoft.CodeAnalysis .Completion
26
21
open Microsoft.CodeAnalysis .Options
22
+ open Microsoft.FSharp .Compiler .CompileOps
23
+ open Microsoft.FSharp .Compiler .SourceCodeServices
27
24
open Microsoft.VisualStudio
28
25
open Microsoft.VisualStudio .Editor
26
+ open Microsoft.VisualStudio .FSharp .LanguageService
27
+ open Microsoft.VisualStudio .FSharp .LanguageService .SiteProvider
29
28
open Microsoft.VisualStudio .TextManager .Interop
30
29
open Microsoft.VisualStudio .LanguageServices
31
30
open Microsoft.VisualStudio .LanguageServices .Implementation .LanguageService
@@ -34,10 +33,9 @@ open Microsoft.VisualStudio.LanguageServices.Implementation.TaskList
34
33
open Microsoft.VisualStudio .LanguageServices .ProjectSystem
35
34
open Microsoft.VisualStudio .Shell
36
35
open Microsoft.VisualStudio .Shell .Interop
37
- open Microsoft.VisualStudio .FSharp .LanguageService
38
36
open Microsoft.VisualStudio .ComponentModelHost
39
37
40
- // Exposes FSharpChecker as MEF export
38
+ /// Exposes FSharpChecker as MEF export
41
39
[<Export( typeof< FSharpCheckerProvider>); Composition.Shared>]
42
40
type internal FSharpCheckerProvider
43
41
[<ImportingConstructor>]
@@ -84,12 +82,12 @@ type internal FSharpCheckerProvider
84
82
85
83
86
84
/// Exposes FCS FSharpProjectOptions information management as MEF component.
87
- //
88
- // This service allows analyzers to get an appropriate FSharpProjectOptions value for a project or single file.
89
- // It also allows a 'cheaper' route to get the project options relevant to parsing (e.g. the #define values).
90
- // The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject.
85
+ ///
86
+ /// This service allows analyzers to get an appropriate FSharpProjectOptions value for a project or single file.
87
+ /// It also allows a 'cheaper' route to get the project options relevant to parsing (e.g. the #define values).
88
+ /// The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject.
91
89
[<Export( typeof< FSharpProjectOptionsManager>); Composition.Shared>]
92
- type internal FSharpProjectOptionsManager
90
+ type internal FSharpProjectOptionsManager
93
91
[<ImportingConstructor>]
94
92
(
95
93
checkerProvider: FSharpCheckerProvider,
@@ -114,33 +112,36 @@ type internal FSharpProjectOptionsManager
114
112
/// Clear a project from the project table
115
113
member this.ClearInfoForProject ( projectId : ProjectId ) = projectOptionsTable.ClearInfoForProject( projectId)
116
114
115
+ /// Clear a project from the single file project table
117
116
member this.ClearInfoForSingleFileProject ( projectId ) =
118
117
singleFileProjectTable.TryRemove( projectId) |> ignore
119
118
119
+ /// Update a project in the single file project table
120
120
member this.AddOrUpdateSingleFileProject ( projectId , data ) = singleFileProjectTable.[ projectId] <- data
121
121
122
122
/// Get the exact options for a single-file script
123
- member this.ComputeSingleFileOptions ( tryGetOrCreateProjectId , fileName , loadTime , fileContents , workspace : Workspace ) = async {
124
- let extraProjectInfo = Some( box workspace)
125
- let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject |> Option.map( fun ( _ , _ , projectOptions ) -> projectOptions)
126
- if SourceFile.MustBeSingleFileProject( fileName) then
127
- // NOTE: we don't use a unique stamp for single files, instead comparing options structurally.
128
- // This is because we repeatedly recompute the options.
129
- let optionsStamp = None
130
- let! options , _diagnostics = checkerProvider.Checker.GetProjectOptionsFromScript( fileName, fileContents, loadTime, [| |], ?extraProjectInfo= extraProjectInfo, ?optionsStamp= optionsStamp)
131
- // NOTE: we don't use FCS cross-project references from scripts to projects. THe projects must have been
132
- // compiled and #r will refer to files on disk
133
- let referencedProjectFileNames = [| |]
134
- let site = ProjectSitesAndFiles.CreateProjectSiteForScript( fileName, referencedProjectFileNames, options)
135
- let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, options.ExtraProjectInfo, Some projectOptionsTable, true )
136
- let parsingOptions , _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions( projectOptions)
137
- return ( deps, parsingOptions, projectOptions)
138
- else
139
- let site = ProjectSitesAndFiles.ProjectSiteOfSingleFile( fileName)
140
- let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, extraProjectInfo, Some projectOptionsTable, true )
141
- let parsingOptions , _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions( projectOptions)
142
- return ( deps, parsingOptions, projectOptions)
143
- }
123
+ member this.ComputeSingleFileOptions ( tryGetOrCreateProjectId , fileName , loadTime , fileContents ) =
124
+ async {
125
+ let extraProjectInfo = Some( box workspace)
126
+ let tryGetOptionsForReferencedProject f = f |> tryGetOrCreateProjectId |> Option.bind this.TryGetOptionsForProject |> Option.map( fun ( _ , _ , projectOptions ) -> projectOptions)
127
+ if SourceFile.MustBeSingleFileProject( fileName) then
128
+ // NOTE: we don't use a unique stamp for single files, instead comparing options structurally.
129
+ // This is because we repeatedly recompute the options.
130
+ let optionsStamp = None
131
+ let! options , _diagnostics = checkerProvider.Checker.GetProjectOptionsFromScript( fileName, fileContents, loadTime, [| |], ?extraProjectInfo= extraProjectInfo, ?optionsStamp= optionsStamp)
132
+ // NOTE: we don't use FCS cross-project references from scripts to projects. THe projects must have been
133
+ // compiled and #r will refer to files on disk
134
+ let referencedProjectFileNames = [| |]
135
+ let site = ProjectSitesAndFiles.CreateProjectSiteForScript( fileName, referencedProjectFileNames, options)
136
+ let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, options.ExtraProjectInfo, Some projectOptionsTable, true )
137
+ let parsingOptions , _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions( projectOptions)
138
+ return ( deps, parsingOptions, projectOptions)
139
+ else
140
+ let site = ProjectSitesAndFiles.ProjectSiteOfSingleFile( fileName)
141
+ let deps , projectOptions = ProjectSitesAndFiles.GetProjectOptionsForProjectSite( Settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, tryGetOptionsForReferencedProject, site, serviceProvider, ( tryGetOrCreateProjectId fileName), fileName, extraProjectInfo, Some projectOptionsTable, true )
142
+ let parsingOptions , _ = checkerProvider.Checker.GetParsingOptionsFromProjectOptions( projectOptions)
143
+ return ( deps, parsingOptions, projectOptions)
144
+ }
144
145
145
146
/// Update the info for a project in the project table
146
147
member this.UpdateProjectInfo ( tryGetOrCreateProjectId , projectId , site , userOpName ) =
@@ -164,32 +165,34 @@ type internal FSharpProjectOptionsManager
164
165
| _ -> FSharpParsingOptions.Default
165
166
CompilerEnvironment.GetCompilationDefinesForEditing( document.Name, parsingOptions)
166
167
168
+ /// Try and get the Options for a project
167
169
member this.TryGetOptionsForProject ( projectId : ProjectId ) = projectOptionsTable.TryGetOptionsForProject( projectId)
168
170
169
171
/// Get the exact options for a document or project
170
- member this.TryGetOptionsForDocumentOrProject ( document : Document ) = async {
171
- let projectId = document.Project.Id
172
-
173
- // The options for a single-file script project are re-requested each time the file is analyzed. This is because the
174
- // single-file project may contain #load and #r references which are changing as the user edits, and we may need to re-analyze
175
- // to determine the latest settings. FCS keeps a cache to help ensure these are up-to-date.
176
- match singleFileProjectTable.TryGetValue( projectId) with
177
- | true , ( loadTime, _, _) ->
178
- try
179
- let fileName = document.FilePath
180
- let! cancellationToken = Async.CancellationToken
181
- let! sourceText = document.GetTextAsync( cancellationToken) |> Async.AwaitTask
182
- // NOTE: we don't use FCS cross-project references from scripts to projects. The projects must have been
183
- // compiled and #r will refer to files on disk.
184
- let tryGetOrCreateProjectId _ = None
185
- let! _referencedProjectFileNames , parsingOptions , projectOptions = this.ComputeSingleFileOptions ( tryGetOrCreateProjectId, fileName, loadTime, sourceText.ToString(), document.Project.Solution.Workspace)
186
- this.AddOrUpdateSingleFileProject( projectId, ( loadTime, parsingOptions, projectOptions))
187
- return Some ( parsingOptions, None, projectOptions)
188
- with ex ->
189
- Assert.Exception( ex)
190
- return None
191
- | _ -> return this.TryGetOptionsForProject( projectId)
192
- }
172
+ member this.TryGetOptionsForDocumentOrProject ( document : Document ) =
173
+ async {
174
+ let projectId = document.Project.Id
175
+
176
+ // The options for a single-file script project are re-requested each time the file is analyzed. This is because the
177
+ // single-file project may contain #load and #r references which are changing as the user edits, and we may need to re-analyze
178
+ // to determine the latest settings. FCS keeps a cache to help ensure these are up-to-date.
179
+ match singleFileProjectTable.TryGetValue( projectId) with
180
+ | true , ( loadTime, _, _) ->
181
+ try
182
+ let fileName = document.FilePath
183
+ let! cancellationToken = Async.CancellationToken
184
+ let! sourceText = document.GetTextAsync( cancellationToken) |> Async.AwaitTask
185
+ // NOTE: we don't use FCS cross-project references from scripts to projects. The projects must have been
186
+ // compiled and #r will refer to files on disk.
187
+ let tryGetOrCreateProjectId _ = None
188
+ let! _referencedProjectFileNames , parsingOptions , projectOptions = this.ComputeSingleFileOptions ( tryGetOrCreateProjectId, fileName, loadTime, sourceText.ToString())
189
+ this.AddOrUpdateSingleFileProject( projectId, ( loadTime, parsingOptions, projectOptions))
190
+ return Some ( parsingOptions, None, projectOptions)
191
+ with ex ->
192
+ Assert.Exception( ex)
193
+ return None
194
+ | _ -> return this.TryGetOptionsForProject( projectId)
195
+ }
193
196
194
197
/// Get the options for a document or project relevant for syntax processing.
195
198
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project options for a script.
540
543
let projectDisplayName = projectDisplayNameOf projectFileName
541
544
542
545
let projectId = workspace.ProjectTracker.GetOrCreateProjectIdForPath( projectFileName, projectDisplayName)
543
- let _referencedProjectFileNames , parsingOptions , projectOptions = projectInfoManager.ComputeSingleFileOptions ( tryGetOrCreateProjectId workspace, fileName, loadTime, fileContents, workspace ) |> Async.RunSynchronously
546
+ let _referencedProjectFileNames , parsingOptions , projectOptions = projectInfoManager.ComputeSingleFileOptions ( tryGetOrCreateProjectId workspace, fileName, loadTime, fileContents) |> Async.RunSynchronously
544
547
projectInfoManager.AddOrUpdateSingleFileProject( projectId, ( loadTime, parsingOptions, projectOptions))
545
548
546
549
if isNull ( workspace.ProjectTracker.GetProject projectId) then
0 commit comments