-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Add metadata documents to the MAS workspace upfront #78886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
758b375
to
a7e6b19
Compare
_keyToInformation.Clear(); | ||
} | ||
|
||
private static (ProjectInfo, DocumentId) GenerateProjectAndDocumentInfo( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved from metadataassourcegeneratedfileinfo
@@ -50,15 +46,10 @@ internal sealed class DecompilationMetadataAsSourceFileProvider(IImplementationA | |||
/// generally run concurrently. However, to be safe, we make this a concurrent dictionary to be safe to that | |||
/// potentially happening. | |||
/// </summary> | |||
private readonly ConcurrentDictionary<string, MetadataAsSourceGeneratedFileInfo> _generatedFilenameToInformation = new(StringComparer.OrdinalIgnoreCase); | |||
private readonly ConcurrentDictionary<string, (MetadataAsSourceGeneratedFileInfo Metadata, DocumentId DocumentId)> _generatedFilenameToInformation = new(StringComparer.OrdinalIgnoreCase); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might it make sense for MetadataAsSourceGeneratedFileInfo to contain the DocId? or is that not possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't immediately straightforward as the MetadataAsSourceGeneratedFileInfo is created before we create the document (and stored in a separate map). However, I am changing all this a bit more for the virtual file part - so I'll include this feedback in that PR if it ends up working.
src/Features/Core/Portable/MetadataAsSource/MetadataAsSourceFileService.cs
Show resolved
Hide resolved
@@ -383,50 +371,6 @@ public bool ShouldCollapseOnOpen(MetadataAsSourceWorkspace workspace, string fil | |||
return _fileToDocumentInfoMap.TryGetValue(filePath, out _) && blockStructureOptions.CollapseMetadataImplementationsWhenFirstOpened; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm beginning to wonder why _fileToDocumentInfoMap needs to exist at all -- couldn't that now just be centrally held?
@@ -51,15 +50,6 @@ internal sealed class LspMiscellaneousFilesWorkspaceProvider(ILspServices lspSer | |||
documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri.ParsedUri); | |||
} | |||
|
|||
var container = new StaticSourceTextContainer(documentText); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we delete StaticSourceTextContainer too?
workspace.GetService<LspWorkspaceRegistrationService>().Register(workspace); | ||
// By default, workspace event listeners are disabled in tests. Explicitly enable the LSP workspace registration event listener | ||
// to ensure that the lsp workspace registration service sees all workspaces. | ||
var lspWorkspaceRegistrationListener = (LspWorkspaceRegistrationEventListener)workspace.ExportProvider.GetExports<IEventListener>().Single(e => e.Value is LspWorkspaceRegistrationEventListener).Value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var lspWorkspaceRegistrationListener = (LspWorkspaceRegistrationEventListener)workspace.ExportProvider.GetExports<IEventListener>().Single(e => e.Value is LspWorkspaceRegistrationEventListener).Value; | |
var lspWorkspaceRegistrationListener = (LspWorkspaceRegistrationEventListener)workspace.ExportProvider.GetExportedValues<IEventListener>().Single(e => e is LspWorkspaceRegistrationEventListener); |
Since there's not any metadata you're checking before creating everything anyways.
@@ -364,7 +365,11 @@ internal LspTestWorkspace CreateWorkspace( | |||
composition ?? Composition, workspaceKind, configurationOptions: new WorkspaceConfigurationOptions(ValidateCompilationTrackerStates: true), supportsLspMutation: mutatingLspWorkspace); | |||
options?.OptionUpdater?.Invoke(workspace.GetService<IGlobalOptionService>()); | |||
|
|||
workspace.GetService<LspWorkspaceRegistrationService>().Register(workspace); | |||
// By default, workspace event listeners are disabled in tests. Explicitly enable the LSP workspace registration event listener |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels a bit fishy that we're not enabling the listeners generally, but I appreciate this makes the code behave a bit more like the product rather than the explicit registration going on. Should we have a tracking bug to investigate this further though?
@@ -1022,7 +1022,7 @@ await RunTestAsync(async path => | |||
var file = await service.GetGeneratedFileAsync(project.Solution.Workspace, project, symbol, signaturesOnly: false, options: MetadataAsSourceOptions.Default, cancellationToken: CancellationToken.None); | |||
|
|||
var result = service.TryRemoveDocumentFromWorkspace(file.FilePath); | |||
Assert.False(result); | |||
Assert.True(result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this still be returning false? I'd assume we don't say we removed something if we didn't add it in the first place? It seems like this is missing a different return for the "if not open" case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is deleted in the followup (open doesn't always make sense here)
#79023
|
||
// We do own the file, so let's open it up in our workspace | ||
(var projectInfo, documentId) = fileInfo.GetProjectInfoAndDocumentId(workspace.Services.SolutionServices, loadFileFromDisk: true); | ||
workspace.OnDocumentClosed(documentIdInfo.DocumentId, new WorkspaceFileTextLoader(workspace.Services.SolutionServices, fileInfo.TemporaryFilePath, MetadataAsSourceGeneratedFileInfo.Encoding)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have to do that check for open files here?
.GetRequiredDocument(temporaryDocumentId); | ||
|
||
if (useDecompiler) | ||
// Generate the file if it doesn't exist (we may still have it if there was a previous request for it that was then closed). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I admit it's not clear to me the scenario for this comment...
} | ||
|
||
// Mark read-only | ||
new FileInfo(fileInfo.TemporaryFilePath).IsReadOnly = true; | ||
if (!skipWritingFile && !File.Exists(fileInfo.TemporaryFilePath)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're still under the !File.Exists() check you added on line 100 in the new version; isn't that part always true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is guarding against the file going away in between (though there is technically a mutex held there so not sure if it could)? I changed this in the followup though
Precursor to changes to allow LSP to use virtual files for MAS. This modifies the MAS providers to put the generated document into the workspace upfront, instead of waiting for someone to attempt to open it. This does mean that we may keep files in the workspace for longer, but generally we were keeping the project and file info around anyway in order to service requests when the document is re-opened. We can remove those separate stores and just use the workspace as the document holder.
Additionally, this simplifies the current LSP MAS implementation (now the MAS workspace is just a normal workspace which we pull documents from), and will simplify the virtual file implementation (virtual files will be stored as documents in the workspace that LSP can query as it normally does). Will be working on that in a followup
Resolves #78421
Clean RPS - https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/644402