Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit72cd439

Browse files
TIHanKevinRansom
authored andcommitted
Small Language Service refactoring (dotnet#5687)
* Started language service refactoring* Updated editor fsproj* Fixed service, should work
1 parentac86fdb commit72cd439

File tree

5 files changed

+487
-429
lines changed

5 files changed

+487
-429
lines changed

‎vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
<CompileInclude="LanguageService\IProjectSite.fs" />
5151
<CompileInclude="LanguageService\ProjectSitesAndFiles.fs" />
5252
<CompileInclude="LanguageService\ProvideFSharpVersionRegistrationAttribute.fs" />
53+
<CompileInclude="LanguageService\FSharpCheckerProvider.fs" />
54+
<CompileInclude="LanguageService\FSharpProjectOptionsManager.fs" />
55+
<CompileInclude="LanguageService\LegacyProjectWorkspaceMap.fs" />
5356
<CompileInclude="LanguageService\LanguageService.fs" />
5457
<CompileInclude="LanguageService\AssemblyContentProvider.fs" />
5558
<CompileInclude="LanguageService\SymbolHelpers.fs" />
@@ -152,7 +155,7 @@
152155
<PackageReferenceInclude="Microsoft.VisualStudio.Text.UI.Wpf"Version="$(MicrosoftVisualStudioTextUIWpfPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
153156
<PackageReferenceInclude="Microsoft.VisualStudio.TextManager.Interop"Version="$(MicrosoftVisualStudioTextManagerInteropPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
154157
<PackageReferenceInclude="Microsoft.VisualStudio.TextManager.Interop.12.0"Version="$(MicrosoftVisualStudioTextManagerInterop120PackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
155-
<PackageReferenceInclude="Microsoft.VSSDK.BuildTools"Version="$(MicrosoftVSSDKBuildToolsPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
158+
<PackageReferenceInclude="Microsoft.VSSDK.BuildTools"Version="$(MicrosoftVSSDKBuildToolsPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
156159
<PackageReferenceInclude="Newtonsoft.Json"Version="$(NewtonsoftJsonPackageVersion)"PrivateAssets="all"ExcludeAssets="runtime;contentFiles;build;analyzers;native" />
157160
<PackageReferenceInclude="System.Collections.Immutable"Version="$(SystemCollectionsImmutablePackageVersion)" />
158161
<PackageReferenceInclude="System.ValueTuple"Version="$(SystemValueTuplePackageVersion)" />
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
2+
3+
namespaceMicrosoft.VisualStudio.FSharp.Editor
4+
5+
openSystem
6+
openSystem.ComponentModel.Composition
7+
openSystem.Diagnostics
8+
openMicrosoft.CodeAnalysis
9+
openMicrosoft.CodeAnalysis.Diagnostics
10+
openMicrosoft.FSharp.Compiler.SourceCodeServices
11+
openMicrosoft.VisualStudio
12+
openMicrosoft.VisualStudio.FSharp.Editor
13+
openMicrosoft.VisualStudio.LanguageServices
14+
openMicrosoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
15+
openFSharp.NativeInterop
16+
17+
#nowarn"9"// NativePtr.toNativeInt
18+
19+
// Exposes FSharpChecker as MEF export
20+
[<Export(typeof<FSharpCheckerProvider>); Composition.Shared>]
21+
typeinternalFSharpCheckerProvider
22+
[<ImportingConstructor>]
23+
(
24+
analyzerService: IDiagnosticAnalyzerService,
25+
[<Import(typeof<VisualStudioWorkspace>)>] workspace: VisualStudioWorkspaceImpl,
26+
settings: EditorOptions
27+
)=
28+
29+
lettryGetMetadataSnapshot(path,timeStamp)=
30+
try
31+
letmetadataReferenceProvider= workspace.Services.GetService<VisualStudioMetadataReferenceManager>()
32+
letmd= metadataReferenceProvider.GetMetadata(path, timeStamp)
33+
letamd=(md:?> AssemblyMetadata)
34+
letmmd= amd.GetModules().[0]
35+
letmmr= mmd.GetMetadataReader()
36+
37+
// "lifetime is timed to Metadata you got from the GetMetadata(...). As long as you hold it strongly, raw
38+
// memory we got from metadata reader will be alive. Once you are done, just let everything go and
39+
// let finalizer handle resource rather than calling Dispose from Metadata directly. It is shared metadata.
40+
// You shouldn't dispose it directly."
41+
42+
letobjToHold= box md
43+
44+
// We don't expect any ilread WeakByteFile to be created when working in Visual Studio
45+
Debug.Assert((Microsoft.FSharp.Compiler.AbstractIL.ILBinaryReader.GetStatistics().weakByteFileCount=0),"Expected weakByteFileCount to be zero when using F# in Visual Studio. Was there a problem reading a .NET binary?")
46+
47+
Some(objToHold, NativePtr.toNativeInt mmr.MetadataPointer, mmr.MetadataLength)
48+
with ex->
49+
// We catch all and let the backup routines in the F# compiler find the error
50+
Assert.Exception(ex)
51+
None
52+
53+
54+
letchecker=
55+
lazy
56+
letchecker=
57+
FSharpChecker.Create(
58+
projectCacheSize= settings.LanguageServicePerformance.ProjectCheckCacheSize,
59+
keepAllBackgroundResolutions=false,
60+
// Enabling this would mean that if devenv.exe goes above 2.3GB we do a one-off downsize of the F# Compiler Service caches
61+
(* , MaxMemory = 2300*)
62+
legacyReferenceResolver=Microsoft.FSharp.Compiler.MSBuildReferenceResolver.Resolver,
63+
tryGetMetadataSnapshot= tryGetMetadataSnapshot)
64+
65+
// This is one half of the bridge between the F# background builder and the Roslyn analysis engine.
66+
// When the F# background builder refreshes the background semantic build context for a file,
67+
// we request Roslyn to reanalyze that individual file.
68+
checker.BeforeBackgroundFileCheck.Add(fun(fileName,_extraProjectInfo)->
69+
async{
70+
try
71+
letsolution= workspace.CurrentSolution
72+
letdocumentIds= solution.GetDocumentIdsWithFilePath(fileName)
73+
ifnot documentIds.IsEmptythen
74+
letdocumentIdsFiltered= documentIds|> Seq.filter workspace.IsDocumentOpen|> Seq.toArray
75+
for documentIdin documentIdsFiltereddo
76+
Trace.TraceInformation("{0:n3} Requesting Roslyn reanalysis of {1}", DateTime.Now.TimeOfDay.TotalSeconds, documentId)
77+
if documentIdsFiltered.Length>0then
78+
analyzerService.Reanalyze(workspace,documentIds=documentIdsFiltered)
79+
with ex->
80+
Assert.Exception(ex)
81+
}|> Async.StartImmediate
82+
)
83+
checker
84+
85+
memberthis.Checker= checker.Value
86+
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
2+
3+
namespaceMicrosoft.VisualStudio.FSharp.Editor
4+
5+
openSystem
6+
openSystem.Collections.Concurrent
7+
openSystem.Collections.Immutable
8+
openSystem.ComponentModel.Composition
9+
openSystem.IO
10+
openSystem.Linq
11+
openMicrosoft.CodeAnalysis
12+
openMicrosoft.FSharp.Compiler.CompileOps
13+
openMicrosoft.FSharp.Compiler.SourceCodeServices
14+
openMicrosoft.VisualStudio
15+
openMicrosoft.VisualStudio.FSharp.Editor
16+
openMicrosoft.VisualStudio.FSharp.Editor.SiteProvider
17+
openMicrosoft.VisualStudio.LanguageServices
18+
openMicrosoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
19+
openMicrosoft.VisualStudio.Shell
20+
21+
/// Exposes FCS FSharpProjectOptions information management as MEF component.
22+
//
23+
// This service allows analyzers to get an appropriate FSharpProjectOptions value for a project or single file.
24+
// It also allows a 'cheaper' route to get the project options relevant to parsing (e.g. the #define values).
25+
// The main entrypoints are TryGetOptionsForDocumentOrProject and TryGetOptionsForEditingDocumentOrProject.
26+
[<Export(typeof<FSharpProjectOptionsManager>); Composition.Shared>]
27+
typeinternalFSharpProjectOptionsManager
28+
[<ImportingConstructor>]
29+
(
30+
checkerProvider: FSharpCheckerProvider,
31+
[<Import(typeof<VisualStudioWorkspace>)>] workspace: VisualStudioWorkspaceImpl,
32+
[<Import(typeof<SVsServiceProvider>)>] serviceProvider: System.IServiceProvider,
33+
settings: EditorOptions
34+
)=
35+
36+
// A table of information about projects, excluding single-file projects.
37+
letprojectOptionsTable= FSharpProjectOptionsTable()
38+
39+
// A table of information about single-file projects. Currently we only need the load time of each such file, plus
40+
// the original options for editing
41+
letsingleFileProjectTable= ConcurrentDictionary<ProjectId, DateTime* FSharpParsingOptions* FSharpProjectOptions>()
42+
43+
lettryGetOrCreateProjectId(projectFileName:string)=
44+
letprojectDisplayName= projectDisplayNameOf projectFileName
45+
Some(workspace.ProjectTracker.GetOrCreateProjectIdForPath(projectFileName, projectDisplayName))
46+
47+
/// Retrieve the projectOptionsTable
48+
member__.FSharpOptions= projectOptionsTable
49+
50+
/// Clear a project from the project table
51+
memberthis.ClearInfoForProject(projectId:ProjectId)= projectOptionsTable.ClearInfoForProject(projectId)
52+
53+
/// Clear a project from the single file project table
54+
memberthis.ClearInfoForSingleFileProject(projectId)=
55+
singleFileProjectTable.TryRemove(projectId)|> ignore
56+
57+
/// Update a project in the single file project table
58+
memberthis.AddOrUpdateSingleFileProject(projectId,data)= singleFileProjectTable.[projectId]<- data
59+
60+
/// Get the exact options for a single-file script
61+
memberthis.ComputeSingleFileOptions(tryGetOrCreateProjectId,fileName,loadTime,fileContents)=
62+
async{
63+
letextraProjectInfo= Some(box workspace)
64+
if SourceFile.MustBeSingleFileProject(fileName)then
65+
// NOTE: we don't use a unique stamp for single files, instead comparing options structurally.
66+
// This is because we repeatedly recompute the options.
67+
letoptionsStamp= None
68+
let!options,_diagnostics= checkerProvider.Checker.GetProjectOptionsFromScript(fileName, fileContents, loadTime,[||], ?extraProjectInfo=extraProjectInfo, ?optionsStamp=optionsStamp)
69+
// NOTE: we don't use FCS cross-project references from scripts to projects. THe projects must have been
70+
// compiled and #r will refer to files on disk
71+
letreferencedProjectFileNames=[||]
72+
letsite= ProjectSitesAndFiles.CreateProjectSiteForScript(fileName, referencedProjectFileNames, options)
73+
letdeps,projectOptions= ProjectSitesAndFiles.GetProjectOptionsForProjectSite(settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider,(tryGetOrCreateProjectId fileName), fileName, options.ExtraProjectInfo, Some projectOptionsTable)
74+
letparsingOptions,_= checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions)
75+
return(deps, parsingOptions, projectOptions)
76+
else
77+
letsite= ProjectSitesAndFiles.ProjectSiteOfSingleFile(fileName)
78+
letdeps,projectOptions= ProjectSitesAndFiles.GetProjectOptionsForProjectSite(settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider,(tryGetOrCreateProjectId fileName), fileName, extraProjectInfo, Some projectOptionsTable)
79+
letparsingOptions,_= checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions)
80+
return(deps, parsingOptions, projectOptions)
81+
}
82+
83+
/// Update the info for a project in the project table
84+
memberthis.UpdateProjectInfo(tryGetOrCreateProjectId,projectId,site,userOpName,invalidateConfig)=
85+
Logger.Log LogEditorFunctionId.LanguageService_UpdateProjectInfo
86+
projectOptionsTable.AddOrUpdateProject(projectId,(fun isRefresh->
87+
letextraProjectInfo= Some(box workspace)
88+
letreferencedProjects,projectOptions= ProjectSitesAndFiles.GetProjectOptionsForProjectSite(settings.LanguageServicePerformance.EnableInMemoryCrossProjectReferences, site, serviceProvider, Some(projectId), site.ProjectFileName, extraProjectInfo, Some projectOptionsTable)
89+
if invalidateConfigthen checkerProvider.Checker.InvalidateConfiguration(projectOptions, startBackgroundCompileIfAlreadySeen=not isRefresh, userOpName= userOpName+".UpdateProjectInfo")
90+
letreferencedProjectIds= referencedProjects|> Array.choose tryGetOrCreateProjectId
91+
letparsingOptions,_= checkerProvider.Checker.GetParsingOptionsFromProjectOptions(projectOptions)
92+
referencedProjectIds, parsingOptions, Some site, projectOptions))
93+
94+
/// Get compilation defines relevant for syntax processing.
95+
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project
96+
/// options for a script.
97+
memberthis.GetCompilationDefinesForEditingDocument(document:Document)=
98+
letprojectOptionsOpt= this.TryGetOptionsForProject(document.Project.Id)
99+
letparsingOptions=
100+
match projectOptionsOptwith
101+
| Some(parsingOptions,_site,_projectOptions)-> parsingOptions
102+
|_->{ FSharpParsingOptions.Defaultwith IsInteractive= IsScript document.Name}
103+
CompilerEnvironment.GetCompilationDefinesForEditing parsingOptions
104+
105+
/// Try and get the Options for a project
106+
memberthis.TryGetOptionsForProject(projectId:ProjectId)= projectOptionsTable.TryGetOptionsForProject(projectId)
107+
108+
/// Get the exact options for a document or project
109+
memberthis.TryGetOptionsForDocumentOrProject(document:Document)=
110+
async{
111+
letprojectId= document.Project.Id
112+
113+
// The options for a single-file script project are re-requested each time the file is analyzed. This is because the
114+
// single-file project may contain #load and #r references which are changing as the user edits, and we may need to re-analyze
115+
// to determine the latest settings. FCS keeps a cache to help ensure these are up-to-date.
116+
match singleFileProjectTable.TryGetValue(projectId)with
117+
|true,(loadTime,_,_)->
118+
try
119+
letfileName= document.FilePath
120+
let!cancellationToken= Async.CancellationToken
121+
let!sourceText= document.GetTextAsync(cancellationToken)|> Async.AwaitTask
122+
// NOTE: we don't use FCS cross-project references from scripts to projects. The projects must have been
123+
// compiled and #r will refer to files on disk.
124+
lettryGetOrCreateProjectId _= None
125+
let!_referencedProjectFileNames,parsingOptions,projectOptions= this.ComputeSingleFileOptions(tryGetOrCreateProjectId, fileName, loadTime, sourceText.ToString())
126+
this.AddOrUpdateSingleFileProject(projectId,(loadTime, parsingOptions, projectOptions))
127+
return Some(parsingOptions, None, projectOptions)
128+
with ex->
129+
Assert.Exception(ex)
130+
return None
131+
|_->return this.TryGetOptionsForProject(projectId)
132+
}
133+
134+
/// Get the options for a document or project relevant for syntax processing.
135+
/// Quicker then TryGetOptionsForDocumentOrProject as it doesn't need to recompute the exact project options for a script.
136+
memberthis.TryGetOptionsForEditingDocumentOrProject(document:Document)=
137+
letprojectId= document.Project.Id
138+
match singleFileProjectTable.TryGetValue(projectId)with
139+
|true,(_loadTime, parsingOptions, originalOptions)-> Some(parsingOptions, originalOptions)
140+
|_-> this.TryGetOptionsForProject(projectId)|> Option.map(fun(parsingOptions,_,projectOptions)-> parsingOptions, projectOptions)
141+
142+
/// get a siteprovider
143+
memberthis.ProvideProjectSiteProvider(project:Project)= provideProjectSiteProvider(workspace, project, serviceProvider, Some projectOptionsTable)
144+
145+
/// Tell the checker to update the project info for the specified project id
146+
memberthis.UpdateProjectInfoWithProjectId(projectId:ProjectId,userOpName,invalidateConfig)=
147+
lethier= workspace.GetHierarchy(projectId)
148+
match hierwith
149+
|null->()
150+
| hwhen(h.IsCapabilityMatch("CPS"))->
151+
letproject= workspace.CurrentSolution.GetProject(projectId)
152+
ifnot(isNull project)then
153+
letsiteProvider= this.ProvideProjectSiteProvider(project)
154+
letprojectSite= siteProvider.GetProjectSite()
155+
if projectSite.CompilationSourceFiles.Length<>0then
156+
this.UpdateProjectInfo(tryGetOrCreateProjectId, projectId, projectSite, userOpName, invalidateConfig)
157+
|_->()
158+
159+
/// Tell the checker to update the project info for the specified project id
160+
memberthis.UpdateDocumentInfoWithProjectId(projectId:ProjectId,documentId:DocumentId,userOpName,invalidateConfig)=
161+
if workspace.IsDocumentOpen(documentId)then
162+
this.UpdateProjectInfoWithProjectId(projectId, userOpName, invalidateConfig)
163+
164+
[<Export>]
165+
/// This handles commandline change notifications from the Dotnet Project-system
166+
/// Prior to VS 15.7 path contained path to project file, post 15.7 contains target binpath
167+
/// binpath is more accurate because a project file can have multiple in memory projects based on configuration
168+
memberthis.HandleCommandLineChanges(path:string,sources:ImmutableArray<CommandLineSourceFile>,references:ImmutableArray<CommandLineReference>,options:ImmutableArray<string>)=
169+
use _logBlock= Logger.LogBlock(LogEditorFunctionId.LanguageService_HandleCommandLineArgs)
170+
171+
letprojectId=
172+
match workspace.ProjectTracker.TryGetProjectByBinPath(path)with
173+
|true, project-> project.Id
174+
|false,_-> workspace.ProjectTracker.GetOrCreateProjectIdForPath(path, projectDisplayNameOf path)
175+
letproject= workspace.ProjectTracker.GetProject(projectId)
176+
letpath= project.ProjectFilePath
177+
letfullPath p=
178+
if Path.IsPathRooted(p)|| path=nullthen p
179+
else Path.Combine(Path.GetDirectoryName(path), p)
180+
letsourcePaths= sources|> Seq.map(fun s-> fullPath s.Path)|> Seq.toArray
181+
letreferencePaths= references|> Seq.map(fun r-> fullPath r.Reference)|> Seq.toArray
182+
183+
projectOptionsTable.SetOptionsWithProjectId(projectId, sourcePaths, referencePaths, options.ToArray())
184+
this.UpdateProjectInfoWithProjectId(projectId,"HandleCommandLineChanges", invalidateConfig=true)
185+
186+
member__.Checker= checkerProvider.Checker

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp