From 2a3ca24db247fc1259432d74c71793408a1d43bb Mon Sep 17 00:00:00 2001 From: David Barbet Date: Wed, 8 Jan 2025 17:52:12 -0800 Subject: [PATCH 1/9] Do not parse URIs during LSP serialization/deserialization --- .../Api/AbstractVSTypeScriptRequestHandler.cs | 2 +- .../AbstractLanguageServerProtocolTests.cs | 31 ++-- src/Features/Lsif/Generator/Generator.cs | 2 +- .../GeneratorTest/ProjectStructureTests.vb | 2 +- ...operSdkLspServiceDocumentRequestHandler.cs | 2 +- .../LspFileChangeWatcherTests.cs | 4 +- .../ServerInitializationTests.cs | 2 +- .../FileWatching/LspFileChangeWatcher.cs | 4 +- .../Razor/RazorDynamicFileChangedHandler.cs | 4 +- ...cFileInfoProvider.TextChangesTextLoader.cs | 5 +- .../Razor/RazorDynamicFileInfoProvider.cs | 8 +- .../WorkspaceDebugConfigurationHandler.cs | 5 +- .../WorkspaceDebugConfigurationParams.cs | 2 +- .../Protocol/Extensions/Extensions.cs | 45 ++++-- .../ProtocolConversions.Diagnostics.cs | 2 +- .../Extensions/ProtocolConversions.cs | 37 +++-- .../Extensions/SourceGeneratedDocumentUri.cs | 5 +- .../Razor/FormatNewFileHandler.cs | 5 +- .../Protocol/Handler/AbstractRefreshQueue.cs | 9 +- .../CodeActions/CodeActionResolveHelper.cs | 2 +- .../AbstractGoToDefinitionHandler.cs | 2 +- .../AbstractProjectDiagnosticSource.cs | 2 +- .../Handler/DocumentChanges/DidOpenHandler.cs | 4 +- .../Handler/IDocumentChangeTracker.cs | 13 +- .../Handler/MapCode/MapCodeHandler.cs | 8 +- .../References/FindUsagesLSPContext.cs | 4 +- .../Protocol/Handler/RequestContext.cs | 14 +- .../Protocol/Handler/RequestContextFactory.cs | 6 +- .../SemanticTokensRefreshQueue.cs | 2 +- .../SourceGeneratorRefreshQueue.cs | 2 +- .../Protocol/ILanguageInfoProvider.cs | 3 +- .../Protocol/LanguageInfoProvider.cs | 7 +- .../Protocol/Protocol/CodeDescription.cs | 4 +- .../Protocol/Protocol/ConfigurationItem.cs | 2 +- .../Converters/DocumentUriConverter.cs | 12 +- .../Protocol/Converters/SumConverter.cs | 9 +- .../Protocol/Protocol/CreateFile.cs | 2 +- .../Protocol/Protocol/DeleteFile.cs | 2 +- .../Protocol/Protocol/DocumentLink.cs | 2 +- .../Protocol/Protocol/DocumentUri.cs | 137 ++++++++++++++++++ .../Protocol/FileOperations/FileCreate.cs | 2 +- .../Protocol/FileOperations/FileDelete.cs | 2 +- .../Protocol/FileOperations/FileEvent.cs | 2 +- .../Protocol/FileOperations/FileRename.cs | 4 +- .../FileOperations/RelativePattern.cs | 2 +- .../Protocol/Protocol/InitializeParams.cs | 2 +- .../Protocol/Protocol/Location.cs | 6 +- .../Protocol/Protocol/LocationLink.cs | 7 +- .../Protocol/Navigation/CallHierarchyItem.cs | 2 +- .../Protocol/Navigation/TypeHierarchyItem.cs | 2 +- .../Protocol/Notebook/NotebookCell.cs | 2 +- .../Protocol/Protocol/PreviousResultId.cs | 2 +- .../Protocol/PublishDiagnosticParams.cs | 2 +- .../Protocol/Protocol/RenameFile.cs | 4 +- .../Protocol/TextDocumentIdentifier.cs | 6 +- .../Protocol/Protocol/TextDocumentItem.cs | 2 +- .../Protocol/Protocol/WorkspaceFolder.cs | 2 +- .../WorkspaceFullDocumentDiagnosticReport.cs | 2 +- .../Protocol/WorkspaceSymbolLocation.cs | 2 +- ...kspaceUnchangedDocumentDiagnosticReport.cs | 2 +- .../Protocol/RoslynLanguageServer.cs | 11 +- .../LspMiscellaneousFilesWorkspace.cs | 18 ++- .../Workspaces/LspWorkspaceManager.cs | 89 +++--------- .../CodeActions/CodeActionResolveTests.cs | 8 +- .../Definitions/GoToDefinitionTests.cs | 8 +- .../Definitions/GoToTypeDefinitionTests.cs | 5 +- .../AbstractPullDiagnosticTestsBase.cs | 4 +- .../AdditionalFileDiagnosticsTests.cs | 8 +- .../Diagnostics/PullDiagnosticTests.cs | 16 +- .../WorkspaceProjectDiagnosticsTests.cs | 4 +- .../DocumentChangesTests.LinkedDocuments.cs | 2 +- .../DocumentChanges/DocumentChangesTests.cs | 7 +- .../FormatNewFile/FormatNewFileTests.cs | 4 +- .../Formatting/FormatDocumentTests.cs | 5 +- .../ProtocolUnitTests/HandlerTests.cs | 20 +-- .../LanguageServerTargetTests.cs | 4 +- .../ProtocolUnitTests/MapCode/MapCodeTests.cs | 2 +- .../LspMetadataAsSourceWorkspaceTests.cs | 5 +- .../LspMiscellaneousFilesWorkspaceTests.cs | 25 ++-- .../Ordering/RequestOrderingTests.cs | 2 +- .../GetTextDocumentWithContextHandlerTests.cs | 5 +- .../ProtocolConversionsTests.cs | 40 ++--- .../References/FindImplementationsTests.cs | 2 +- .../RelatedDocuments/RelatedDocumentsTests.cs | 2 +- .../ProtocolUnitTests/Rename/RenameTests.cs | 2 +- .../SpellCheck/SpellCheckTests.cs | 12 +- .../ProtocolUnitTests/UriTests.cs | 76 +++++++--- .../VSTypeScriptHandlerTests.cs | 5 +- .../Workspaces/LspWorkspaceManagerTests.cs | 17 ++- .../SourceGeneratedDocumentUriTests.cs | 8 +- ...stractRazorCohostDocumentRequestHandler.cs | 2 +- .../Razor/Cohost/RazorCohostRequestContext.cs | 6 +- src/Tools/ExternalAccess/Razor/RazorUri.cs | 5 + .../Razor/SolutionExtensions.cs | 5 +- .../Razor/TextDocumentExtensions.cs | 4 + .../Xaml/External/ResolveDataConversions.cs | 10 +- .../Xaml/External/XamlRequestHandlerBase.cs | 3 +- .../DocumentOutlineViewModel_Utilities.cs | 2 +- .../RoslynSearchResultViewFactory.cs | 4 +- .../Client/RemoteLanguageServiceWorkspace.cs | 7 +- .../LiveShare/Test/ProjectsHandlerTests.cs | 2 +- .../Definitions/GoToDefinitionHandler.cs | 8 +- .../XamlRequestExecutionQueue.cs | 3 +- 103 files changed, 581 insertions(+), 368 deletions(-) create mode 100644 src/LanguageServer/Protocol/Protocol/DocumentUri.cs diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs index bb128f92430dd..46b559222fb7c 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs @@ -31,7 +31,7 @@ internal abstract class AbstractVSTypeScriptRequestHandler @@ -159,7 +160,7 @@ private protected static int CompareLocations(LSP.Location? l1, LSP.Location? l2 if (l2 is null) return 1; - var compareDocument = l1.Uri.AbsoluteUri.CompareTo(l2.Uri.AbsoluteUri); + var compareDocument = l1.Uri.UriString.CompareTo(l2.Uri.UriString); var compareRange = CompareRange(l1.Range, l2.Range); return compareDocument != 0 ? compareDocument : compareRange; } @@ -206,7 +207,7 @@ internal static LSP.SymbolInformation CreateSymbolInformation(LSP.SymbolKind kin return info; } - private protected static LSP.TextDocumentIdentifier CreateTextDocumentIdentifier(Uri uri, ProjectId? projectContext = null) + private protected static LSP.TextDocumentIdentifier CreateTextDocumentIdentifier(DocumentUri uri, ProjectId? projectContext = null) { var documentIdentifier = new LSP.VSTextDocumentIdentifier { Uri = uri }; @@ -474,7 +475,7 @@ protected static async Task RemoveGeneratorAsync(AnalyzerReference reference, Ed return locations; - static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText text, Uri documentUri) + static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText text, DocumentUri documentUri) { var location = new LSP.Location { @@ -500,7 +501,7 @@ private static string GetDocumentFilePathFromName(string documentName) => "C:\\" + documentName; private static LSP.DidChangeTextDocumentParams CreateDidChangeTextDocumentParams( - Uri documentUri, + DocumentUri documentUri, ImmutableArray<(LSP.Range Range, string Text)> changes) { var changeEvents = changes.Select(change => new LSP.TextDocumentContentChangeEvent @@ -519,7 +520,7 @@ private static LSP.DidChangeTextDocumentParams CreateDidChangeTextDocumentParams }; } - private static LSP.DidOpenTextDocumentParams CreateDidOpenTextDocumentParams(Uri uri, string source, string languageId = "") + private static LSP.DidOpenTextDocumentParams CreateDidOpenTextDocumentParams(DocumentUri uri, string source, string languageId = "") => new LSP.DidOpenTextDocumentParams { TextDocument = new LSP.TextDocumentItem @@ -530,7 +531,7 @@ private static LSP.DidOpenTextDocumentParams CreateDidOpenTextDocumentParams(Uri } }; - private static LSP.DidCloseTextDocumentParams CreateDidCloseTextDocumentParams(Uri uri) + private static LSP.DidCloseTextDocumentParams CreateDidCloseTextDocumentParams(DocumentUri uri) => new LSP.DidCloseTextDocumentParams() { TextDocument = new LSP.TextDocumentIdentifier @@ -650,14 +651,14 @@ private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Str return languageServer; } - public async Task GetDocumentAsync(Uri uri) + public async Task GetDocumentAsync(DocumentUri uri) { var document = await GetCurrentSolution().GetDocumentAsync(new LSP.TextDocumentIdentifier { Uri = uri }, CancellationToken.None).ConfigureAwait(false); Contract.ThrowIfNull(document, $"Unable to find document with {uri} in solution"); return document; } - public async Task GetDocumentTextAsync(Uri uri) + public async Task GetDocumentTextAsync(DocumentUri uri) { var document = await GetDocumentAsync(uri).ConfigureAwait(false); return await document.GetTextAsync(CancellationToken.None).ConfigureAwait(false); @@ -692,7 +693,7 @@ public Task ExecutePreSerializedRequestAsync(string methodName, JsonDocument ser return _clientRpc.InvokeWithParameterObjectAsync(methodName, serializedRequest); } - public async Task OpenDocumentAsync(Uri documentUri, string? text = null, string languageId = "") + public async Task OpenDocumentAsync(DocumentUri documentUri, string? text = null, string languageId = "") { if (text == null) { @@ -706,7 +707,7 @@ public async Task OpenDocumentAsync(Uri documentUri, string? text = null, string await ExecuteRequestAsync(LSP.Methods.TextDocumentDidOpenName, didOpenParams, CancellationToken.None); } - public Task ReplaceTextAsync(Uri documentUri, params (LSP.Range Range, string Text)[] changes) + public Task ReplaceTextAsync(DocumentUri documentUri, params (LSP.Range Range, string Text)[] changes) { var didChangeParams = CreateDidChangeTextDocumentParams( documentUri, @@ -714,7 +715,7 @@ public Task ReplaceTextAsync(Uri documentUri, params (LSP.Range Range, string Te return ExecuteRequestAsync(LSP.Methods.TextDocumentDidChangeName, didChangeParams, CancellationToken.None); } - public Task InsertTextAsync(Uri documentUri, params (int Line, int Column, string Text)[] changes) + public Task InsertTextAsync(DocumentUri documentUri, params (int Line, int Column, string Text)[] changes) { return ReplaceTextAsync(documentUri, [.. changes.Select(change => (new LSP.Range { @@ -723,7 +724,7 @@ public Task InsertTextAsync(Uri documentUri, params (int Line, int Column, strin }, change.Text))]); } - public Task DeleteTextAsync(Uri documentUri, params (int StartLine, int StartColumn, int EndLine, int EndColumn)[] changes) + public Task DeleteTextAsync(DocumentUri documentUri, params (int StartLine, int StartColumn, int EndLine, int EndColumn)[] changes) { return ReplaceTextAsync(documentUri, [.. changes.Select(change => (new LSP.Range { @@ -732,7 +733,7 @@ public Task DeleteTextAsync(Uri documentUri, params (int StartLine, int StartCol }, string.Empty))]); } - public Task CloseDocumentAsync(Uri documentUri) + public Task CloseDocumentAsync(DocumentUri documentUri) { var didCloseParams = CreateDidCloseTextDocumentParams(documentUri); return ExecuteRequestAsync(LSP.Methods.TextDocumentDidCloseName, didCloseParams, CancellationToken.None); @@ -790,7 +791,7 @@ internal async Task WaitForDiagnosticsAsync() internal T GetRequiredLspService() where T : class, ILspService => LanguageServer.GetTestAccessor().GetRequiredLspService(); - internal ImmutableArray GetTrackedTexts() => [.. GetManager().GetTrackedLspText().Values.Select(v => v.Text)]; + internal ImmutableArray GetTrackedTexts() => [.. GetManager().GetTrackedLspText().Values.Select(v => v.SourceText)]; internal Task RunCodeAnalysisAsync(ProjectId? projectId) => _codeAnalysisService.RunAnalysisAsync(GetCurrentSolution(), projectId, onAfterProjectAnalyzed: _ => { }, CancellationToken.None); diff --git a/src/Features/Lsif/Generator/Generator.cs b/src/Features/Lsif/Generator/Generator.cs index 354e412cf2d71..5d25333aba60b 100644 --- a/src/Features/Lsif/Generator/Generator.cs +++ b/src/Features/Lsif/Generator/Generator.cs @@ -212,7 +212,7 @@ public async Task GenerateForProjectAsync( var contentBase64Encoded = await GetBase64EncodedContentAsync(document, cancellationToken); - var documentVertex = new Graph.LsifDocument(document.GetURI(), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); + var documentVertex = new Graph.LsifDocument(document.GetURI().GetRequiredParsedUri(), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); lsifJsonWriter.Write(documentVertex); lsifJsonWriter.Write(new Event(Event.EventKind.Begin, documentVertex.GetId(), idFactory)); diff --git a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb index 3b7f729aaf3f5..07854f60ea5c3 100644 --- a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb +++ b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb @@ -76,7 +76,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests Await TestLsifOutput.GenerateForWorkspaceAsync(workspace, New LineModeLsifJsonWriter(stringWriter)) Dim generatedDocument = Assert.Single(Await workspace.CurrentSolution.Projects.Single().GetSourceGeneratedDocumentsAsync()) - Dim uri = SourceGeneratedDocumentUri.Create(generatedDocument.Identity) + Dim uri = SourceGeneratedDocumentUri.Create(generatedDocument.Identity).GetRequiredParsedUri() Dim outputText = stringWriter.ToString() Assert.Contains(uri.AbsoluteUri, outputText) End Function diff --git a/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Handler/AbstractCompilerDeveloperSdkLspServiceDocumentRequestHandler.cs b/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Handler/AbstractCompilerDeveloperSdkLspServiceDocumentRequestHandler.cs index 1d7899ee3ce37..8a730ba669fb0 100644 --- a/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Handler/AbstractCompilerDeveloperSdkLspServiceDocumentRequestHandler.cs +++ b/src/LanguageServer/ExternalAccess/CompilerDeveloperSDK/Handler/AbstractCompilerDeveloperSdkLspServiceDocumentRequestHandler.cs @@ -22,7 +22,7 @@ internal abstract class AbstractCompilerDeveloperSdkLspServiceDocumentRequestHan bool ISolutionRequiredHandler.RequiresLSPSolution => RequiresLSPSolution; TextDocumentIdentifier ITextDocumentIdentifierHandler.GetTextDocumentIdentifier(TRequest request) - => new() { Uri = GetTextDocumentIdentifier(request) }; + => new() { Uri = new(GetTextDocumentIdentifier(request)) }; Task IRequestHandler.HandleRequestAsync(TRequest request, LspRequestContext context, CancellationToken cancellationToken) => HandleRequestAsync(request, new RequestContext(context), cancellationToken); } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs index 900cf1a438c89..ba46122a93977 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/LspFileChangeWatcherTests.cs @@ -62,7 +62,7 @@ public async Task CreatingDirectoryWatchRequestsDirectoryWatch() var watcher = GetSingleFileWatcher(dynamicCapabilitiesRpcTarget); - Assert.Equal(tempDirectory.Path, watcher.GlobPattern.Second.BaseUri.Second.LocalPath); + Assert.Equal(tempDirectory.Path, watcher.GlobPattern.Second.BaseUri.Second.GetRequiredParsedUri().LocalPath); Assert.Equal("**/*", watcher.GlobPattern.Second.Pattern); // Get rid of the registration and it should be gone again @@ -93,7 +93,7 @@ public async Task CreatingFileWatchRequestsFileWatch() var watcher = GetSingleFileWatcher(dynamicCapabilitiesRpcTarget); - Assert.Equal("Z:\\", watcher.GlobPattern.Second.BaseUri.Second.LocalPath); + Assert.Equal("Z:\\", watcher.GlobPattern.Second.BaseUri.Second.GetRequiredParsedUri().LocalPath); Assert.Equal("SingleFile.txt", watcher.GlobPattern.Second.Pattern); // Get rid of the registration and it should be gone again diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs index c66971d44d5c0..2264a03f0cf11 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs @@ -18,7 +18,7 @@ public ServerInitializationTests(ITestOutputHelper testOutputHelper) : base(test public async Task TestServerHandlesTextSyncRequestsAsync() { await using var server = await CreateLanguageServerAsync(); - var document = new VersionedTextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteUri("C:\\\ue25b\ud86d\udeac.cs") }; + var document = new VersionedTextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteDocumentUri("C:\\\ue25b\ud86d\udeac.cs") }; var response = await server.ExecuteRequestAsync(Methods.TextDocumentDidOpenName, new DidOpenTextDocumentParams { TextDocument = new TextDocumentItem diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs index c21b47a23e803..e8f469f8ad7aa 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/FileWatching/LspFileChangeWatcher.cs @@ -104,7 +104,7 @@ private void WatchedFilesHandler_OnNotificationRaised(object? sender, DidChangeW { foreach (var changedFile in e.Changes) { - var filePath = changedFile.Uri.LocalPath; + var filePath = changedFile.Uri.GetRequiredParsedUri().LocalPath; // Unfortunately the LSP protocol doesn't give us any hint of which of the file watches we might have sent to the client // was the one that registered for this change, so we have to check paths to see if this one we should respond to. @@ -152,7 +152,7 @@ public IWatchedFile EnqueueWatchingFile(string filePath) // TODO: figure out how I just can do an absolute path watch GlobPattern = new RelativePattern { - BaseUri = ProtocolConversions.CreateAbsoluteUri(Path.GetDirectoryName(filePath)!), + BaseUri = ProtocolConversions.CreateAbsoluteDocumentUri(Path.GetDirectoryName(filePath)!), Pattern = Path.GetFileName(filePath) } }; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs index 48c1c3fa8595f..0cbacfb133105 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileChangedHandler.cs @@ -5,6 +5,7 @@ using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; @@ -27,7 +28,8 @@ public RazorDynamicFileChangedHandler(RazorDynamicFileInfoProvider razorDynamicF public Task HandleNotificationAsync(RazorDynamicFileChangedParams request, RequestContext requestContext, CancellationToken cancellationToken) { - var filePath = ProtocolConversions.GetDocumentFilePathFromUri(request.RazorDocument.Uri); + var parsedUri = request.RazorDocument.Uri.GetRequiredParsedUri(); + var filePath = ProtocolConversions.GetDocumentFilePathFromUri(parsedUri); _razorDynamicFileInfoProvider.Update(filePath); return Task.CompletedTask; } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs index 0f62d58b1d221..57647dff70919 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.TextChangesTextLoader.cs @@ -6,6 +6,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; @@ -18,14 +19,14 @@ private sealed class TextChangesTextLoader( byte[] checksum, SourceHashAlgorithm checksumAlgorithm, int? codePage, - Uri razorUri) : TextLoader + DocumentUri razorUri) : TextLoader { private readonly TextDocument? _document = document; private readonly IEnumerable _updates = updates; private readonly byte[] _checksum = checksum; private readonly SourceHashAlgorithm _checksumAlgorithm = checksumAlgorithm; private readonly int? _codePage = codePage; - private readonly Uri _razorUri = razorUri; + private readonly DocumentUri _razorUri = razorUri; private readonly Lazy _emptySourceText = new Lazy(() => { diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs index b064fb31132c3..cbc34022c4cf2 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/Razor/RazorDynamicFileInfoProvider.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.LanguageServer.LanguageServer; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.Razor; @@ -55,7 +56,7 @@ public void Update(string filePath) { _razorWorkspaceListenerInitializer.Value.NotifyDynamicFile(projectId); - var razorUri = ProtocolConversions.CreateAbsoluteUri(filePath); + var razorUri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); var requestParams = new RazorProvideDynamicFileParams { RazorDocument = new() @@ -77,7 +78,8 @@ public void Update(string filePath) // Since we only sent one file over, we should get either zero or one URI back var responseUri = response.CSharpDocument.Uri; - var dynamicFileInfoFilePath = ProtocolConversions.GetDocumentFilePathFromUri(responseUri); + var parsedUri = responseUri.GetRequiredParsedUri(); + var dynamicFileInfoFilePath = ProtocolConversions.GetDocumentFilePathFromUri(parsedUri); if (response.Updates is not null) { @@ -113,7 +115,7 @@ public Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFileP { CSharpDocument = new() { - Uri = ProtocolConversions.CreateAbsoluteUri(filePath) + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath) } }; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationHandler.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationHandler.cs index a04adfd9c4bda..52e3845ae942e 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationHandler.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationHandler.cs @@ -4,6 +4,7 @@ using System.Composition; using Microsoft.CodeAnalysis.Host.Mef; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.DebugConfiguration; @@ -38,9 +39,9 @@ public Task HandleRequestAsync(WorkspaceDebugConfig return Task.FromResult(projects); } - private static bool IsProjectInWorkspace(Uri workspacePath, Project project) + private static bool IsProjectInWorkspace(DocumentUri workspacePath, Project project) { - return PathUtilities.IsSameDirectoryOrChildOf(project.FilePath!, workspacePath.LocalPath); + return PathUtilities.IsSameDirectoryOrChildOf(project.FilePath!, workspacePath.GetRequiredParsedUri().LocalPath); } private ProjectDebugConfiguration GetProjectDebugConfiguration(Project project) diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationParams.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationParams.cs index ac806d4fe897b..33bb843dc842c 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationParams.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServer/Handler/DebugConfiguration/WorkspaceDebugConfigurationParams.cs @@ -8,4 +8,4 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.DebugConfiguration; internal record WorkspaceDebugConfigurationParams( - [property: JsonPropertyName("workspacePath"), JsonConverter(typeof(DocumentUriConverter))] Uri WorkspacePath); + [property: JsonPropertyName("workspacePath"), JsonConverter(typeof(DocumentUriConverter))] DocumentUri WorkspacePath); diff --git a/src/LanguageServer/Protocol/Extensions/Extensions.cs b/src/LanguageServer/Protocol/Extensions/Extensions.cs index adc965d671f6f..bdb2cad3fd85b 100644 --- a/src/LanguageServer/Protocol/Extensions/Extensions.cs +++ b/src/LanguageServer/Protocol/Extensions/Extensions.cs @@ -23,19 +23,19 @@ namespace Microsoft.CodeAnalysis.LanguageServer { internal static partial class Extensions { - public static Uri GetURI(this TextDocument document) + public static DocumentUri GetURI(this TextDocument document) { Contract.ThrowIfNull(document.FilePath); return document is SourceGeneratedDocument sourceGeneratedDocument ? SourceGeneratedDocumentUri.Create(sourceGeneratedDocument.Identity) - : ProtocolConversions.CreateAbsoluteUri(document.FilePath); + : ProtocolConversions.CreateAbsoluteDocumentUri(document.FilePath); } /// /// Generate the Uri of a document by replace the name in file path using the document's name. /// Used to generate the correct Uri when rename a document, because calling doesn't update the file path. /// - public static Uri GetUriForRenamedDocument(this TextDocument document) + public static DocumentUri GetUriForRenamedDocument(this TextDocument document) { Contract.ThrowIfNull(document.FilePath); Contract.ThrowIfNull(document.Name); @@ -44,10 +44,10 @@ public static Uri GetUriForRenamedDocument(this TextDocument document) Contract.ThrowIfNull(directoryName); var path = Path.Combine(directoryName, document.Name); - return ProtocolConversions.CreateAbsoluteUri(path); + return ProtocolConversions.CreateAbsoluteDocumentUri(path); } - public static Uri CreateUriForDocumentWithoutFilePath(this TextDocument document) + public static DocumentUri CreateUriForDocumentWithoutFilePath(this TextDocument document) { Contract.ThrowIfNull(document.Name); Contract.ThrowIfNull(document.Project.FilePath); @@ -55,14 +55,20 @@ public static Uri CreateUriForDocumentWithoutFilePath(this TextDocument document var projectDirectoryName = Path.GetDirectoryName(document.Project.FilePath); Contract.ThrowIfNull(projectDirectoryName); var path = Path.Combine([projectDirectoryName, .. document.Folders, document.Name]); - return ProtocolConversions.CreateAbsoluteUri(path); + return ProtocolConversions.CreateAbsoluteDocumentUri(path); + } + + public static Uri GetRequiredParsedUri(this DocumentUri documentUri) + { + Contract.ThrowIfNull(documentUri.ParsedUri, $"URI {documentUri} could not be parsed"); + return documentUri.ParsedUri; } /// /// Get all regular and additional s for the given . /// This will not return source generated documents. /// - public static ImmutableArray GetTextDocuments(this Solution solution, Uri documentUri) + public static ImmutableArray GetTextDocuments(this Solution solution, DocumentUri documentUri) { var documentIds = GetDocumentIds(solution, documentUri); @@ -73,16 +79,23 @@ public static ImmutableArray GetTextDocuments(this Solution soluti return documents; } - public static ImmutableArray GetDocumentIds(this Solution solution, Uri documentUri) + public static ImmutableArray GetDocumentIds(this Solution solution, DocumentUri documentUri) { + if (documentUri.ParsedUri is null) + { + // If we were given an unparse-able URI, just search for documents with the full URI string. + // For example the miscellaneous workspace stores these kinds of documents with the full URI string. + return solution.GetDocumentIdsWithFilePath(documentUri.UriString); + } + // If this is not our special scheme for generated documents, then we can just look for documents with that file path. - if (documentUri.Scheme != SourceGeneratedDocumentUri.Scheme) - return solution.GetDocumentIdsWithFilePath(ProtocolConversions.GetDocumentFilePathFromUri(documentUri)); + if (documentUri.ParsedUri.Scheme != SourceGeneratedDocumentUri.Scheme) + return solution.GetDocumentIdsWithFilePath(ProtocolConversions.GetDocumentFilePathFromUri(documentUri.ParsedUri)); // We can get a null documentId if we were unable to find the project associated with the // generated document - this can happen if say a project is unloaded. There may be LSP requests // already in-flight which may ask for a generated document from that project. So we return null - var documentId = SourceGeneratedDocumentUri.DeserializeIdentity(solution, documentUri)?.DocumentId; + var documentId = SourceGeneratedDocumentUri.DeserializeIdentity(solution, documentUri.ParsedUri)?.DocumentId; return documentId is not null ? [documentId] : []; } @@ -103,7 +116,7 @@ public static ImmutableArray GetDocumentIds(this Solution solution, public static async ValueTask GetTextDocumentAsync(this Solution solution, TextDocumentIdentifier documentIdentifier, CancellationToken cancellationToken) { // If it's the URI scheme for source generated files, delegate to our other helper, otherwise we can handle anything else here. - if (documentIdentifier.Uri.Scheme == SourceGeneratedDocumentUri.Scheme) + if (documentIdentifier.Uri.ParsedUri?.Scheme == SourceGeneratedDocumentUri.Scheme) { // In the case of a URI scheme for source generated files, we generate a different URI for each project, thus this URI cannot be linked into multiple projects; // this means we can safely call .SingleOrDefault() and not worry about calling FindDocumentInProjectContext. @@ -164,7 +177,13 @@ public static T FindDocumentInProjectContext(this ImmutableArray documents public static Project? GetProject(this Solution solution, TextDocumentIdentifier projectIdentifier) { - var projects = solution.Projects.Where(project => project.FilePath == projectIdentifier.Uri.LocalPath).ToImmutableArray(); + // We need to parse the URI (scheme, file path) to be able to lookup the URI in the solution. + if (projectIdentifier.Uri.ParsedUri is null) + { + return null; + } + + var projects = solution.Projects.Where(project => project.FilePath == projectIdentifier.Uri.ParsedUri.LocalPath).ToImmutableArray(); return !projects.Any() ? null : FindItemInProjectContext(projects, projectIdentifier, projectIdGetter: (item) => item.Id, defaultGetter: () => projects[0]); diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs index 9d084b8076d00..2f09f98c9235f 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs @@ -82,7 +82,7 @@ internal static partial class ProtocolConversions Location = new LSP.Location { Range = GetRange(l), - Uri = ProtocolConversions.CreateAbsoluteUri(l.UnmappedFileSpan.Path) + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(l.UnmappedFileSpan.Path) }, Message = diagnostic.Message }).ToArray(); diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index d4a1eda80a6cb..3080e76318c3c 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text.Json; using System.Text.RegularExpressions; @@ -23,6 +24,7 @@ using Microsoft.CodeAnalysis.SpellCheck; using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; using Roslyn.Text.Adornments; using Roslyn.Utilities; using Logger = Microsoft.CodeAnalysis.Internal.Log.Logger; @@ -106,6 +108,7 @@ public static JsonSerializerOptions AddLspSerializerOptions(this JsonSerializerO { LSP.VSInternalExtensionUtilities.AddVSInternalExtensionConverters(options); options.Converters.Add(new LSP.NaturalObjectConverter()); + options.Converters.Add(new DocumentUriConverter()); return options; } @@ -188,6 +191,7 @@ public static string GetDocumentFilePathFromUri(Uri uri) /// /// Converts an absolute local file path or an absolute URL string to . + /// For use with callers that require specifically a /// /// /// The can't be represented as . @@ -211,7 +215,20 @@ public static Uri CreateAbsoluteUri(string absolutePath) } } - internal static Uri CreateRelativePatternBaseUri(string path) + /// + /// Converts an absolute local file path or an absolute URL string to . + /// For use with callers (generally LSP) that require + /// + /// + /// The can't be represented as . + /// For example, UNC paths with invalid characters in server name. + /// + public static DocumentUri CreateAbsoluteDocumentUri(string absolutePath) + { + return new(CreateAbsoluteUri(absolutePath)); + } + + internal static DocumentUri CreateRelativePatternBaseUri(string path) { // According to VSCode LSP RelativePattern spec, // found at https://github.com/microsoft/vscode/blob/9e1974682eb84eebb073d4ae775bad1738c281f6/src/vscode-dts/vscode.d.ts#L2226 @@ -224,7 +241,7 @@ internal static Uri CreateRelativePatternBaseUri(string path) Debug.Assert(!path.Split(System.IO.Path.DirectorySeparatorChar).Any(p => p == "." || p == "..")); - return CreateAbsoluteUri(path); + return CreateAbsoluteDocumentUri(path); } // Implements workaround for https://github.com/dotnet/runtime/issues/89538: @@ -376,7 +393,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) public static async Task ChangedDocumentsToTextDocumentEditsAsync(IEnumerable changedDocuments, Func getNewDocumentFunc, Func getOldDocumentFunc, IDocumentTextDifferencingService? textDiffService, CancellationToken cancellationToken) where T : TextDocument { - using var _ = ArrayBuilder<(Uri Uri, LSP.TextEdit TextEdit)>.GetInstance(out var uriToTextEdits); + using var _ = ArrayBuilder<(DocumentUri Uri, LSP.TextEdit TextEdit)>.GetInstance(out var uriToTextEdits); foreach (var docId in changedDocuments) { @@ -419,7 +436,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) var textChange = textChanges[i]; if (!mappedSpan.IsDefault) { - uriToTextEdits.Add((CreateAbsoluteUri(mappedSpan.FilePath), new LSP.TextEdit + uriToTextEdits.Add((CreateAbsoluteDocumentUri(mappedSpan.FilePath), new LSP.TextEdit { Range = MappedSpanResultToRange(mappedSpan), NewText = textChange.NewText ?? string.Empty @@ -464,17 +481,17 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) if (mappedSpan.IsDefault) return await ConvertTextSpanToLocationAsync(document, textSpan, isStale, cancellationToken).ConfigureAwait(false); - Uri? uri = null; + DocumentUri? uri = null; try { if (PathUtilities.IsAbsolute(mappedSpan.FilePath)) - uri = CreateAbsoluteUri(mappedSpan.FilePath); + uri = CreateAbsoluteDocumentUri(mappedSpan.FilePath); } catch (UriFormatException) { } - if (uri == null) + if (uri is null) { context?.TraceInformation($"Could not convert '{mappedSpan.FilePath}' to uri"); return null; @@ -508,7 +525,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) return ConvertTextSpanWithTextToLocation(span, text, uri); } - static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText text, Uri documentUri) + static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText text, DocumentUri documentUri) { var location = new LSP.Location { @@ -521,7 +538,9 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText } public static LSP.CodeDescription? HelpLinkToCodeDescription(Uri? uri) - => (uri != null) ? new LSP.CodeDescription { Href = uri } : null; + { + return (uri != null) ? new LSP.CodeDescription { Href = new(uri) } : null; + } public static LSP.SymbolKind NavigateToKindToSymbolKind(string kind) { diff --git a/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs b/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs index c42bc1002eae8..45382429ca582 100644 --- a/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs +++ b/src/LanguageServer/Protocol/Extensions/SourceGeneratedDocumentUri.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Specialized; using System.Linq; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer; @@ -30,7 +31,7 @@ internal static class SourceGeneratedDocumentUri private const string AssemblyPathParam = "assemblyPath"; private const string TypeNameParam = "typeName"; - public static Uri Create(SourceGeneratedDocumentIdentity identity) + public static DocumentUri Create(SourceGeneratedDocumentIdentity identity) { var hintPath = Uri.EscapeDataString(identity.HintName); var projectId = identity.DocumentId.ProjectId.Id.ToString(GuidFormat); @@ -46,7 +47,7 @@ public static Uri Create(SourceGeneratedDocumentIdentity identity) if (identity.Generator.AssemblyPath != null) uri += $"&{AssemblyPathParam}={Uri.EscapeDataString(identity.Generator.AssemblyPath)}"; - return ProtocolConversions.CreateAbsoluteUri(uri); + return ProtocolConversions.CreateAbsoluteDocumentUri(uri); } public static SourceGeneratedDocumentIdentity? DeserializeIdentity(Solution solution, Uri documentUri) diff --git a/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs b/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs index fb8bdf4533e68..5a91057b1de6b 100644 --- a/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs +++ b/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Razor; @@ -45,8 +46,10 @@ public FormatNewFileHandler(IGlobalOptionService globalOptions) return null; } + var parsedUri = request.Document.Uri.GetRequiredParsedUri(); + // Create a document in-memory to represent the file Razor wants to add - var filePath = ProtocolConversions.GetDocumentFilePathFromUri(request.Document.Uri); + var filePath = ProtocolConversions.GetDocumentFilePathFromUri(parsedUri); var source = SourceText.From(request.Contents); var fileLoader = new SourceTextLoader(source, filePath); var documentId = DocumentId.CreateNewId(project.Id); diff --git a/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs index 5eec735c049bd..d97bfe16d3905 100644 --- a/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/AbstractRefreshQueue.cs @@ -20,7 +20,7 @@ internal abstract class AbstractRefreshQueue : ILspService, IDisposable { - private AsyncBatchingWorkQueue? _refreshQueue; + private AsyncBatchingWorkQueue? _refreshQueue; private readonly LspWorkspaceManager _lspWorkspaceManager; private readonly IClientLanguageServerManager _notificationManager; @@ -63,11 +63,10 @@ public void Initialize(ClientCapabilities clientCapabilities) // sending too many notifications at once. This ensures we batch up workspace notifications, // but also means we send soon enough after a compilation-computation to not make the user wait // an enormous amount of time. - _refreshQueue = new AsyncBatchingWorkQueue( + _refreshQueue = new AsyncBatchingWorkQueue( delay: TimeSpan.FromMilliseconds(2000), processBatchAsync: (documentUris, cancellationToken) => FilterLspTrackedDocumentsAsync(_lspWorkspaceManager, _notificationManager, documentUris, cancellationToken), - equalityComparer: EqualityComparer.Default, asyncListener: _asyncListener, _disposalTokenSource.Token); _isQueueCreated = true; @@ -94,7 +93,7 @@ protected virtual void OnLspSolutionChanged(object? sender, WorkspaceChangeEvent } } - protected void EnqueueRefreshNotification(Uri? documentUri) + protected void EnqueueRefreshNotification(DocumentUri? documentUri) { if (_isQueueCreated) { @@ -106,7 +105,7 @@ protected void EnqueueRefreshNotification(Uri? documentUri) private ValueTask FilterLspTrackedDocumentsAsync( LspWorkspaceManager lspWorkspaceManager, IClientLanguageServerManager notificationManager, - ImmutableSegmentedList documentUris, + ImmutableSegmentedList documentUris, CancellationToken cancellationToken) { var trackedDocuments = lspWorkspaceManager.GetTrackedLspText(); diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs index 88b7247a1cd16..e2316519a2e73 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs @@ -225,7 +225,7 @@ async Task AddTextDocumentAdditionsAsync( var newTextDoc = getNewDocument(docId); Contract.ThrowIfNull(newTextDoc); - Uri? uri = null; + DocumentUri? uri = null; if (newTextDoc.FilePath != null) { uri = newTextDoc.GetURI(); diff --git a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs index a0c753ff3ff9d..41d4f1328fcc7 100644 --- a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs @@ -88,7 +88,7 @@ await definition.Document.GetRequiredDocumentAsync(document.Project.Solution, ca var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteUri(declarationFile.FilePath), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(declarationFile.FilePath), Range = ProtocolConversions.LinePositionToRange(linePosSpan), }); } diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs index ac49b0a9da7c6..8ec99dcb33984 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs @@ -29,7 +29,7 @@ public static AbstractProjectDiagnosticSource CreateForCodeAnalysisDiagnostics(P public Project GetProject() => Project; public TextDocumentIdentifier? GetDocumentIdentifier() => !string.IsNullOrEmpty(Project.FilePath) - ? new VSTextDocumentIdentifier { ProjectContext = ProtocolConversions.ProjectToProjectContext(Project), Uri = ProtocolConversions.CreateAbsoluteUri(Project.FilePath) } + ? new VSTextDocumentIdentifier { ProjectContext = ProtocolConversions.ProjectToProjectContext(Project), Uri = ProtocolConversions.CreateAbsoluteDocumentUri(Project.FilePath) } : null; public string ToDisplayString() => Project.Name; diff --git a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs index b75b6c9793e95..0da9e13562664 100644 --- a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs +++ b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler.DocumentChanges { [ExportCSharpVisualBasicStatelessLspService(typeof(DidOpenHandler)), Shared] [Method(LSP.Methods.TextDocumentDidOpenName)] - internal class DidOpenHandler : ILspServiceNotificationHandler, ITextDocumentIdentifierHandler + internal class DidOpenHandler : ILspServiceNotificationHandler, ITextDocumentIdentifierHandler { [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] @@ -26,7 +26,7 @@ public DidOpenHandler() public bool MutatesSolutionState => true; public bool RequiresLSPSolution => false; - public Uri GetTextDocumentIdentifier(LSP.DidOpenTextDocumentParams request) => request.TextDocument.Uri; + public LSP.TextDocumentItem GetTextDocumentIdentifier(LSP.DidOpenTextDocumentParams request) => request.TextDocument; public async Task HandleNotificationAsync(LSP.DidOpenTextDocumentParams request, RequestContext context, CancellationToken cancellationToken) { diff --git a/src/LanguageServer/Protocol/Handler/IDocumentChangeTracker.cs b/src/LanguageServer/Protocol/Handler/IDocumentChangeTracker.cs index ff2410d5277d7..86520e74f6bde 100644 --- a/src/LanguageServer/Protocol/Handler/IDocumentChangeTracker.cs +++ b/src/LanguageServer/Protocol/Handler/IDocumentChangeTracker.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler.DocumentChanges; using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler; @@ -16,24 +17,24 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler; /// internal interface IDocumentChangeTracker { - ValueTask StartTrackingAsync(Uri documentUri, SourceText initialText, string languageId, CancellationToken cancellationToken); - void UpdateTrackedDocument(Uri documentUri, SourceText text); - ValueTask StopTrackingAsync(Uri documentUri, CancellationToken cancellationToken); + ValueTask StartTrackingAsync(DocumentUri documentUri, SourceText initialText, string languageId, CancellationToken cancellationToken); + void UpdateTrackedDocument(DocumentUri documentUri, SourceText text); + ValueTask StopTrackingAsync(DocumentUri documentUri, CancellationToken cancellationToken); } internal class NonMutatingDocumentChangeTracker : IDocumentChangeTracker { - public ValueTask StartTrackingAsync(Uri documentUri, SourceText initialText, string languageId, CancellationToken cancellationToken) + public ValueTask StartTrackingAsync(DocumentUri documentUri, SourceText initialText, string languageId, CancellationToken cancellationToken) { throw new InvalidOperationException("Mutating documents not allowed in a non-mutating request handler"); } - public ValueTask StopTrackingAsync(Uri documentUri, CancellationToken cancellationToken) + public ValueTask StopTrackingAsync(DocumentUri documentUri, CancellationToken cancellationToken) { throw new InvalidOperationException("Mutating documents not allowed in a non-mutating request handler"); } - public void UpdateTrackedDocument(Uri documentUri, SourceText text) + public void UpdateTrackedDocument(DocumentUri documentUri, SourceText text) { throw new InvalidOperationException("Mutating documents not allowed in a non-mutating request handler"); } diff --git a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs index a404c848ff4ec..c0ba90e0d56c2 100644 --- a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs @@ -42,12 +42,12 @@ public MapCodeHandler() throw new NotImplementedException("mapCode Request failed: additional workspace 'Update' is currently not supported"); } - using var _ = PooledDictionary.GetInstance(out var uriToEditsMap); + using var _ = PooledDictionary.GetInstance(out var uriToEditsMap); foreach (var codeMapping in request.Mappings) { var mappingResult = await MapCodeAsync(codeMapping).ConfigureAwait(false); - if (mappingResult is not (Uri uri, LSP.TextEdit[] textEdits)) + if (mappingResult is not (DocumentUri uri, LSP.TextEdit[] textEdits)) { // Failed the entire request if any of the sub-requests failed return null; @@ -73,11 +73,11 @@ public MapCodeHandler() { return new WorkspaceEdit { - Changes = uriToEditsMap.ToDictionary(kvp => ProtocolConversions.GetDocumentFilePathFromUri(kvp.Key), kvp => kvp.Value) + Changes = uriToEditsMap.ToDictionary(kvp => ProtocolConversions.GetDocumentFilePathFromUri(kvp.Key.GetRequiredParsedUri()), kvp => kvp.Value) }; } - async Task<(Uri, LSP.TextEdit[])?> MapCodeAsync(LSP.VSInternalMapCodeMapping codeMapping) + async Task<(DocumentUri, LSP.TextEdit[])?> MapCodeAsync(LSP.VSInternalMapCodeMapping codeMapping) { var textDocument = codeMapping.TextDocument ?? throw new ArgumentException($"mapCode sub-request failed: MapCodeMapping.TextDocument not expected to be null."); diff --git a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs index 4196abef13bbe..b030a18049b78 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs @@ -217,7 +217,7 @@ public override async ValueTask OnReferencesFoundAsync(IAsyncEnumerable - private readonly ImmutableDictionary _trackedDocuments; + private readonly ImmutableDictionary _trackedDocuments; private readonly ILspServices _lspServices; @@ -176,7 +176,7 @@ public RequestContext( WellKnownLspServerKinds serverKind, TextDocument? document, IDocumentChangeTracker documentChangeTracker, - ImmutableDictionary trackedDocuments, + ImmutableDictionary trackedDocuments, ImmutableArray supportedLanguages, ILspServices lspServices, CancellationToken queueCancellationToken) @@ -304,17 +304,17 @@ public static async Task CreateAsync( /// Allows a mutating request to open a document and start it being tracked. /// Mutating requests are serialized by the execution queue in order to prevent concurrent access. /// - public ValueTask StartTrackingAsync(Uri uri, SourceText initialText, string languageId, CancellationToken cancellationToken) + public ValueTask StartTrackingAsync(DocumentUri uri, SourceText initialText, string languageId, CancellationToken cancellationToken) => _documentChangeTracker.StartTrackingAsync(uri, initialText, languageId, cancellationToken); /// /// Allows a mutating request to update the contents of a tracked document. /// Mutating requests are serialized by the execution queue in order to prevent concurrent access. /// - public void UpdateTrackedDocument(Uri uri, SourceText changedText) + public void UpdateTrackedDocument(DocumentUri uri, SourceText changedText) => _documentChangeTracker.UpdateTrackedDocument(uri, changedText); - public SourceText GetTrackedDocumentSourceText(Uri documentUri) + public SourceText GetTrackedDocumentSourceText(DocumentUri documentUri) { Contract.ThrowIfFalse(_trackedDocuments.ContainsKey(documentUri), $"Attempted to get text for {documentUri} which is not open."); return _trackedDocuments[documentUri].Text; @@ -347,10 +347,10 @@ public SourceText GetTrackedDocumentSourceText(Uri documentUri) /// Allows a mutating request to close a document and stop it being tracked. /// Mutating requests are serialized by the execution queue in order to prevent concurrent access. /// - public ValueTask StopTrackingAsync(Uri uri, CancellationToken cancellationToken) + public ValueTask StopTrackingAsync(DocumentUri uri, CancellationToken cancellationToken) => _documentChangeTracker.StopTrackingAsync(uri, cancellationToken); - public bool IsTracking(Uri documentUri) + public bool IsTracking(DocumentUri documentUri) => _trackedDocuments.ContainsKey(documentUri); public void ClearSolutionContext() diff --git a/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs b/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs index d23deddb0bc00..9e68282dced72 100644 --- a/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs +++ b/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs @@ -41,12 +41,12 @@ public override Task CreateRequestContextAsync(IQ { textDocumentIdentifier = nullHandler.GetTextDocumentIdentifier(requestParam); } - else if (textDocumentIdentifierHandler is ITextDocumentIdentifierHandler uHandler) + else if (textDocumentIdentifierHandler is ITextDocumentIdentifierHandler uHandler) { - var uri = uHandler.GetTextDocumentIdentifier(requestParam); + var textDocumentItem = uHandler.GetTextDocumentIdentifier(requestParam); textDocumentIdentifier = new TextDocumentIdentifier { - Uri = uri, + Uri = textDocumentItem.Uri, }; } else if (textDocumentIdentifierHandler is null) diff --git a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs index af4f7fe83d7a5..8f20c255d78f4 100644 --- a/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensRefreshQueue.cs @@ -62,7 +62,7 @@ public async Task TryEnqueueRefreshComputationAsync(Project project, Cancellatio protected override void OnLspSolutionChanged(object? sender, WorkspaceChangeEventArgs e) { - Uri? documentUri = null; + DocumentUri? documentUri = null; if (e.DocumentId is not null) { diff --git a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs index f1e315fc18004..9ade93237811a 100644 --- a/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs +++ b/src/LanguageServer/Protocol/Handler/SourceGenerators/SourceGeneratorRefreshQueue.cs @@ -122,7 +122,7 @@ await newProject.GetDependentVersionAsync(_disposalTokenSource.Token).ConfigureA private ValueTask RefreshSourceGeneratedDocumentsAsync( CancellationToken cancellationToken) { - var hasOpenSourceGeneratedDocuments = _lspWorkspaceManager.GetTrackedLspText().Keys.Any(uri => uri.Scheme == SourceGeneratedDocumentUri.Scheme); + var hasOpenSourceGeneratedDocuments = _lspWorkspaceManager.GetTrackedLspText().Keys.Any(uri => uri.ParsedUri?.Scheme == SourceGeneratedDocumentUri.Scheme); if (!hasOpenSourceGeneratedDocuments) { // There are no opened source generated documents - we don't need to bother asking the client to refresh anything. diff --git a/src/LanguageServer/Protocol/ILanguageInfoProvider.cs b/src/LanguageServer/Protocol/ILanguageInfoProvider.cs index 315e6ed6e22fb..5186176c672f2 100644 --- a/src/LanguageServer/Protocol/ILanguageInfoProvider.cs +++ b/src/LanguageServer/Protocol/ILanguageInfoProvider.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Features.Workspaces; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer { @@ -20,6 +21,6 @@ internal interface ILanguageInfoProvider : ILspService /// It is totally possible to not find language based on the file path (e.g. a newly created file that hasn't been saved to disk). /// In that case, we use the language Id that the LSP client gave us. /// - bool TryGetLanguageInformation(Uri uri, string? lspLanguageId, [NotNullWhen(true)] out LanguageInformation? languageInformation); + bool TryGetLanguageInformation(DocumentUri uri, string? lspLanguageId, [NotNullWhen(true)] out LanguageInformation? languageInformation); } } diff --git a/src/LanguageServer/Protocol/LanguageInfoProvider.cs b/src/LanguageServer/Protocol/LanguageInfoProvider.cs index 56e9c506aa809..5290dff6006af 100644 --- a/src/LanguageServer/Protocol/LanguageInfoProvider.cs +++ b/src/LanguageServer/Protocol/LanguageInfoProvider.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using Microsoft.CodeAnalysis.Features.Workspaces; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer { @@ -44,13 +45,13 @@ internal class LanguageInfoProvider : ILanguageInfoProvider { ".mts", s_typeScriptLanguageInformation }, }; - public bool TryGetLanguageInformation(Uri uri, string? lspLanguageId, [NotNullWhen(true)] out LanguageInformation? languageInformation) + public bool TryGetLanguageInformation(DocumentUri requestUri, string? lspLanguageId, [NotNullWhen(true)] out LanguageInformation? languageInformation) { // First try to get language information from the URI path. // We can do this for File uris and absolute uris. We use local path to get the value without any query parameters. - if (uri.IsFile || uri.IsAbsoluteUri) + if (requestUri.ParsedUri is not null && (requestUri.ParsedUri.IsFile || requestUri.ParsedUri.IsAbsoluteUri)) { - var localPath = uri.LocalPath; + var localPath = requestUri.ParsedUri.LocalPath; var extension = Path.GetExtension(localPath); if (s_extensionToLanguageInformation.TryGetValue(extension, out languageInformation)) { diff --git a/src/LanguageServer/Protocol/Protocol/CodeDescription.cs b/src/LanguageServer/Protocol/Protocol/CodeDescription.cs index 4ff525a766ad9..88654c7fda7b5 100644 --- a/src/LanguageServer/Protocol/Protocol/CodeDescription.cs +++ b/src/LanguageServer/Protocol/Protocol/CodeDescription.cs @@ -21,7 +21,7 @@ internal class CodeDescription : IEquatable /// [JsonPropertyName("href")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Href + public DocumentUri Href { get; set; @@ -70,7 +70,7 @@ public override bool Equals(object obj) /// public override int GetHashCode() { - return this.Href == null ? 53 : this.Href.GetHashCode(); + return this.Href is null ? 53 : this.Href.GetHashCode(); } } } diff --git a/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs b/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs index f97fcd9a3652c..b30297969cded 100644 --- a/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs +++ b/src/LanguageServer/Protocol/Protocol/ConfigurationItem.cs @@ -21,7 +21,7 @@ internal class ConfigurationItem [JsonPropertyName("scopeUri")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonConverter(typeof(DocumentUriConverter))] - public Uri? ScopeUri + public DocumentUri? ScopeUri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs b/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs index 4a91a4cacbde4..c2a6b95d90476 100644 --- a/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs +++ b/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs @@ -9,13 +9,15 @@ namespace Roslyn.LanguageServer.Protocol; /// -/// TODO: document. +/// Converts the LSP spec URI string into our custom wrapper for URI strings. +/// We do not convert directly to as it is unable to handle +/// certain valid RFC spec URIs. We do not want serialization / deserialization to fail if we cannot parse the URI. /// -internal class DocumentUriConverter : JsonConverter +internal class DocumentUriConverter : JsonConverter { - public override Uri Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override DocumentUri Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => new(reader.GetString()); - public override void Write(Utf8JsonWriter writer, Uri value, JsonSerializerOptions options) - => writer.WriteStringValue(value.AbsoluteUri); + public override void Write(Utf8JsonWriter writer, DocumentUri value, JsonSerializerOptions options) + => writer.WriteStringValue(value.UriString); } diff --git a/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs b/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs index a3879a6b50449..39b86df161931 100644 --- a/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs +++ b/src/LanguageServer/Protocol/Protocol/Converters/SumConverter.cs @@ -65,6 +65,7 @@ public SumTypeInfoCache(Type sumTypeType) if (parameterTypeInfo.IsPrimitive || parameterTypeInfo == typeof(string) || + parameterTypeInfo == typeof(DocumentUri) || parameterTypeInfo == typeof(Uri) || typeof(IStringEnum).IsAssignableFrom(parameterTypeInfo)) { @@ -261,7 +262,12 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions var sumValue = value.Value; // behavior from DocumentUriConverter - if (sumValue is Uri) + if (sumValue is DocumentUri documentUri) + { + writer.WriteStringValue(documentUri.UriString); + return; + } + else if (sumValue is Uri) { writer.WriteStringValue(sumValue.ToString()); return; @@ -297,6 +303,7 @@ private static bool IsTokenCompatibleWithType(ref Utf8JsonReader reader, SumConv case JsonTokenType.String: isCompatible = unionTypeInfo.Type == typeof(string) || unionTypeInfo.Type == typeof(Uri) || + unionTypeInfo.Type == typeof(DocumentUri) || typeof(IStringEnum).IsAssignableFrom(unionTypeInfo.Type); break; } diff --git a/src/LanguageServer/Protocol/Protocol/CreateFile.cs b/src/LanguageServer/Protocol/Protocol/CreateFile.cs index 2ca8e1a7e3a8c..20ca04744c668 100644 --- a/src/LanguageServer/Protocol/Protocol/CreateFile.cs +++ b/src/LanguageServer/Protocol/Protocol/CreateFile.cs @@ -30,7 +30,7 @@ internal class CreateFile : IAnnotatedChange [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/DeleteFile.cs b/src/LanguageServer/Protocol/Protocol/DeleteFile.cs index 72cae2338387d..98e766d9b8cdb 100644 --- a/src/LanguageServer/Protocol/Protocol/DeleteFile.cs +++ b/src/LanguageServer/Protocol/Protocol/DeleteFile.cs @@ -30,7 +30,7 @@ internal class DeleteFile : IAnnotatedChange [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/DocumentLink.cs b/src/LanguageServer/Protocol/Protocol/DocumentLink.cs index f060bec505004..d44479a463fad 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentLink.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentLink.cs @@ -32,7 +32,7 @@ public Range Range [JsonPropertyName("target")] [JsonConverter(typeof(DocumentUriConverter))] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public Uri? Target + public DocumentUri? Target { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/DocumentUri.cs b/src/LanguageServer/Protocol/Protocol/DocumentUri.cs new file mode 100644 index 0000000000000..cc2eaeab69b8e --- /dev/null +++ b/src/LanguageServer/Protocol/Protocol/DocumentUri.cs @@ -0,0 +1,137 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Roslyn.LanguageServer.Protocol; + +/// +/// Datatype used to hold URI strings for LSP message serialization. For details on how URIs are communicated in LSP, +/// see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri +/// +/// +/// While .NET has a type represent URIs (System.Uri), we do not want to use this type directly in +/// serialization and deserialization. System.Uri does full parsing and validation on the URI upfront, so +/// any issues in the uri format will cause deserialization to fail and bypass any of our error recovery. +/// +/// Compounding this problem, System.Uri will fail to parse various RFC spec valid URIs. +/// In order to gracefully handle these issues, we defer the parsing of the URI until someone +/// actually asks for it (and can handle the failure). +/// +internal sealed class DocumentUri : IEquatable +{ + private readonly Lazy _parsedUriLazy; + + public DocumentUri(string uriString) + { + UriString = uriString; + _parsedUriLazy = new(() => ParseUri(uriString)); + } + + public DocumentUri(Uri parsedUri) + { + UriString = parsedUri.AbsoluteUri; + _parsedUriLazy = new(() => parsedUri); + } + + public string UriString { get; } + + /// + /// Gets the parsed System.Uri for the URI string. + /// + /// + /// Null if the URI string is not parse-able with System.Uri. + /// + /// + /// Invalid RFC spec URI strings are not parse-able as so will return null here. + /// However, System.Uri can also fail to parse certain valid RFC spec URI strings. + /// + /// For example, any URI containing a 'sub-delims' character in the host name + /// is a valid RFC spec URI, but will fail with System.Uri + /// + public Uri? ParsedUri => _parsedUriLazy.Value; + + private static Uri? ParseUri(string uriString) + { + try + { + return new Uri(uriString); + } + catch (UriFormatException) + { + // This is not a URI that System.Uri can handle. + return null; + } + } + + public override string ToString() => UriString; + + public override bool Equals([NotNullWhen(true)] object? obj) => obj is DocumentUri other && this.Equals(other); + + public bool Equals(DocumentUri otherUri) + { + // 99% of the time the equivalent URIs will have equivalent URI strings, as the client is expected to be consistent in how it sends the URIs to the server, + // either always encoded or always unencoded. + // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri + if (this.UriString == otherUri.UriString) + { + return true; + } + + // If either of the URIs cannot be parsed, we'll compare the original URI strings. + if (otherUri.ParsedUri is null || this.ParsedUri is null) + { + return this.UriString == otherUri.UriString; + } + + // Next we compare the parsed URIs to handle various casing and encoding scenarios (for example - different schemes may handle casing differently). + + // Uri.Equals will not always consider a percent encoded URI equal to an unencoded URI, even if they point to the same resource. + // As above, the client is supposed to be consistent in which kind of URI they send. + // + // However, there are rare cases where we are comparing an unencoded URI to an encoded URI and should consider them + // equivalent if they point to the same file path. + // For example - say the client generally sends us the unencoded URI. When we serialize URIs back to the client, we always serialize the AbsoluteUri property (see FromUri). + // The AbsoluteUri property is *always* percent encoded - if this URI gets sent back to us as part of a data object on a request (e.g. codelens/resolve), the client will leave + // the URI untouched, even if they generally send unencoded URIs. In such cases we need to consider the encoded and unencoded URI equivalent. + // + // To handle that, we first compare the AbsoluteUri properties on both, which are always percent encoded. + if (this.ParsedUri.IsAbsoluteUri && otherUri.ParsedUri.IsAbsoluteUri && this.ParsedUri.AbsoluteUri == otherUri.ParsedUri.AbsoluteUri) + { + return true; + } + else + { + return Uri.Equals(this.ParsedUri, otherUri.ParsedUri); + } + } + + public override int GetHashCode() + { + if (this.ParsedUri is null) + { + // We can't do anything better than the uri string hash code if we cannot parse the URI. + return this.UriString.GetHashCode(); + } + + if (this.ParsedUri.IsAbsoluteUri) + { + // Since the Uri type does not consider an encoded Uri equal to an unencoded Uri, we need to handle this ourselves. + // The AbsoluteUri property is always encoded, so we can use this to compare the URIs (see Equals above). + // + // However, depending on the kind of URI, case sensitivity in AbsoluteUri should be ignored. + // Uri.GetHashCode normally handles this internally, but the parameters it uses to determine which comparison to use are not exposed. + // + // Instead, we will always create the hash code ignoring case, and will rely on the Equals implementation + // to handle collisions (between two Uris with different casing). This should be very rare in practice. + // Collisions can happen for non UNC URIs (e.g. `git:/blah` vs `git:/Blah`). + return StringComparer.OrdinalIgnoreCase.GetHashCode(this.ParsedUri.AbsoluteUri); + } + else + { + return this.ParsedUri.GetHashCode(); + } + } +} diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileCreate.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileCreate.cs index ddd7192f4af3e..732f9dd564f94 100644 --- a/src/LanguageServer/Protocol/Protocol/FileOperations/FileCreate.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileCreate.cs @@ -22,5 +22,5 @@ internal class FileCreate [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri { get; set; } + public DocumentUri Uri { get; set; } } diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileDelete.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileDelete.cs index f5ff575a3cc27..1edbd3adecc40 100644 --- a/src/LanguageServer/Protocol/Protocol/FileOperations/FileDelete.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileDelete.cs @@ -22,5 +22,5 @@ internal class FileDelete [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri { get; set; } + public DocumentUri Uri { get; set; } } diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileEvent.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileEvent.cs index 6a45333d8a5ee..26daaeb252db3 100644 --- a/src/LanguageServer/Protocol/Protocol/FileOperations/FileEvent.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileEvent.cs @@ -20,7 +20,7 @@ internal class FileEvent /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri { get; set; } + public DocumentUri Uri { get; set; } /// /// Gets or sets the file change type. diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/FileRename.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/FileRename.cs index fada354f69415..3aea71a4f1bc8 100644 --- a/src/LanguageServer/Protocol/Protocol/FileOperations/FileRename.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/FileRename.cs @@ -22,7 +22,7 @@ internal class FileRename [JsonPropertyName("oldUri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri OldUri { get; set; } + public DocumentUri OldUri { get; set; } /// /// A file:// URI for the new location of the file/folder being renamed. @@ -30,5 +30,5 @@ internal class FileRename [JsonPropertyName("newUri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri NewUri { get; set; } + public DocumentUri NewUri { get; set; } } diff --git a/src/LanguageServer/Protocol/Protocol/FileOperations/RelativePattern.cs b/src/LanguageServer/Protocol/Protocol/FileOperations/RelativePattern.cs index 6126ef4a7c3b7..2a72df32aa6d6 100644 --- a/src/LanguageServer/Protocol/Protocol/FileOperations/RelativePattern.cs +++ b/src/LanguageServer/Protocol/Protocol/FileOperations/RelativePattern.cs @@ -21,7 +21,7 @@ internal class RelativePattern /// [JsonPropertyName("baseUri")] [JsonRequired] - public SumType BaseUri { get; init; } + public SumType BaseUri { get; init; } /// /// The actual glob pattern. See Glob Pattern for more detail. diff --git a/src/LanguageServer/Protocol/Protocol/InitializeParams.cs b/src/LanguageServer/Protocol/Protocol/InitializeParams.cs index 1d6aa360525e3..74b5d8c9a96dd 100644 --- a/src/LanguageServer/Protocol/Protocol/InitializeParams.cs +++ b/src/LanguageServer/Protocol/Protocol/InitializeParams.cs @@ -67,7 +67,7 @@ public string? RootPath [JsonPropertyName("rootUri")] [Obsolete("Deprecated in favor of WorkspaceFolders")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri? RootUri + public DocumentUri? RootUri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/Location.cs b/src/LanguageServer/Protocol/Protocol/Location.cs index 123dfea04440a..d2b9adf4fc707 100644 --- a/src/LanguageServer/Protocol/Protocol/Location.cs +++ b/src/LanguageServer/Protocol/Protocol/Location.cs @@ -20,7 +20,7 @@ internal class Location : IEquatable /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; @@ -45,7 +45,7 @@ public override bool Equals(object obj) /// public bool Equals(Location? other) { - return other != null && this.Uri != null && other.Uri != null && + return other != null && this.Uri.Equals(other.Uri) && EqualityComparer.Default.Equals(this.Range, other.Range); } @@ -54,7 +54,7 @@ public bool Equals(Location? other) public override int GetHashCode() { var hashCode = 1486144663; - hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Uri); + hashCode = (hashCode * -1521134295) + this.Uri.GetHashCode(); hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Range); return hashCode; } diff --git a/src/LanguageServer/Protocol/Protocol/LocationLink.cs b/src/LanguageServer/Protocol/Protocol/LocationLink.cs index 8f2fff57d4246..818f93d54cc48 100644 --- a/src/LanguageServer/Protocol/Protocol/LocationLink.cs +++ b/src/LanguageServer/Protocol/Protocol/LocationLink.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Text.Json.Serialization; - using Roslyn.Utilities; namespace Roslyn.LanguageServer.Protocol; @@ -36,7 +35,7 @@ internal class LocationLink : IEquatable [JsonPropertyName("targetUri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri TargetUri { get; init; } + public DocumentUri TargetUri { get; init; } /// /// The full target range of the linked location in the target document, which includes @@ -63,7 +62,7 @@ internal class LocationLink : IEquatable public bool Equals(LocationLink? other) => other != null && EqualityComparer.Default.Equals(this.OriginSelectionRange, other.OriginSelectionRange) - && this.TargetUri != null && other.TargetUri != null && this.TargetUri.Equals(other.TargetUri) + && EqualityComparer.Default.Equals(this.TargetUri, other.TargetUri) && EqualityComparer.Default.Equals(this.TargetRange, other.TargetRange) && EqualityComparer.Default.Equals(this.TargetSelectionRange, other.TargetSelectionRange); @@ -73,7 +72,7 @@ public override int GetHashCode() => HashCode.Combine(OriginSelectionRange, TargetUri, TargetRange, TargetSelectionRange); #else Hash.Combine(OriginSelectionRange, - Hash.Combine(TargetUri, + Hash.Combine(TargetUri.GetHashCode(), Hash.Combine(TargetRange, TargetSelectionRange.GetHashCode()))); #endif } diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyItem.cs b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyItem.cs index 384c225efa4cd..2e99f501865aa 100644 --- a/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyItem.cs +++ b/src/LanguageServer/Protocol/Protocol/Navigation/CallHierarchyItem.cs @@ -50,7 +50,7 @@ internal class CallHierarchyItem [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri { get; init; } + public DocumentUri Uri { get; init; } /// /// The range enclosing this symbol not including leading/trailing whitespace diff --git a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyItem.cs b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyItem.cs index 860eba4cc1d1a..7cc7b274849fd 100644 --- a/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyItem.cs +++ b/src/LanguageServer/Protocol/Protocol/Navigation/TypeHierarchyItem.cs @@ -50,7 +50,7 @@ internal class TypeHierarchyItem [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri { get; init; } + public DocumentUri Uri { get; init; } /// /// The range enclosing this symbol not including leading/trailing whitespace diff --git a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCell.cs b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCell.cs index a738797ac815b..dd5e7f28abdc5 100644 --- a/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCell.cs +++ b/src/LanguageServer/Protocol/Protocol/Notebook/NotebookCell.cs @@ -33,7 +33,7 @@ internal class NotebookCell [JsonPropertyName("document")] [JsonConverter(typeof(DocumentUriConverter))] [JsonRequired] - public Uri Document { get; init; } + public DocumentUri Document { get; init; } /// /// Additional metadata stored with the cell. diff --git a/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs b/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs index 610de39552d7c..28dd4ea10b834 100644 --- a/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs +++ b/src/LanguageServer/Protocol/Protocol/PreviousResultId.cs @@ -21,7 +21,7 @@ internal class PreviousResultId /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs b/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs index 4656113a54618..32d553bc844de 100644 --- a/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs +++ b/src/LanguageServer/Protocol/Protocol/PublishDiagnosticParams.cs @@ -19,7 +19,7 @@ internal class PublishDiagnosticParams /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/RenameFile.cs b/src/LanguageServer/Protocol/Protocol/RenameFile.cs index 4b50223b1495c..0bf93abc553d8 100644 --- a/src/LanguageServer/Protocol/Protocol/RenameFile.cs +++ b/src/LanguageServer/Protocol/Protocol/RenameFile.cs @@ -30,7 +30,7 @@ internal class RenameFile : IAnnotatedChange [JsonPropertyName("oldUri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri OldUri + public DocumentUri OldUri { get; set; @@ -42,7 +42,7 @@ public Uri OldUri [JsonPropertyName("newUri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri NewUri + public DocumentUri NewUri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs index 9ec8f5a0c8804..9c6fdebb755e7 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs @@ -19,7 +19,7 @@ internal class TextDocumentIdentifier : IEquatable /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; @@ -69,13 +69,13 @@ public override bool Equals(object obj) /// public override int GetHashCode() { - return this.Uri == null ? 89 : this.Uri.GetHashCode(); + return this.Uri is null ? 89 : this.Uri.GetHashCode(); } /// public override string ToString() { - return this.Uri == null ? string.Empty : this.Uri.AbsolutePath; + return this.Uri.ToString(); } } } diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs index 9a627e3ff7622..e9ce7c82dc905 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs @@ -19,7 +19,7 @@ internal class TextDocumentItem /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs index baa62b41407f1..b91a229b55994 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs @@ -17,7 +17,7 @@ internal class WorkspaceFolder [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] [JsonRequired] - public Uri Uri { get; init; } + public DocumentUri Uri { get; init; } /// /// The name of the workspace folder used in the UI. diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs index a034368bf8bda..26a2976aa190a 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceFullDocumentDiagnosticReport.cs @@ -23,7 +23,7 @@ internal class WorkspaceFullDocumentDiagnosticReport : FullDocumentDiagnosticRep [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolLocation.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolLocation.cs index 6719e157caac2..ed0ab6803d7cc 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolLocation.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceSymbolLocation.cs @@ -15,6 +15,6 @@ internal class WorkspaceSymbolLocation [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri { get; init; } + public DocumentUri Uri { get; init; } } diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs index 84316ebaacbfa..2680f13e33da7 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceUnchangedDocumentDiagnosticReport.cs @@ -23,7 +23,7 @@ internal class WorkspaceUnchangedDocumentDiagnosticReport : UnchangedDocumentDia [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public Uri Uri + public DocumentUri Uri { get; set; diff --git a/src/LanguageServer/Protocol/RoslynLanguageServer.cs b/src/LanguageServer/Protocol/RoslynLanguageServer.cs index a68788ad03c87..ad65228f893d9 100644 --- a/src/LanguageServer/Protocol/RoslynLanguageServer.cs +++ b/src/LanguageServer/Protocol/RoslynLanguageServer.cs @@ -191,13 +191,14 @@ public override bool TryGetLanguageForRequest(string methodName, object? seriali // { "textDocument": { "uri": "" ... } ... } // // We can easily identify the URI for the request by looking for this structure - Uri? uri = null; + DocumentUri? uri = null; if (parameters.TryGetProperty("textDocument", out var textDocumentToken) || parameters.TryGetProperty("_vs_textDocument", out textDocumentToken)) { - var uriToken = textDocumentToken.GetProperty("uri"); - uri = JsonSerializer.Deserialize(uriToken, ProtocolConversions.LspJsonSerializerOptions); - Contract.ThrowIfNull(uri, "Failed to deserialize uri property"); + //var uriToken = textDocumentToken.GetProperty("uri"); + var textDocumentIdentifier = JsonSerializer.Deserialize(textDocumentToken, ProtocolConversions.LspJsonSerializerOptions); + Contract.ThrowIfNull(textDocumentIdentifier, "Failed to deserialize uri property"); + uri = textDocumentIdentifier.Uri; } else if (parameters.TryGetProperty("data", out var dataToken)) { @@ -211,7 +212,7 @@ public override bool TryGetLanguageForRequest(string methodName, object? seriali uri = data.TextDocument.Uri; } - if (uri == null) + if (uri is null) { // This request is not for a textDocument and is not a resolve request. Logger.LogInformation("Request did not contain a textDocument, using default language handler"); diff --git a/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs b/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs index 289bda83594e4..15b1d0ba5f955 100644 --- a/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs +++ b/src/LanguageServer/Protocol/Workspaces/LspMiscellaneousFilesWorkspace.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CommonLanguageServerProtocol.Framework; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer @@ -33,12 +34,16 @@ internal sealed class LspMiscellaneousFilesWorkspace(ILspServices lspServices, I /// /// Takes in a file URI and text and creates a misc project and document for the file. /// - /// Calls to this method and are made + /// Calls to this method and are made /// from LSP text sync request handling which do not run concurrently. /// - public Document? AddMiscellaneousDocument(Uri uri, SourceText documentText, string languageId, ILspLogger logger) + public Document? AddMiscellaneousDocument(DocumentUri uri, SourceText documentText, string languageId, ILspLogger logger) { - var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); + var documentFilePath = uri.UriString; + if (uri.ParsedUri is not null) + { + documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri.ParsedUri); + } var container = new StaticSourceTextContainer(documentText); if (metadataAsSourceFileService.TryAddDocumentToWorkspace(documentFilePath, container, out var documentId)) @@ -70,13 +75,12 @@ internal sealed class LspMiscellaneousFilesWorkspace(ILspServices lspServices, I /// /// Removes a document with the matching file path from this workspace. /// - /// Calls to this method and are made + /// Calls to this method and are made /// from LSP text sync request handling which do not run concurrently. /// - public void TryRemoveMiscellaneousDocument(Uri uri, bool removeFromMetadataWorkspace) + public void TryRemoveMiscellaneousDocument(DocumentUri uri, bool removeFromMetadataWorkspace) { - var documentFilePath = ProtocolConversions.GetDocumentFilePathFromUri(uri); - if (removeFromMetadataWorkspace && metadataAsSourceFileService.TryRemoveDocumentFromWorkspace(documentFilePath)) + if (removeFromMetadataWorkspace && uri.ParsedUri is not null && metadataAsSourceFileService.TryRemoveDocumentFromWorkspace(ProtocolConversions.GetDocumentFilePathFromUri(uri.ParsedUri))) { return; } diff --git a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs index f9e31132397a7..8b95326437e8a 100644 --- a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs +++ b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs @@ -45,56 +45,6 @@ namespace Microsoft.CodeAnalysis.LanguageServer; /// internal sealed class LspWorkspaceManager : IDocumentChangeTracker, ILspService { - private class LspUriComparer : IEqualityComparer - { - public static readonly LspUriComparer Instance = new(); - public bool Equals(Uri? x, Uri? y) - { - // Compare the absolute URIs to handle the case where one URI is encoded and the other is not. - // By default, Uri.Equals will not consider the encoded version of a URI equal to the unencoded version. - // - // The client is expected to be consistent in how it sends the URIs (either encoded or unencoded). - // So we normally can safely store the URIs as they send us in our map and expect subsequent requests to be encoded in the same way and match. - // See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri - // - // However when we serialize URIs to the client, we serialize the AbsoluteUri property which is always % encoded (no matter the original representation). - // For some requests, the client sends us exactly back what we sent (e.g. the data in a codelens/resolve request). - // This means that for these requests, the URI we will get from the client is the encoded version (that we sent). - // If the client sent us an unencoded URI originally, Uri.Equals will not consider it equal to the encoded version and we will fail to find the document - // - // So in order to resolve the encoded URI to the correct text, we can compare the AbsoluteUri properties (which are always encoded). - if (x is not null && y is not null && x.IsAbsoluteUri && y.IsAbsoluteUri && x.AbsoluteUri == y.AbsoluteUri) - { - return true; - } - else - { - return Uri.Equals(x, y); - } - } - - public int GetHashCode(Uri obj) - { - if (obj.IsAbsoluteUri) - { - // Since the Uri type does not consider an encoded Uri equal to an unencoded Uri, we need to handle this ourselves. - // The AbsoluteUri property is always encoded, so we can use this to compare the URIs (see Equals above). - // - // However, depending on the kind of URI, case sensitivity in AbsoluteUri should be ignored. - // Uri.GetHashCode normally handles this internally, but the parameters it uses to determine which comparison to use are not exposed. - // - // Instead, we will always create the hash code ignoring case, and will rely on the Equals implementation - // to handle collisions (between two Uris with different casing). This should be very rare in practice. - // Collisions can happen for non UNC URIs (e.g. `git:/blah` vs `git:/Blah`). - return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.AbsoluteUri); - } - else - { - return obj.GetHashCode(); - } - } - } - /// /// A cache from workspace to the last solution we returned for LSP. /// The forkedFromVersion is not null when the solution was created from a fork of the workspace with LSP @@ -112,7 +62,7 @@ public int GetHashCode(Uri obj) /// the URI. /// Access to this is guaranteed to be serial by the /// - private ImmutableDictionary _trackedDocuments = ImmutableDictionary.Empty.WithComparers(LspUriComparer.Instance); + private ImmutableDictionary _trackedDocuments = ImmutableDictionary.Empty; private readonly ILspLogger _logger; private readonly LspMiscellaneousFilesWorkspace? _lspMiscellaneousFilesWorkspace; @@ -139,7 +89,7 @@ public LspWorkspaceManager( #region Implementation of IDocumentChangeTracker - private static async ValueTask ApplyChangeToMutatingWorkspaceAsync(Workspace workspace, Uri uri, Func change) + private static async ValueTask ApplyChangeToMutatingWorkspaceAsync(Workspace workspace, DocumentUri uri, Func change) { if (workspace is not ILspWorkspace { SupportsMutation: true } mutatingWorkspace) return; @@ -153,10 +103,16 @@ private static async ValueTask ApplyChangeToMutatingWorkspaceAsync(Workspace wor /// /// is true which means this runs serially in the /// - public async ValueTask StartTrackingAsync(Uri uri, SourceText documentText, string languageId, CancellationToken cancellationToken) + public async ValueTask StartTrackingAsync(DocumentUri uri, SourceText documentText, string languageId, CancellationToken cancellationToken) { // First, store the LSP view of the text as the uri is now owned by the LSP client. Contract.ThrowIfTrue(_trackedDocuments.ContainsKey(uri), $"didOpen received for {uri} which is already open."); + + if (uri.ParsedUri is null) + { + _logger.LogError($"Unable to parse URI {uri}"); + } + _trackedDocuments = _trackedDocuments.Add(uri, (documentText, languageId)); // If LSP changed, we need to compare against the workspace again to get the updated solution. @@ -171,7 +127,7 @@ public async ValueTask StartTrackingAsync(Uri uri, SourceText documentText, stri return; - async ValueTask TryOpenDocumentsInMutatingWorkspaceAsync(Uri uri) + async ValueTask TryOpenDocumentsInMutatingWorkspaceAsync(DocumentUri uri) { var registeredWorkspaces = _lspWorkspaceRegistrationService.GetAllRegistrations(); foreach (var workspace in registeredWorkspaces) @@ -187,7 +143,7 @@ await ApplyChangeToMutatingWorkspaceAsync(workspace, uri, (_, documentId) => /// /// is true which means this runs serially in the /// - public async ValueTask StopTrackingAsync(Uri uri, CancellationToken cancellationToken) + public async ValueTask StopTrackingAsync(DocumentUri uri, CancellationToken cancellationToken) { // First, stop tracking this URI and source text as it is no longer owned by LSP. Contract.ThrowIfFalse(_trackedDocuments.ContainsKey(uri), $"didClose received for {uri} which is not open."); @@ -206,7 +162,7 @@ public async ValueTask StopTrackingAsync(Uri uri, CancellationToken cancellation return; - async ValueTask TryCloseDocumentsInMutatingWorkspaceAsync(Uri uri) + async ValueTask TryCloseDocumentsInMutatingWorkspaceAsync(DocumentUri uri) { var registeredWorkspaces = _lspWorkspaceRegistrationService.GetAllRegistrations(); foreach (var workspace in registeredWorkspaces) @@ -231,7 +187,7 @@ await ApplyChangeToMutatingWorkspaceAsync(workspace, uri, async (_, documentId) /// /// is true which means this runs serially in the /// - public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) + public void UpdateTrackedDocument(DocumentUri uri, SourceText newSourceText) { // Store the updated LSP view of the source text. Contract.ThrowIfFalse(_trackedDocuments.ContainsKey(uri), $"didChange received for {uri} which is not open."); @@ -244,7 +200,7 @@ public void UpdateTrackedDocument(Uri uri, SourceText newSourceText) LspTextChanged?.Invoke(this, EventArgs.Empty); } - public ImmutableDictionary GetTrackedLspText() => _trackedDocuments; + public ImmutableDictionary GetTrackedLspText() => _trackedDocuments; #endregion @@ -396,8 +352,9 @@ .. registeredWorkspaces.Where(workspace => workspace.Kind == WorkspaceKind.Misce var documentsInWorkspace = GetDocumentsForUris([.. _trackedDocuments.Keys], workspaceCurrentSolution); var sourceGeneratedDocuments = - _trackedDocuments.Keys.Where(static uri => uri.Scheme == SourceGeneratedDocumentUri.Scheme) - .Select(uri => (identity: SourceGeneratedDocumentUri.DeserializeIdentity(workspaceCurrentSolution, uri), _trackedDocuments[uri].Text)) + _trackedDocuments.Keys.Where(static trackedDocument => trackedDocument.ParsedUri?.Scheme == SourceGeneratedDocumentUri.Scheme) + // We know we have a non null URI with a source generated scheme. + .Select(uri => (identity: SourceGeneratedDocumentUri.DeserializeIdentity(workspaceCurrentSolution, uri.ParsedUri!), _trackedDocuments[uri].Text)) .Where(tuple => tuple.identity.HasValue) .SelectAsArray(tuple => (tuple.identity!.Value, DateTime.Now, tuple.Text)); @@ -478,11 +435,11 @@ await workspace.TryOnDocumentOpenedAsync( /// This looks at the source generator state explicitly to avoid actually running source generators /// private static bool DoesAllSourceGeneratedTextMatchWorkspaceSolution( - ImmutableArray<(SourceGeneratedDocumentIdentity Identity, DateTime Generated, SourceText Text)> sourceGenereatedDocuments, + ImmutableArray<(SourceGeneratedDocumentIdentity Identity, DateTime Generated, SourceText Text)> sourceGeneratedDocuments, Solution workspaceSolution) { var compilationState = workspaceSolution.CompilationState; - foreach (var (identity, _, text) in sourceGenereatedDocuments) + foreach (var (identity, _, text) in sourceGeneratedDocuments) { var existingState = compilationState.TryGetSourceGeneratedDocumentStateForAlreadyGeneratedId(identity.DocumentId); if (existingState is null) @@ -504,7 +461,7 @@ private static bool DoesAllSourceGeneratedTextMatchWorkspaceSolution( /// /// Given a set of documents from the workspace current solution, verify that the LSP text is the same as the document contents. /// - private async Task DoesAllTextMatchWorkspaceSolutionAsync(ImmutableDictionary> documentsInWorkspace, CancellationToken cancellationToken) + private async Task DoesAllTextMatchWorkspaceSolutionAsync(ImmutableDictionary> documentsInWorkspace, CancellationToken cancellationToken) { foreach (var (uriInWorkspace, documentsForUri) in documentsInWorkspace) { @@ -536,7 +493,7 @@ private static async ValueTask AreChecksumsEqualAsync(TextDocument documen /// /// Returns a Roslyn language name for the given URI. /// - internal bool TryGetLanguageForUri(Uri uri, [NotNullWhen(true)] out string? language) + internal bool TryGetLanguageForUri(DocumentUri uri, [NotNullWhen(true)] out string? language) { string? languageId = null; if (_trackedDocuments.TryGetValue(uri, out var trackedDocument)) @@ -557,9 +514,9 @@ internal bool TryGetLanguageForUri(Uri uri, [NotNullWhen(true)] out string? lang /// /// Using the workspace's current solutions, find the matching documents in for each URI. /// - private static ImmutableDictionary> GetDocumentsForUris(ImmutableArray trackedDocuments, Solution workspaceCurrentSolution) + private static ImmutableDictionary> GetDocumentsForUris(ImmutableArray trackedDocuments, Solution workspaceCurrentSolution) { - using var _ = PooledDictionary>.GetInstance(out var documentsInSolution); + using var _ = PooledDictionary>.GetInstance(out var documentsInSolution); foreach (var trackedDoc in trackedDocuments) { var documents = workspaceCurrentSolution.GetTextDocuments(trackedDoc); diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs index 115998c9c86ca..217b0dfac9ade 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs @@ -193,7 +193,7 @@ class {|caret:ABC|} groupName: "Roslyn2", applicableRange: new LSP.Range { Start = new Position { Line = 0, Character = 6 }, End = new Position { Line = 0, Character = 9 } }, diagnostics: null, - edit: GenerateRenameFileEdit(new List<(Uri, Uri)> { (documentUriBefore, documentUriAfter) })); + edit: GenerateRenameFileEdit(new List<(DocumentUri, DocumentUri)> { (documentUriBefore, documentUriAfter) })); AssertJsonEquals(expectedCodeAction, actualResolvedAction); } @@ -343,7 +343,7 @@ class BCD var actualResolvedAction = await RunGetCodeActionResolveAsync(testLspServer, unresolvedCodeAction); var project = testWorkspace.CurrentSolution.Projects.Single(); - var newDocumentUri = ProtocolConversions.CreateAbsoluteUri(Path.Combine(Path.GetDirectoryName(project.FilePath), "ABC.cs")); + var newDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(Path.Combine(Path.GetDirectoryName(project.FilePath), "ABC.cs")); var existingDocumentUri = testWorkspace.CurrentSolution.GetRequiredDocument(testWorkspace.Documents.Single().Id).GetURI(); var workspaceEdit = new WorkspaceEdit() { @@ -470,7 +470,7 @@ class {|caret:BCD|} var existingDocumentUri = existingDocument.GetURI(); Assert.Contains(Path.Combine("dir1", "dir2", "dir3"), existingDocument.FilePath); - var newDocumentUri = ProtocolConversions.CreateAbsoluteUri( + var newDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri( Path.Combine(Path.GetDirectoryName(existingDocument.FilePath), "BCD.cs")); var workspaceEdit = new WorkspaceEdit() { @@ -583,7 +583,7 @@ private static WorkspaceEdit GenerateWorkspaceEdit( } }; - private static WorkspaceEdit GenerateRenameFileEdit(IList<(Uri oldUri, Uri newUri)> renameLocations) + private static WorkspaceEdit GenerateRenameFileEdit(IList<(DocumentUri oldUri, DocumentUri newUri)> renameLocations) => new() { DocumentChanges = renameLocations.Select( diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs index 7eb8c621e703c..91bdbc4d8de54 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs @@ -38,7 +38,7 @@ void M() var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); // Verify that as originally serialized, the URI had a file scheme. - Assert.True(results.Single().Uri.OriginalString.StartsWith("file")); + Assert.True(results.Single().Uri.UriString.StartsWith("file")); AssertLocationsEqual(testLspServer.GetLocations("definition"), results); } @@ -88,7 +88,7 @@ void M() var position = new LSP.Position { Line = 5, Character = 18 }; var results = await RunGotoDefinitionAsync(testLspServer, new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteUri($"C:\\{TestSpanMapper.GeneratedFileName}"), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), Range = new LSP.Range { Start = position, End = position } }); AssertLocationsEqual([TestSpanMapper.MappedFileLocation], results); @@ -253,7 +253,7 @@ class B var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); var result = Assert.Single(results); - Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.Scheme); + Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.GetRequiredParsedUri().Scheme); } [Theory, CombinatorialData] @@ -272,7 +272,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); - Assert.True(results.Single().Uri.OriginalString.EndsWith("String.cs")); + Assert.True(results.Single().Uri.UriString.EndsWith("String.cs")); } private static async Task RunGotoDefinitionAsync(TestLspServer testLspServer, LSP.Location caret) diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs index a18b449d3cd47..52b7c5cd9e783 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Roslyn.Test.Utilities.TestGenerators; using Xunit; @@ -216,7 +217,7 @@ class B var results = await RunGotoTypeDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); var result = Assert.Single(results); - Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.Scheme); + Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.GetRequiredParsedUri().Scheme); } [Theory, CombinatorialData] @@ -279,7 +280,7 @@ End Class CreateTextDocumentPositionParams(caret), CancellationToken.None); } - private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, Uri fileUri) + private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, DocumentUri fileUri) { var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None); return lspWorkspace!; diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs index 094dec54538ad..a55ee70852925 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs @@ -232,7 +232,7 @@ private protected static async Task InsertTextAsync( private protected static Task> RunGetDocumentPullDiagnosticsAsync( TestLspServer testLspServer, - Uri uri, + DocumentUri uri, bool useVSDiagnostics, string? previousResultId = null, bool useProgress = false, @@ -367,7 +367,7 @@ private protected static InitializationOptions GetInitializationOptions( /// private protected record TestDiagnosticResult(TextDocumentIdentifier TextDocument, string? ResultId, LSP.Diagnostic[]? Diagnostics) { - public Uri Uri { get; } = TextDocument.Uri; + public DocumentUri Uri { get; } = TextDocument.Uri; } [DiagnosticAnalyzer(InternalLanguageNames.TypeScript), PartNotDiscoverable] diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs index 140598171eaa0..09974b7387be1 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AdditionalFileDiagnosticsTests.cs @@ -40,7 +40,7 @@ public async Task TestWorkspaceDiagnosticsReportsAdditionalFileDiagnostic(bool u @"C:\C.cs: []", @$"C:\Test.txt: [{MockAdditionalFileDiagnosticAnalyzer.Id}]", @"C:\CSProj1.csproj: []" - ], results.Select(r => $"{r.Uri.LocalPath}: [{string.Join(", ", r.Diagnostics.Select(d => d.Code?.Value?.ToString()))}]")); + ], results.Select(r => $"{r.Uri.GetRequiredParsedUri().LocalPath}: [{string.Join(", ", r.Diagnostics.Select(d => d.Code?.Value?.ToString()))}]")); // Asking again should give us back an unchanged diagnostic. var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); @@ -65,7 +65,7 @@ public async Task TestWorkspaceDiagnosticsWithRemovedAdditionalFile(bool useVSDi AssertEx.Empty(results[0].Diagnostics); Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); - Assert.Equal(@"C:\Test.txt", results[1].Uri.LocalPath); + Assert.Equal(@"C:\Test.txt", results[1].Uri.GetRequiredParsedUri().LocalPath); AssertEx.Empty(results[2].Diagnostics); var initialSolution = testLspServer.GetCurrentSolution(); @@ -101,10 +101,10 @@ public async Task TestWorkspaceDiagnosticsWithAdditionalFileInMultipleProjects(b Assert.Equal(6, results.Length); Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); - Assert.Equal(@"C:\Test.txt", results[1].Uri.LocalPath); + Assert.Equal(@"C:\Test.txt", results[1].Uri.GetRequiredParsedUri().LocalPath); Assert.Equal("CSProj1", ((LSP.VSDiagnostic)results[1].Diagnostics.Single()).Projects.First().ProjectName); Assert.Equal(MockAdditionalFileDiagnosticAnalyzer.Id, results[4].Diagnostics.Single().Code); - Assert.Equal(@"C:\Test.txt", results[4].Uri.LocalPath); + Assert.Equal(@"C:\Test.txt", results[4].Uri.GetRequiredParsedUri().LocalPath); Assert.Equal("CSProj2", ((LSP.VSDiagnostic)results[4].Diagnostics.Single()).Projects.First().ProjectName); // Asking again should give us back an unchanged diagnostic. diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 8e5958674d2b3..f87f09eeeef41 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -69,7 +69,7 @@ public async Task TestDocumentDiagnosticsForOpenFilesWithFSAOff(bool useVSDiagno testLspServer, document.GetURI(), useVSDiagnostics); Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href.ParsedUri); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/fsharp/issues/15972")] @@ -636,7 +636,7 @@ public async Task TestDocumentDiagnosticsFromRazorServer(bool useVSDiagnostics, // Assert that we have diagnostics even though the option is set to push. Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href.ParsedUri); } [Theory, CombinatorialData] @@ -660,7 +660,7 @@ public async Task TestDocumentDiagnosticsFromLiveShareServer(bool useVSDiagnosti // Assert that we have diagnostics even though the option is set to push. Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code); - Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href); + Assert.NotNull(results.Single().Diagnostics.Single().CodeDescription!.Href.ParsedUri); } [Theory, CombinatorialData] @@ -1374,7 +1374,7 @@ public async Task TestNoWorkspaceDiagnosticsForClosedFilesInProjectsWithIncorrec var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); - Assert.False(results.Any(r => r.TextDocument!.Uri.LocalPath.Contains(".ts"))); + Assert.False(results.Any(r => r.TextDocument!.Uri.GetRequiredParsedUri().LocalPath.Contains(".ts"))); } [Theory, CombinatorialData] @@ -1549,7 +1549,7 @@ class A {"; var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal(ProtocolConversions.CreateAbsoluteUri(@"C:\test1.cs"), results[0].TextDocument!.Uri); + Assert.Equal(ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test1.cs"), results[0].TextDocument!.Uri); Assert.Equal("CS1513", results[0].Diagnostics.Single().Code); Assert.Equal(1, results[0].Diagnostics.Single().Range.Start.Line); AssertEx.Empty(results[1].Diagnostics); @@ -1945,9 +1945,9 @@ public async Task TestWorkspaceDiagnosticsDoesNotThrowIfProjectWithoutFilePathEx var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal(@"C:/C.cs", results[0].TextDocument.Uri.AbsolutePath); - Assert.Equal(@"C:/CSProj1.csproj", results[1].TextDocument.Uri.AbsolutePath); - Assert.Equal(@"C:/C2.cs", results[2].TextDocument.Uri.AbsolutePath); + Assert.Equal(@"C:/C.cs", results[0].TextDocument.Uri.GetRequiredParsedUri().AbsolutePath); + Assert.Equal(@"C:/CSProj1.csproj", results[1].TextDocument.Uri.GetRequiredParsedUri().AbsolutePath); + Assert.Equal(@"C:/C2.cs", results[2].TextDocument.Uri.GetRequiredParsedUri().AbsolutePath); } [Theory, CombinatorialData] diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs index ce607c6a9fc25..27f1228914d57 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/WorkspaceProjectDiagnosticsTests.cs @@ -30,7 +30,7 @@ public async Task TestWorkspaceDiagnosticsReportsProjectDiagnostic(bool useVSDia Assert.Equal(2, results.Length); AssertEx.Empty(results[0].Diagnostics); Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); - Assert.Equal(ProtocolConversions.CreateAbsoluteUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); + Assert.Equal(ProtocolConversions.CreateAbsoluteDocumentUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); // Asking again should give us back an unchanged diagnostic. var results2 = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics, previousResults: CreateDiagnosticParamsFromPreviousReports(results)); @@ -47,7 +47,7 @@ public async Task TestWorkspaceDiagnosticsWithRemovedProject(bool useVSDiagnosti Assert.Equal(2, results.Length); AssertEx.Empty(results[0].Diagnostics); Assert.Equal(MockProjectDiagnosticAnalyzer.Id, results[1].Diagnostics.Single().Code); - Assert.Equal(ProtocolConversions.CreateAbsoluteUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); + Assert.Equal(ProtocolConversions.CreateAbsoluteDocumentUri(testLspServer.GetCurrentSolution().Projects.First().FilePath!), results[1].Uri); var initialSolution = testLspServer.GetCurrentSolution(); var newSolution = initialSolution.RemoveProject(initialSolution.Projects.First().Id); diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs index f16259e730118..cbd9da7f4176c 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs @@ -99,7 +99,7 @@ void M() Assert.Empty(testLspServer.GetTrackedTexts()); } - private static async Task GetLSPSolutionAsync(TestLspServer testLspServer, Uri uri) + private static async Task GetLSPSolutionAsync(TestLspServer testLspServer, DocumentUri uri) { var (_, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new TextDocumentIdentifier { Uri = uri }, CancellationToken.None).ConfigureAwait(false); Contract.ThrowIfNull(lspDocument); diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs index 83bb8b0438328..5669360eb871a 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler.DocumentChanges; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -457,11 +458,11 @@ void M() return (testLspServer, locationTyped, documentText.ToString()); } - private static Task DidOpen(TestLspServer testLspServer, Uri uri) => testLspServer.OpenDocumentAsync(uri); + private static Task DidOpen(TestLspServer testLspServer, DocumentUri uri) => testLspServer.OpenDocumentAsync(uri); - private static async Task DidChange(TestLspServer testLspServer, Uri uri, params (int line, int column, string text)[] changes) + private static async Task DidChange(TestLspServer testLspServer, DocumentUri uri, params (int line, int column, string text)[] changes) => await testLspServer.InsertTextAsync(uri, changes); - private static async Task DidClose(TestLspServer testLspServer, Uri uri) => await testLspServer.CloseDocumentAsync(uri); + private static async Task DidClose(TestLspServer testLspServer, DocumentUri uri) => await testLspServer.CloseDocumentAsync(uri); } } diff --git a/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs b/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs index 8dd97f5428f23..ea3ba4eafacf9 100644 --- a/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs @@ -74,11 +74,11 @@ public partial class MyComponent { Project = new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(project.FilePath) + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(project.FilePath) }, Document = new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(newFilePath) + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(newFilePath) }, Contents = input }; diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs index e4ae2a35b33cc..a852df923d3d4 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -107,7 +108,7 @@ void M() private static async Task RunFormatDocumentAsync( TestLspServer testLspServer, - Uri uri, + DocumentUri uri, bool insertSpaces = true, int tabSize = 4) { @@ -115,7 +116,7 @@ void M() CreateDocumentFormattingParams(uri, insertSpaces, tabSize), CancellationToken.None); } - private static LSP.DocumentFormattingParams CreateDocumentFormattingParams(Uri uri, bool insertSpaces, int tabSize) + private static LSP.DocumentFormattingParams CreateDocumentFormattingParams(DocumentUri uri, bool insertSpaces, int tabSize) => new LSP.DocumentFormattingParams() { TextDocument = CreateTextDocumentIdentifier(uri), diff --git a/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs index 3787a64d7a2d8..d0f66a226c3ae 100644 --- a/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs @@ -43,7 +43,7 @@ public async Task CanExecuteRequestHandler(bool mutatingLspWorkspace) var request = new TestRequestTypeOne(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var response = await server.ExecuteRequestAsync(TestDocumentHandler.MethodName, request, CancellationToken.None); Assert.Equal(typeof(TestDocumentHandler).Name, response); @@ -65,7 +65,7 @@ public async Task CanExecuteNotificationHandler(bool mutatingLspWorkspace) var request = new TestRequestTypeOne(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); await server.ExecuteNotificationAsync(TestNotificationHandler.MethodName, request); @@ -90,7 +90,7 @@ public async Task CanExecuteLanguageSpecificHandler(bool mutatingLspWorkspace) var request = new TestRequestTypeOne(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.fs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.fs") }); var response = await server.ExecuteRequestAsync(TestDocumentHandler.MethodName, request, CancellationToken.None); Assert.Equal(typeof(TestLanguageSpecificHandler).Name, response); @@ -103,7 +103,7 @@ public async Task CanExecuteLanguageSpecificHandlerWithDifferentRequestTypes(boo var request = new TestRequestTypeTwo(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.vb") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.vb") }); var response = await server.ExecuteRequestAsync(TestDocumentHandler.MethodName, request, CancellationToken.None); Assert.Equal(typeof(TestLanguageSpecificHandlerWithDifferentParams).Name, response); @@ -144,7 +144,7 @@ public async Task NonMutatingHandlerExceptionNFWIsReported(bool mutatingLspWorks var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -172,7 +172,7 @@ public async Task NonMutatingHandlerExceptionNFWIsNotReportedForLocalRpcExceptio var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -200,7 +200,7 @@ public async Task MutatingHandlerExceptionNFWIsReported(bool mutatingLspWorkspac var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -230,7 +230,7 @@ public async Task NonMutatingHandlerCancellationExceptionNFWIsNotReported(bool m var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -258,7 +258,7 @@ public async Task MutatingHandlerCancellationExceptionNFWIsNotReported(bool muta var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs") + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -287,7 +287,7 @@ public async Task TestMutatingHandlerCrashesIfUnableToDetermineLanguage(bool mut // Run a mutating request against a file which we have no saved languageId for // and where the language cannot be determined from the URI. // This should crash the server. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"untitled:untitledFile"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"untitled:untitledFile"); var request = new TestRequestTypeOne(new TextDocumentIdentifier { Uri = looseFileUri diff --git a/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs b/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs index b9faef82ff489..2df0109f0d22d 100644 --- a/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs @@ -93,7 +93,7 @@ public async Task LanguageServerSucceedsAfterInitializedCalled(bool mutatingLspW TextDocument = new TextDocumentItem { Text = "sometext", - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\location\file.json"), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\location\file.json"), } }; @@ -111,7 +111,7 @@ public async Task LanguageServerRejectsRequestsBeforeInitialized(bool mutatingLs TextDocument = new TextDocumentItem { Text = "sometext", - Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\location\file.json"), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\location\file.json"), } }; var ex = await Assert.ThrowsAsync(async () => await server.ExecuteRequestAsync(Methods.TextDocumentDidOpenName, didOpenParams, CancellationToken.None)); diff --git a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs index 0aaf597dec428..5fc0cac555ce3 100644 --- a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs @@ -128,7 +128,7 @@ static void Main(string[] args) Assert.NotNull(results.Changes); Assert.Null(results.DocumentChanges); - Assert.True(results.Changes!.TryGetValue(ProtocolConversions.GetDocumentFilePathFromUri(documentUri), out edits)); + Assert.True(results.Changes!.TryGetValue(ProtocolConversions.GetDocumentFilePathFromUri(documentUri.GetRequiredParsedUri()), out edits)); } var documentText = await document.GetTextAsync(); diff --git a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs index 36e37923ab780..d8d84b5ccfa1f 100644 --- a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.MetadataAsSource; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -116,10 +117,10 @@ public static void WriteLine(string value) {} Assert.NotNull(definitionFromMetadata); Assert.NotEmpty(definitionFromMetadata); - Assert.Contains("String.cs", definitionFromMetadata.Single().Uri.LocalPath); + Assert.Contains("String.cs", definitionFromMetadata.Single().Uri.UriString); } - private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, Uri fileUri) + private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, DocumentUri fileUri) { var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None); return lspWorkspace!; diff --git a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index be2a76a84c976..b8e8f780e4652 100644 --- a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -36,7 +37,7 @@ void M() Assert.Null(GetMiscellaneousDocument(testLspServer)); // Open an empty loose file and make a request to verify it gets added to the misc workspace. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SomeFile.cs"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SomeFile.cs"); await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false); // Verify file is added to the misc file workspace. @@ -62,7 +63,7 @@ void M() Assert.Null(GetMiscellaneousDocument(testLspServer)); - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SomeFile.cs"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SomeFile.cs"); // Open an empty loose file and make a request to verify it gets added to the misc workspace. await testLspServer.OpenDocumentAsync(looseFileUri, string.Empty).ConfigureAwait(false); @@ -100,7 +101,7 @@ void M() Assert.Null(GetMiscellaneousDocument(testLspServer)); // Open an empty loose file and make a request to verify it gets added to the misc workspace. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SomeFile.cs"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SomeFile.cs"); await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false); await AssertFileInMiscWorkspaceAsync(testLspServer, looseFileUri).ConfigureAwait(false); @@ -147,7 +148,7 @@ void M() // Open an empty loose file and make a request to verify it gets added to the misc workspace. // Include some Unicode characters to test URL handling. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri("C:\\\ue25b\ud86d\udeac.cs"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri("C:\\\ue25b\ud86d\udeac.cs"); var looseFileTextDocumentIdentifier = new LSP.TextDocumentIdentifier { Uri = looseFileUri }; await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false); @@ -158,7 +159,7 @@ void M() Contract.ThrowIfNull(miscDocument); Assert.True(miscWorkspace.CurrentSolution.ContainsDocument(miscDocument.Id)); - var documentPath = ProtocolConversions.GetDocumentFilePathFromUri(looseFileUri); + var documentPath = ProtocolConversions.GetDocumentFilePathFromUri(looseFileUri.GetRequiredParsedUri()); // Update the workspace to contain the loose file. var project = testLspServer.GetCurrentSolution().Projects.Single(); @@ -197,7 +198,7 @@ void M() Assert.Null(GetMiscellaneousDocument(testLspServer)); // Open an empty loose file and make a request to verify it gets added to the misc workspace. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SomeFile.cs"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SomeFile.cs"); await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false); // Trigger a request and assert we got a file in the misc workspace. @@ -229,9 +230,7 @@ void M() // Open an empty loose file that hasn't been saved with a name. -#pragma warning disable RS0030 // Do not use banned APIs - var looseFileUri = new Uri("untitled:untitledFile"); -#pragma warning restore + var looseFileUri = new DocumentUri("untitled:untitledFile"); await testLspServer.OpenDocumentAsync(looseFileUri, source, languageId: "csharp").ConfigureAwait(false); @@ -262,9 +261,7 @@ void M() // Open an empty loose file that hasn't been saved with a name. -#pragma warning disable RS0030 // Do not use banned APIs - var looseFileUri = new Uri("untitled:untitledFile"); -#pragma warning restore + var looseFileUri = new DocumentUri("untitled:untitledFile"); await testLspServer.OpenDocumentAsync(looseFileUri, source, languageId: "csharp").ConfigureAwait(false); // Make an immediate followup request as soon as we queue the didOpen. @@ -292,13 +289,13 @@ void M() Assert.Equal(7, result.Single().Range.End.Character); } - private static async Task AssertFileInMiscWorkspaceAsync(TestLspServer testLspServer, Uri fileUri) + private static async Task AssertFileInMiscWorkspaceAsync(TestLspServer testLspServer, DocumentUri fileUri) { var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None); Assert.Equal(testLspServer.GetManagerAccessor().GetLspMiscellaneousFilesWorkspace(), lspWorkspace); } - private static async Task AssertFileInMainWorkspaceAsync(TestLspServer testLspServer, Uri fileUri) + private static async Task AssertFileInMainWorkspaceAsync(TestLspServer testLspServer, DocumentUri fileUri) { var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None).ConfigureAwait(false); Assert.Equal(testLspServer.TestWorkspace, lspWorkspace); diff --git a/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs b/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs index f9bf10d53f502..e975e0d51f4d0 100644 --- a/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs @@ -252,7 +252,7 @@ public async Task HandlerThatSkipsBuildingLSPSolutionGetsWorkspaceSolution(bool Assert.Null(solution); } - private static async Task ExecuteDidOpen(TestLspServer testLspServer, Uri documentUri) + private static async Task ExecuteDidOpen(TestLspServer testLspServer, DocumentUri documentUri) { var didOpenParams = new LSP.DidOpenTextDocumentParams { diff --git a/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs index 44befe94053bb..5abeb4692ae40 100644 --- a/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -99,13 +100,13 @@ public async Task SwitchingContextsChangesDefaultContext(bool mutatingLspWorkspa } } - internal static async Task RunGetProjectContext(TestLspServer testLspServer, Uri uri) + internal static async Task RunGetProjectContext(TestLspServer testLspServer, DocumentUri uri) { return await testLspServer.ExecuteRequestAsync(LSP.VSMethods.GetProjectContextsName, CreateGetProjectContextParams(uri), cancellationToken: CancellationToken.None); } - private static LSP.VSGetProjectContextsParams CreateGetProjectContextParams(Uri uri) + private static LSP.VSGetProjectContextsParams CreateGetProjectContextParams(DocumentUri uri) => new LSP.VSGetProjectContextsParams() { TextDocument = new LSP.TextDocumentItem { Uri = uri } diff --git a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs index c7f83533e1ade..4bda5874f00ff 100644 --- a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs @@ -44,9 +44,9 @@ public void CreateAbsoluteUri_LocalPaths_AllAscii() Assert.Equal(expectedAbsoluteUri, ProtocolConversions.GetAbsoluteUriString(filePath)); - var uri = ProtocolConversions.CreateAbsoluteUri(filePath); - Assert.Equal(expectedAbsoluteUri, uri.AbsoluteUri); - Assert.Equal(filePath, uri.LocalPath); + var uri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); + Assert.Equal(expectedAbsoluteUri, uri.GetRequiredParsedUri().AbsoluteUri); + Assert.Equal(filePath, uri.GetRequiredParsedUri().LocalPath); } } @@ -71,9 +71,9 @@ public void CreateAbsoluteUri_LocalPaths_Windows(string filePath, string expecte { Assert.Equal(expectedAbsoluteUri, ProtocolConversions.GetAbsoluteUriString(filePath)); - var uri = ProtocolConversions.CreateAbsoluteUri(filePath); - Assert.Equal(expectedAbsoluteUri, uri.AbsoluteUri); - Assert.Equal(filePath.Replace('/', '\\'), uri.LocalPath); + var uri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); + Assert.Equal(expectedAbsoluteUri, uri.GetRequiredParsedUri().AbsoluteUri); + Assert.Equal(filePath.Replace('/', '\\'), uri.GetRequiredParsedUri().LocalPath); } [ConditionalTheory(typeof(WindowsOnly))] @@ -85,9 +85,9 @@ public void CreateAbsoluteUri_LocalPaths_Normalized_Windows(string filePath, str { Assert.Equal(expectedRawUri, ProtocolConversions.GetAbsoluteUriString(filePath)); - var uri = ProtocolConversions.CreateAbsoluteUri(filePath); - Assert.Equal(expectedNormalizedUri, uri.AbsoluteUri); - Assert.Equal(Path.GetFullPath(filePath).Replace('/', '\\'), uri.LocalPath); + var uri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); + Assert.Equal(expectedNormalizedUri, uri.GetRequiredParsedUri().AbsoluteUri); + Assert.Equal(Path.GetFullPath(filePath).Replace('/', '\\'), uri.GetRequiredParsedUri().LocalPath); } [ConditionalTheory(typeof(UnixLikeOnly))] @@ -105,9 +105,9 @@ public void CreateAbsoluteUri_LocalPaths_Unix(string filePath, string expectedAb { Assert.Equal(expectedAbsoluteUri, ProtocolConversions.GetAbsoluteUriString(filePath)); - var uri = ProtocolConversions.CreateAbsoluteUri(filePath); - Assert.Equal(expectedAbsoluteUri, uri.AbsoluteUri); - Assert.Equal(filePath, uri.LocalPath); + var uri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); + Assert.Equal(expectedAbsoluteUri, uri.GetRequiredParsedUri().AbsoluteUri); + Assert.Equal(filePath, uri.GetRequiredParsedUri().LocalPath); } [ConditionalTheory(typeof(WindowsOnly))] @@ -130,7 +130,7 @@ public void CreateAbsoluteUri_LocalPaths_Unix(string filePath, string expectedAb public void CreateRelativePatternBaseUri_LocalPaths_Windows(string filePath, string expectedUri) { var uri = ProtocolConversions.CreateRelativePatternBaseUri(filePath); - Assert.Equal(expectedUri, uri.AbsoluteUri); + Assert.Equal(expectedUri, uri.GetRequiredParsedUri().AbsoluteUri); } [ConditionalTheory(typeof(UnixLikeOnly))] @@ -148,7 +148,7 @@ public void CreateRelativePatternBaseUri_LocalPaths_Windows(string filePath, str public void CreateRelativePatternBaseUri_LocalPaths_Unix(string filePath, string expectedRelativeUri) { var uri = ProtocolConversions.CreateRelativePatternBaseUri(filePath); - Assert.Equal(expectedRelativeUri, uri.AbsoluteUri); + Assert.Equal(expectedRelativeUri, uri.GetRequiredParsedUri().AbsoluteUri); } [ConditionalTheory(typeof(UnixLikeOnly))] @@ -160,9 +160,9 @@ public void CreateAbsoluteUri_LocalPaths_Normalized_Unix(string filePath, string { Assert.Equal(expectedRawUri, ProtocolConversions.GetAbsoluteUriString(filePath)); - var uri = ProtocolConversions.CreateAbsoluteUri(filePath); - Assert.Equal(expectedNormalizedUri, uri.AbsoluteUri); - Assert.Equal(filePath, uri.LocalPath); + var uri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); + Assert.Equal(expectedNormalizedUri, uri.GetRequiredParsedUri().AbsoluteUri); + Assert.Equal(filePath, uri.GetRequiredParsedUri().LocalPath); } [Theory] @@ -171,7 +171,7 @@ public void CreateAbsoluteUri_LocalPaths_Normalized_Unix(string filePath, string [InlineData("xy://host/%2525%EE%89%9B/%C2%89%EC%9E%BD")] public void CreateAbsoluteUri_Urls(string url) { - Assert.Equal(url, ProtocolConversions.CreateAbsoluteUri(url).AbsoluteUri); + Assert.Equal(url, ProtocolConversions.CreateAbsoluteDocumentUri(url).GetRequiredParsedUri().AbsoluteUri); } [Fact] @@ -324,7 +324,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); // Open an empty loose file. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SomeFile.cs"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SomeFile.cs"); await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false); var document = await GetTextDocumentAsync(testLspServer, looseFileUri); @@ -335,7 +335,7 @@ void M() Assert.True(projectContext.IsMiscellaneous); } - internal static async Task GetTextDocumentAsync(TestLspServer testLspServer, Uri uri) + internal static async Task GetTextDocumentAsync(TestLspServer testLspServer, DocumentUri uri) { var (_, _, textDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new TextDocumentIdentifier { Uri = uri }, CancellationToken.None); return textDocument; diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs index a4ae9d8449b3f..931aeaf473de0 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs @@ -91,7 +91,7 @@ void IA.M() var position = new LSP.Position { Line = 2, Character = 9 }; var results = await RunFindImplementationAsync(testLspServer, new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteUri($"C:\\{TestSpanMapper.GeneratedFileName}"), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), Range = new LSP.Range { Start = position, End = position } }); AssertLocationsEqual([TestSpanMapper.MappedFileLocation], results); diff --git a/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs index 6679d9089c729..7aaac23612b49 100644 --- a/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs @@ -21,7 +21,7 @@ public sealed class RelatedDocumentsTests(ITestOutputHelper testOutputHelper) { private static async Task RunGetRelatedDocumentsAsync( TestLspServer testLspServer, - Uri uri, + DocumentUri uri, bool useProgress = false) { BufferedProgress? progress = useProgress ? BufferedProgress.Create(null) : null; diff --git a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs index 68c71fadb2528..63569e7bcc5dd 100644 --- a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs @@ -170,7 +170,7 @@ void M2() var renameText = "RENAME"; var renameParams = CreateRenameParams(new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteUri($"C:\\{TestSpanMapper.GeneratedFileName}"), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), Range = new LSP.Range { Start = startPosition, End = endPosition } }, "RENAME"); diff --git a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs index f9eaf873a3a5f..72078a6891fdf 100644 --- a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs @@ -372,7 +372,7 @@ public async Task TestNoWorkspaceDiagnosticsForClosedFilesInProjectsWithIncorrec var results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer); - Assert.True(results.All(r => r.TextDocument!.Uri.LocalPath == "C:\\C.cs")); + Assert.True(results.All(r => r.TextDocument!.Uri.GetRequiredParsedUri().LocalPath == "C:\\C.cs")); } // [Fact] @@ -599,7 +599,7 @@ private static Task CloseDocumentAsync(TestLspServer testLspServer, Document doc private static async Task RunGetDocumentSpellCheckSpansAsync( TestLspServer testLspServer, - Uri uri, + DocumentUri uri, string? previousResultId = null, bool useProgress = false) { @@ -622,7 +622,7 @@ private static async Task RunGetDocumentS private static async Task RunGetWorkspaceSpellCheckSpansAsync( TestLspServer testLspServer, - ImmutableArray<(string resultId, Uri uri)>? previousResults = null, + ImmutableArray<(string resultId, DocumentUri uri)>? previousResults = null, bool useProgress = false) { BufferedProgress? progress = useProgress ? BufferedProgress.Create(null) : null; @@ -654,7 +654,7 @@ private static async Task InsertTextAsync( } private static VSInternalDocumentSpellCheckableParams CreateDocumentParams( - Uri uri, + DocumentUri uri, string? previousResultId = null, IProgress? progress = null) { @@ -667,7 +667,7 @@ private static VSInternalDocumentSpellCheckableParams CreateDocumentParams( } private static VSInternalWorkspaceSpellCheckableParams CreateWorkspaceParams( - ImmutableArray<(string resultId, Uri uri)>? previousResults = null, + ImmutableArray<(string resultId, DocumentUri uri)>? previousResults = null, IProgress? progress = null) { return new VSInternalWorkspaceSpellCheckableParams @@ -677,7 +677,7 @@ private static VSInternalWorkspaceSpellCheckableParams CreateWorkspaceParams( }; } - private static ImmutableArray<(string resultId, Uri uri)> CreateParamsFromPreviousReports(VSInternalWorkspaceSpellCheckableReport[] results) + private static ImmutableArray<(string resultId, DocumentUri uri)> CreateParamsFromPreviousReports(VSInternalWorkspaceSpellCheckableReport[] results) { return [.. results.Select(r => (r.ResultId!, r.TextDocument.Uri))]; } diff --git a/src/LanguageServer/ProtocolUnitTests/UriTests.cs b/src/LanguageServer/ProtocolUnitTests/UriTests.cs index 8fe9ef3348d4b..ccf43b5a7dc5c 100644 --- a/src/LanguageServer/ProtocolUnitTests/UriTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/UriTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CommonLanguageServerProtocol.Framework; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; @@ -44,7 +45,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); // Open an empty loose file with a file URI. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(filePath); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); await testLspServer.OpenDocumentAsync(looseFileUri, source, languageId: "csharp").ConfigureAwait(false); // Verify file is added to the misc file workspace. @@ -70,7 +71,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); // Open an empty loose file that hasn't been saved with a name. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"untitled:untitledFile"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"untitled:untitledFile"); await testLspServer.OpenDocumentAsync(looseFileUri, source, languageId: "csharp").ConfigureAwait(false); // Verify file is added to the misc file workspace. @@ -78,7 +79,7 @@ void M() Assert.True(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); - Assert.Equal(looseFileUri.OriginalString, document.FilePath); + Assert.Equal(looseFileUri.UriString, document.FilePath); } [Theory, CombinatorialData] @@ -100,7 +101,7 @@ public class A await using var testLspServer = await CreateXmlTestLspServerAsync(markup, mutatingLspWorkspace); var workspaceDocument = testLspServer.TestWorkspace.CurrentSolution.Projects.Single().Documents.Single(); - var expectedDocumentUri = ProtocolConversions.CreateAbsoluteUri(documentFilePath); + var expectedDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(documentFilePath); await testLspServer.OpenDocumentAsync(expectedDocumentUri).ConfigureAwait(false); @@ -115,8 +116,8 @@ public class A // Try again, this time with a uri with different case sensitivity. This is supported, and is needed by Xaml. { - var lowercaseUri = ProtocolConversions.CreateAbsoluteUri(documentFilePath.ToLowerInvariant()); - Assert.NotEqual(expectedDocumentUri.AbsolutePath, lowercaseUri.AbsolutePath); + var lowercaseUri = ProtocolConversions.CreateAbsoluteDocumentUri(documentFilePath.ToLowerInvariant()); + Assert.NotEqual(expectedDocumentUri.GetRequiredParsedUri().AbsolutePath, lowercaseUri.GetRequiredParsedUri().AbsolutePath); var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = lowercaseUri }, CancellationToken.None); Assert.False(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); @@ -138,9 +139,7 @@ public async Task TestWorkspaceDocument_WithFileAndGitScheme(bool mutatingLspWor // Add a git version of this document. Instead of "file://FILEPATH" the uri is "git://FILEPATH" -#pragma warning disable RS0030 // Do not use banned APIs - var gitDocumentUri = new Uri(fileDocumentUri.ToString().Replace("file", "git")); -#pragma warning restore + var gitDocumentUri = new DocumentUri(fileDocumentUri.ToString().Replace("file", "git")); var gitDocumentText = "GitText"; await testLspServer.OpenDocumentAsync(gitDocumentUri, gitDocumentText); @@ -191,9 +190,7 @@ public async Task TestFindsExistingDocumentWhenUriHasDifferentEncodingAsync(bool // Now make a request using the encoded document to ensure the server is able to find the document in misc C# files. var encodedUriString = @"git:/c:/Users/dabarbet/source/repos/ConsoleApp10/ConsoleApp10/Program.cs?%7B%7B%22path%22:%22c:%5C%5CUsers%5C%5Cdabarbet%5C%5Csource%5C%5Crepos%5C%5CConsoleApp10%5C%5CConsoleApp10%5C%5CProgram.cs%22,%22ref%22:%22~%22%7D%7D"; -#pragma warning disable RS0030 // Do not use banned APIs - var encodedUri = new Uri(encodedUriString, UriKind.Absolute); -#pragma warning restore RS0030 // Do not use banned APIs + var encodedUri = new DocumentUri(encodedUriString); var info = await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = encodedUri }), CancellationToken.None); Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); @@ -215,16 +212,14 @@ public async Task TestFindsExistingDocumentWhenUriHasDifferentCasingForCaseInsen { await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); -#pragma warning disable RS0030 // Do not use banned APIs - var upperCaseUri = new Uri(@"file:///C:/Users/dabarbet/source/repos/XUnitApp1/UnitTest1.cs", UriKind.Absolute); - var lowerCaseUri = new Uri(@"file:///c:/Users/dabarbet/source/repos/XUnitApp1/UnitTest1.cs", UriKind.Absolute); -#pragma warning restore RS0030 // Do not use banned APIs + var upperCaseUri = new DocumentUri(@"file:///C:/Users/dabarbet/source/repos/XUnitApp1/UnitTest1.cs"); + var lowerCaseUri = new DocumentUri(@"file:///c:/Users/dabarbet/source/repos/XUnitApp1/UnitTest1.cs"); // Execute the request as JSON directly to avoid the test client serializing System.Uri. var requestJson = $$$""" { "textDocument": { - "uri": "{{{upperCaseUri.OriginalString}}}", + "uri": "{{{upperCaseUri.UriString}}}", "languageId": "csharp", "text": "LSP text" } @@ -263,16 +258,14 @@ public async Task TestUsesDifferentDocumentForDifferentCaseWithNonUncUriAsync(bo { await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); -#pragma warning disable RS0030 // Do not use banned APIs - var upperCaseUri = new Uri(@"git:/Blah", UriKind.Absolute); - var lowerCaseUri = new Uri(@"git:/blah", UriKind.Absolute); -#pragma warning restore RS0030 // Do not use banned APIs + var upperCaseUri = new DocumentUri(@"git:/Blah"); + var lowerCaseUri = new DocumentUri(@"git:/blah"); // Execute the request as JSON directly to avoid the test client serializing System.Uri. var requestJson = $$$""" { "textDocument": { - "uri": "{{{upperCaseUri.OriginalString}}}", + "uri": "{{{upperCaseUri.UriString}}}", "languageId": "csharp", "text": "LSP text" } @@ -302,7 +295,7 @@ public async Task TestDoesNotCrashIfUnableToDetermineLanguageInfo(bool mutatingL await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); // Open an empty loose file that hasn't been saved with a name. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"untitled:untitledFile"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"untitled:untitledFile"); await testLspServer.OpenDocumentAsync(looseFileUri, "hello", languageId: "csharp").ConfigureAwait(false); // Verify file is added to the misc file workspace. @@ -310,7 +303,7 @@ public async Task TestDoesNotCrashIfUnableToDetermineLanguageInfo(bool mutatingL Assert.True(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); - Assert.Equal(looseFileUri.OriginalString, document.FilePath); + Assert.Equal(looseFileUri.UriString, document.FilePath); // Close the document (deleting the saved language information) await testLspServer.CloseDocumentAsync(looseFileUri); @@ -323,6 +316,41 @@ await Assert.ThrowsAnyAsync(async () Assert.False(testLspServer.GetQueueAccessor()!.Value.IsComplete()); } + [Theory] + // Invalid URIs + [InlineData(true, "file://invalid^uri")] + [InlineData(false, "file://invalid^uri")] + [InlineData(true, "perforce://%239/some/file/here/source.cs")] + [InlineData(false, "perforce://%239/some/file/here/source.cs")] + // Valid URI, but System.Uri cannot parse it. + [InlineData(true, "vscode-notebook-cell://dev-container+7b2/workspaces/devkit-crash/notebook.ipynb")] + [InlineData(false, "vscode-notebook-cell://dev-container+7b2/workspaces/devkit-crash/notebook.ipynb")] + // Valid URI, but System.Uri cannot parse it. + [InlineData(true, "perforce://@=1454483/some/file/here/source.cs")] + [InlineData(false, "perforce://@=1454483/some/file/here/source.cs")] + public async Task TestOpenDocumentWithInvalidUri(bool mutatingLspWorkspace, string uriString) + { + // Create a server that supports LSP misc files + await using var testLspServer = await CreateTestLspServerAsync(string.Empty, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); + + // Open file with a URI System.Uri cannot parse. This should not crash the server. + var invalidUri = new DocumentUri(uriString); + // ParsedUri should be null as System.Uri cannot parse it. + Assert.Null(invalidUri.ParsedUri); + await testLspServer.OpenDocumentAsync(invalidUri, string.Empty, languageId: "csharp").ConfigureAwait(false); + + // Verify requests succeed and that the file is in misc. + var info = await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, + new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = invalidUri }), CancellationToken.None); + Assert.Equal(WorkspaceKind.MiscellaneousFiles, info!.WorkspaceKind); + Assert.Equal(LanguageNames.CSharp, info.ProjectLanguage); + + // Verify we can modify the document in misc. + await testLspServer.InsertTextAsync(invalidUri, (0, 0, "hello")); + var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = invalidUri }, CancellationToken.None); + Assert.Equal("hello", (await document!.GetTextAsync()).ToString()); + } + private record class ResolvedDocumentInfo(string WorkspaceKind, string ProjectLanguage); private record class CustomResolveParams([property: JsonPropertyName("textDocument")] LSP.TextDocumentIdentifier TextDocument); diff --git a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs index 043c8670f2733..e01b73c21b2b0 100644 --- a/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/VSTypeScriptHandlerTests.cs @@ -21,6 +21,7 @@ using StreamJsonRpc; using Xunit; using Xunit.Abstractions; +using System.Text.Json.Serialization; namespace Microsoft.CodeAnalysis.LanguageServer.UnitTests; public class VSTypeScriptHandlerTests : AbstractLanguageServerProtocolTests @@ -127,7 +128,7 @@ private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Str return languageServer; } - internal record TSRequest(Uri Document, string Project); + internal record TSRequest([property: JsonConverter(typeof(DocumentUriConverter))] DocumentUri Document, string Project); [ExportTypeScriptLspServiceFactory(typeof(TypeScriptHandler)), PartNotDiscoverable, Shared] internal class TypeScriptHandlerFactory : AbstractVSTypeScriptRequestHandlerFactory @@ -157,7 +158,7 @@ internal class TypeScriptHandler : AbstractVSTypeScriptRequestHandler HandleRequestAsync(TSRequest request, TypeScriptRequestContext context, CancellationToken cancellationToken) diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs index 5866d332036e1..09581c9205d34 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/LspWorkspaceManagerTests.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; +using Roslyn.LanguageServer.Protocol; using Roslyn.Test.Utilities; using Roslyn.Test.Utilities.TestGenerators; using Xunit; @@ -246,7 +247,7 @@ public async Task TestLspTransfersDocumentToNewWorkspaceAsync(bool mutatingLspWo // Include some Unicode characters to test URL handling. var newDocumentFilePath = "C:\\NewDoc\\\ue25b\ud86d\udeac.cs"; var newDocumentInfo = DocumentInfo.Create(newDocumentId, "NewDoc.cs", filePath: newDocumentFilePath, loader: new TestTextLoader("New Doc")); - var newDocumentUri = ProtocolConversions.CreateAbsoluteUri(newDocumentFilePath); + var newDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(newDocumentFilePath); // Open the document via LSP before the workspace sees it. await testLspServer.OpenDocumentAsync(newDocumentUri, "LSP text"); @@ -372,8 +373,8 @@ public async Task TestLspUpdatesCorrectWorkspaceWithMultipleWorkspacesAsync(bool Assert.True(IsWorkspaceRegistered(testLspServer.TestWorkspace, testLspServer)); Assert.True(IsWorkspaceRegistered(testWorkspaceTwo, testLspServer)); - var firstWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteUri(@"C:\FirstWorkspace.cs"); - var secondWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SecondWorkspace.cs"); + var firstWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\FirstWorkspace.cs"); + var secondWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SecondWorkspace.cs"); await testLspServer.OpenDocumentAsync(firstWorkspaceDocumentUri); // Verify we can get both documents from their respective workspaces. @@ -427,8 +428,8 @@ public async Task TestWorkspaceEventUpdatesCorrectWorkspaceWithMultipleWorkspace // Wait for workspace operations to complete for the second workspace. await WaitForWorkspaceOperationsAsync(testWorkspaceTwo); - var firstWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteUri(@"C:\FirstWorkspace.cs"); - var secondWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SecondWorkspace.cs"); + var firstWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\FirstWorkspace.cs"); + var secondWorkspaceDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SecondWorkspace.cs"); await testLspServer.OpenDocumentAsync(firstWorkspaceDocumentUri); // Verify we can get both documents from their respective workspaces. @@ -542,7 +543,7 @@ public async Task TestLspDocumentPreferredOverProjectSystemDocumentAddInMutating // Open the doc var filePath = "c:\\\ue25b\ud86d\udeac.cs"; - var documentUri = ProtocolConversions.CreateAbsoluteUri(filePath); + var documentUri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath); await testLspServer.OpenDocumentAsync(documentUri, "Text"); // Initially the doc will be in the lsp misc workspace. @@ -750,7 +751,7 @@ public async Task TestForksWithRemovedGeneratorAsync(bool mutatingLspWorkspace) Assert.NotSame(testLspServer.TestWorkspace.CurrentSolution, sourceGeneratedDocument.Project.Solution); } - private static async Task OpenDocumentAndVerifyLspTextAsync(Uri documentUri, TestLspServer testLspServer, string openText = "LSP text") + private static async Task OpenDocumentAndVerifyLspTextAsync(DocumentUri documentUri, TestLspServer testLspServer, string openText = "LSP text") { await testLspServer.OpenDocumentAsync(documentUri, openText); @@ -766,7 +767,7 @@ private static bool IsWorkspaceRegistered(Workspace workspace, TestLspServer tes return testLspServer.GetManagerAccessor().IsWorkspaceRegistered(workspace); } - private static async Task<(Workspace? workspace, Document? document)> GetLspWorkspaceAndDocumentAsync(Uri uri, TestLspServer testLspServer) + private static async Task<(Workspace? workspace, Document? document)> GetLspWorkspaceAndDocumentAsync(DocumentUri uri, TestLspServer testLspServer) { var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(CreateTextDocumentIdentifier(uri), CancellationToken.None).ConfigureAwait(false); return (workspace, document as Document); diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentUriTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentUriTests.cs index e71bedfbdb23e..4303d979695cc 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentUriTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentUriTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -32,8 +32,8 @@ public async Task UrisRoundTrip() new SourceGeneratorIdentity("GeneratorAssembly", "Generator.dll", new Version(1, 0), "GeneratorType"), HintName); var uri = SourceGeneratedDocumentUri.Create(identity); - Assert.Equal(SourceGeneratedDocumentUri.Scheme, uri.Scheme); - var deserialized = SourceGeneratedDocumentUri.DeserializeIdentity(testLspServer.TestWorkspace.CurrentSolution, uri); + Assert.Equal(SourceGeneratedDocumentUri.Scheme, uri.GetRequiredParsedUri().Scheme); + var deserialized = SourceGeneratedDocumentUri.DeserializeIdentity(testLspServer.TestWorkspace.CurrentSolution, uri.GetRequiredParsedUri()); AssertEx.NotNull(deserialized); Assert.Equal(identity, deserialized.Value); @@ -41,4 +41,4 @@ public async Task UrisRoundTrip() // Debug name is not considered as a the usual part of equality, but we want to ensure we pass this through too Assert.Equal(generatedDocumentId.DebugName, deserialized.Value.DocumentId.DebugName); } -} \ No newline at end of file +} diff --git a/src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorCohostDocumentRequestHandler.cs b/src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorCohostDocumentRequestHandler.cs index 30fb43c5301d7..53a3706e7c329 100644 --- a/src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorCohostDocumentRequestHandler.cs +++ b/src/Tools/ExternalAccess/Razor/Cohost/AbstractRazorCohostDocumentRequestHandler.cs @@ -20,7 +20,7 @@ internal abstract class AbstractRazorCohostDocumentRequestHandler context.Method; - internal Uri? Uri => context.TextDocument?.GetURI(); + + [Obsolete("Use DocumentUri instead")] + internal Uri? Uri => context.TextDocument?.GetURI().GetRequiredParsedUri(); + internal DocumentUri? DocumentUri => context.TextDocument?.GetURI(); /// internal Workspace? Workspace => context.Workspace; /// diff --git a/src/Tools/ExternalAccess/Razor/RazorUri.cs b/src/Tools/ExternalAccess/Razor/RazorUri.cs index dd0e03df5dab1..f2366f1f09645 100644 --- a/src/Tools/ExternalAccess/Razor/RazorUri.cs +++ b/src/Tools/ExternalAccess/Razor/RazorUri.cs @@ -4,14 +4,19 @@ using System; using Microsoft.CodeAnalysis.LanguageServer; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; internal static class RazorUri { + [Obsolete("Use RazorUri.GetUriFromFilePath instead")] public static Uri CreateAbsoluteUri(string absolutePath) => ProtocolConversions.CreateAbsoluteUri(absolutePath); + public static DocumentUri CreateAbsoluteDocumentUri(string absolutePath) + => ProtocolConversions.CreateAbsoluteDocumentUri(absolutePath); + public static string GetDocumentFilePathFromUri(Uri uri) => ProtocolConversions.GetDocumentFilePathFromUri(uri); } diff --git a/src/Tools/ExternalAccess/Razor/SolutionExtensions.cs b/src/Tools/ExternalAccess/Razor/SolutionExtensions.cs index 358ea29bf613b..efff1002c6d9a 100644 --- a/src/Tools/ExternalAccess/Razor/SolutionExtensions.cs +++ b/src/Tools/ExternalAccess/Razor/SolutionExtensions.cs @@ -4,16 +4,17 @@ using System; using System.Collections.Immutable; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; internal static class SolutionExtensions { public static ImmutableArray GetTextDocuments(this Solution solution, Uri documentUri) - => LanguageServer.Extensions.GetTextDocuments(solution, documentUri); + => LanguageServer.Extensions.GetTextDocuments(solution, new(documentUri)); public static ImmutableArray GetDocumentIds(this Solution solution, Uri documentUri) - => LanguageServer.Extensions.GetDocumentIds(solution, documentUri); + => LanguageServer.Extensions.GetDocumentIds(solution, new(documentUri)); public static int GetWorkspaceVersion(this Solution solution) => solution.WorkspaceVersion; diff --git a/src/Tools/ExternalAccess/Razor/TextDocumentExtensions.cs b/src/Tools/ExternalAccess/Razor/TextDocumentExtensions.cs index d9ef4e5898b5a..41734d31af7fe 100644 --- a/src/Tools/ExternalAccess/Razor/TextDocumentExtensions.cs +++ b/src/Tools/ExternalAccess/Razor/TextDocumentExtensions.cs @@ -6,12 +6,16 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.ExternalAccess.Razor; internal static class TextDocumentExtensions { public static Uri CreateUri(this TextDocument document) + => document.GetURI().GetRequiredParsedUri(); + + public static DocumentUri CreateDocumentUri(this TextDocument document) => document.GetURI(); public static async Task GetChecksumAsync(this TextDocument document, CancellationToken cancellationToken) diff --git a/src/Tools/ExternalAccess/Xaml/External/ResolveDataConversions.cs b/src/Tools/ExternalAccess/Xaml/External/ResolveDataConversions.cs index bec4c319fe13a..4def672c4537a 100644 --- a/src/Tools/ExternalAccess/Xaml/External/ResolveDataConversions.cs +++ b/src/Tools/ExternalAccess/Xaml/External/ResolveDataConversions.cs @@ -4,7 +4,9 @@ using System; using System.Text.Json; +using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; using LSP = Roslyn.LanguageServer.Protocol; @@ -16,20 +18,20 @@ private record DataResolveData(object Data, LSP.TextDocumentIdentifier Document) private record DataIdResolveData(long DataId, LSP.TextDocumentIdentifier Document) : DocumentResolveData(Document); public static object ToResolveData(object data, Uri uri) - => new DataResolveData(data, new LSP.TextDocumentIdentifier { Uri = uri }); + => new DataResolveData(data, new LSP.TextDocumentIdentifier { Uri = new(uri) }); public static (object? data, Uri? uri) FromResolveData(object? requestData) { Contract.ThrowIfNull(requestData); var resolveData = JsonSerializer.Deserialize((JsonElement)requestData); - return (resolveData?.Data, resolveData?.Document.Uri); + return (resolveData?.Data, resolveData?.Document.Uri.GetRequiredParsedUri()); } internal static object ToCachedResolveData(object data, Uri uri, ResolveDataCache resolveDataCache) { var dataId = resolveDataCache.UpdateCache(data); - return new DataIdResolveData(dataId, new LSP.TextDocumentIdentifier { Uri = uri }); + return new DataIdResolveData(dataId, new LSP.TextDocumentIdentifier { Uri = new(uri) }); } internal static (object? data, Uri? uri) FromCachedResolveData(object? lspData, ResolveDataCache resolveDataCache) @@ -48,6 +50,6 @@ internal static (object? data, Uri? uri) FromCachedResolveData(object? lspData, var data = resolveDataCache.GetCachedEntry(resolveData.DataId); var document = resolveData.Document; - return (data, document.Uri); + return (data, document.Uri.GetRequiredParsedUri()); } } diff --git a/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs b/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs index 847df9d9dcc31..7256368655b43 100644 --- a/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs +++ b/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.LanguageServer.Handler; +using Roslyn.LanguageServer.Protocol; using LSP = Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.ExternalAccess.Xaml; @@ -24,7 +25,7 @@ public XamlRequestHandlerBase(IXamlRequestHandler? xamlRequ public bool RequiresLSPSolution => true; public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(TRequest request) - => new() { Uri = GetTextDocumentUri(request) }; + => new() { Uri = new(GetTextDocumentUri(request)) }; public abstract Uri GetTextDocumentUri(TRequest request); diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs index 0559d1c49b659..bc93359b89082 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs @@ -46,7 +46,7 @@ internal sealed partial class DocumentOutlineViewModel { TextDocument = new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteUri(textViewFilePath), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(textViewFilePath), }, UseHierarchicalSymbols = true }; diff --git a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs index 04f24b82d0579..219c53b9db340 100644 --- a/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs +++ b/src/VisualStudio/Core/Def/NavigateTo/RoslynSearchResultViewFactory.cs @@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.LanguageServer; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Search.Data; +using Roslyn.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.NavigateTo; @@ -66,7 +67,7 @@ public Task> GetPreviewPanelsAsync(S Uri? absoluteUri; if (document.SourceGeneratedDocumentIdentity is not null) { - absoluteUri = SourceGeneratedDocumentUri.Create(document.SourceGeneratedDocumentIdentity.Value); + absoluteUri = SourceGeneratedDocumentUri.Create(document.SourceGeneratedDocumentIdentity.Value).GetRequiredParsedUri(); } else { @@ -89,6 +90,7 @@ public Task> GetPreviewPanelsAsync(S { new RoslynSearchResultPreviewPanel( _provider, + // Editor APIs require a parseable System.Uri instance absoluteUri, projectGuid, roslynResult.SearchResult.NavigableItem.SourceSpan.ToSpan(), diff --git a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs index 93b7878aa2496..817967df6281b 100644 --- a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs +++ b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs @@ -287,7 +287,12 @@ public async Task RefreshAllFilesAsync() public async Task GetDocumentSpanFromLocationAsync(LSP.Location location, CancellationToken cancellationToken) { - var document = GetOrAddDocument(location.Uri.LocalPath); + if (location.Uri.ParsedUri is null) + { + return null; + } + + var document = GetOrAddDocument(location.Uri.ParsedUri.LocalPath); if (document == null) { return null; diff --git a/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs b/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs index bf830d1fd3bae..9f89d1b453f05 100644 --- a/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs +++ b/src/VisualStudio/LiveShare/Test/ProjectsHandlerTests.cs @@ -35,7 +35,7 @@ private static CustomProtocol.Project CreateLspProject(Project project) { Language = project.Language, Name = project.Name, - SourceFiles = [.. project.Documents.Select(document => document.GetURI())] + SourceFiles = [.. project.Documents.Select(document => document.GetURI().GetRequiredParsedUri())] }; } } diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs index 6511946b2de07..28bd323a8d0e5 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs @@ -115,7 +115,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe if (sourceDefinition.Span != null) { // If the Span is not null, use the span. - var document = await solution.GetTextDocumentAsync(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteUri(sourceDefinition.FilePath) }, cancellationToken).ConfigureAwait(false); + var document = await solution.GetTextDocumentAsync(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath) }, cancellationToken).ConfigureAwait(false); if (document != null) { return await ProtocolConversions.TextSpanToLocationAsync( @@ -132,7 +132,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe var sourceText = SourceText.From(fileStream); return new LSP.Location { - Uri = new Uri(sourceDefinition.FilePath), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath), Range = ProtocolConversions.TextSpanToRange(sourceDefinition.Span.Value, sourceText) }; } @@ -144,7 +144,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe return new LSP.Location { - Uri = new Uri(sourceDefinition.FilePath), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath), Range = new LSP.Range() { Start = position, End = position } }; } @@ -182,7 +182,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location { - Uri = new Uri(declarationFile.FilePath), + Uri = ProtocolConversions.CreateAbsoluteDocumentUri(declarationFile.FilePath), Range = ProtocolConversions.LinePositionToRange(linePosSpan), }); } diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs index d973ca8e34384..d609e3cd0ddc1 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs @@ -25,8 +25,7 @@ public XamlRequestExecutionQueue( protected internal override void BeforeRequest(TRequest request) { - if (request is ITextDocumentParams textDocumentParams && - textDocumentParams.TextDocument is { Uri: { IsAbsoluteUri: true } documentUri }) + if (request is ITextDocumentParams textDocumentParams && textDocumentParams.TextDocument.Uri.ParsedUri is Uri documentUri && documentUri.IsAbsoluteUri) { _projectService.TrackOpenDocument(documentUri.LocalPath); } From 5472092905fd3864762b885696ee2a1f495332e4 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Tue, 14 Jan 2025 15:54:12 -0800 Subject: [PATCH 2/9] Review feedback --- .../Protocol/Protocol/Converters/DocumentUriConverter.cs | 1 + src/LanguageServer/Protocol/Protocol/DocumentUri.cs | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs b/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs index c2a6b95d90476..f5807c7bab1f0 100644 --- a/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs +++ b/src/LanguageServer/Protocol/Protocol/Converters/DocumentUriConverter.cs @@ -12,6 +12,7 @@ namespace Roslyn.LanguageServer.Protocol; /// Converts the LSP spec URI string into our custom wrapper for URI strings. /// We do not convert directly to as it is unable to handle /// certain valid RFC spec URIs. We do not want serialization / deserialization to fail if we cannot parse the URI. +/// See https://github.com/dotnet/runtime/issues/64707 /// internal class DocumentUriConverter : JsonConverter { diff --git a/src/LanguageServer/Protocol/Protocol/DocumentUri.cs b/src/LanguageServer/Protocol/Protocol/DocumentUri.cs index cc2eaeab69b8e..cf38fe388330d 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentUri.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentUri.cs @@ -80,10 +80,12 @@ public bool Equals(DocumentUri otherUri) return true; } - // If either of the URIs cannot be parsed, we'll compare the original URI strings. + // If either of the URIs cannot be parsed if (otherUri.ParsedUri is null || this.ParsedUri is null) { - return this.UriString == otherUri.UriString; + // Bail if we cannot parse either of the URIs. We already determined the URI strings are not equal + // and we need to be able to parse the URIs to do deeper equivalency checks. + return false; } // Next we compare the parsed URIs to handle various casing and encoding scenarios (for example - different schemes may handle casing differently). From 6ca67b9e6f2963509f693015cc8579778dc73bbb Mon Sep 17 00:00:00 2001 From: David Barbet Date: Tue, 14 Jan 2025 16:23:13 -0800 Subject: [PATCH 3/9] additional feedback --- src/LanguageServer/Protocol/RoslynLanguageServer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LanguageServer/Protocol/RoslynLanguageServer.cs b/src/LanguageServer/Protocol/RoslynLanguageServer.cs index ad65228f893d9..8a4e9b2a45923 100644 --- a/src/LanguageServer/Protocol/RoslynLanguageServer.cs +++ b/src/LanguageServer/Protocol/RoslynLanguageServer.cs @@ -195,9 +195,8 @@ public override bool TryGetLanguageForRequest(string methodName, object? seriali if (parameters.TryGetProperty("textDocument", out var textDocumentToken) || parameters.TryGetProperty("_vs_textDocument", out textDocumentToken)) { - //var uriToken = textDocumentToken.GetProperty("uri"); var textDocumentIdentifier = JsonSerializer.Deserialize(textDocumentToken, ProtocolConversions.LspJsonSerializerOptions); - Contract.ThrowIfNull(textDocumentIdentifier, "Failed to deserialize uri property"); + Contract.ThrowIfNull(textDocumentIdentifier, "Failed to deserialize text document identifier property"); uri = textDocumentIdentifier.Uri; } else if (parameters.TryGetProperty("data", out var dataToken)) From 6762ba4aaf8d3cb022ab8dbc0987af135b7beac3 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Thu, 13 Feb 2025 13:20:17 -0800 Subject: [PATCH 4/9] respond to latest main changes --- ...bstractCopilotLspServiceDocumentRequestHandler.cs | 2 +- ...bstractLanguageServerClientTests.TestLspClient.cs | 8 ++++---- .../Utilities/AbstractLanguageServerClientTests.cs | 12 +++++------- .../Commands/ExecuteWorkspaceCommandTests.cs | 2 +- .../Formatting/FormatDocumentTests.cs | 2 +- .../Apis/Microsoft.CodeAnalysis.txt | 1 + 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs b/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs index a9965a35987e7..4aacd1e1ad8d7 100644 --- a/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs +++ b/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs @@ -21,7 +21,7 @@ internal abstract class AbstractCopilotLspServiceDocumentRequestHandler true; TextDocumentIdentifier ITextDocumentIdentifierHandler.GetTextDocumentIdentifier(TRequest request) - => new() { Uri = GetTextDocumentUri(request) }; + => new() { Uri = new(GetTextDocumentUri(request)) }; Task IRequestHandler.HandleRequestAsync(TRequest request, RequestContext context, CancellationToken cancellationToken) => HandleRequestAsync(request, new CopilotRequestContext(context), cancellationToken); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs index b55dfe6160fdd..4362f7a5e0ff6 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs @@ -24,7 +24,7 @@ internal sealed class TestLspClient : ILspClient, IAsyncDisposable private int _disposed = 0; private readonly Process _process; - private readonly Dictionary _documents; + private readonly Dictionary _documents; private readonly Dictionary> _locations; private readonly ILoggerFactory _loggerFactory; @@ -38,7 +38,7 @@ internal static async Task CreateAsync( bool includeDevKitComponents, bool debugLsp, ILoggerFactory loggerFactory, - Dictionary? documents = null, + Dictionary? documents = null, Dictionary>? locations = null) { var pipeName = CreateNewPipeName(); @@ -124,7 +124,7 @@ static ProcessStartInfo CreateLspStartInfo(string pipeName, string extensionLogs internal ServerCapabilities ServerCapabilities => _serverCapabilities ?? throw new InvalidOperationException("Initialize has not been called"); - private TestLspClient(Process process, string pipeName, Dictionary documents, Dictionary> locations, ILoggerFactory loggerFactory) + private TestLspClient(Process process, string pipeName, Dictionary documents, Dictionary> locations, ILoggerFactory loggerFactory) { _documents = documents; _locations = locations; @@ -242,7 +242,7 @@ public void ApplyWorkspaceEdit(WorkspaceEdit? workspaceEdit) } } - public string GetDocumentText(Uri uri) => _documents[uri].ToString(); + public string GetDocumentText(DocumentUri uri) => _documents[uri].ToString(); public IList GetLocations(string locationName) => _locations[locationName]; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs index 971033a4d5d12..6fab2f99dfbe4 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs @@ -58,11 +58,9 @@ await File.WriteAllTextAsync(projectPath, $""" var codePath = Path.Combine(projectDirectory.Path, "Code.cs"); await File.WriteAllTextAsync(codePath, code); -#pragma warning disable RS0030 // Do not use banned APIs - Uri codeUri = new(codePath); -#pragma warning restore RS0030 // Do not use banned APIs + var codeUri = ProtocolConversions.CreateAbsoluteDocumentUri(codePath); var text = SourceText.From(code); - Dictionary files = new() { [codeUri] = text }; + Dictionary files = new() { [codeUri] = text }; var annotatedLocations = GetAnnotatedLocations(codeUri, text, spans); // Create server and open the project @@ -93,7 +91,7 @@ await File.WriteAllTextAsync(projectPath, $""" return lspClient; } - private protected static Dictionary> GetAnnotatedLocations(Uri codeUri, SourceText text, ImmutableDictionary> spanMap) + private protected static Dictionary> GetAnnotatedLocations(DocumentUri codeUri, SourceText text, ImmutableDictionary> spanMap) { var locations = new Dictionary>(); foreach (var (name, spans) in spanMap) @@ -108,7 +106,7 @@ await File.WriteAllTextAsync(projectPath, $""" return locations; - static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText text, Uri documentUri) + static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText text, DocumentUri documentUri) { var location = new LSP.Location { @@ -120,7 +118,7 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText } } - private protected static TextDocumentIdentifier CreateTextDocumentIdentifier(Uri uri, ProjectId? projectContext = null) + private protected static TextDocumentIdentifier CreateTextDocumentIdentifier(DocumentUri uri, ProjectId? projectContext = null) { var documentIdentifier = new VSTextDocumentIdentifier { Uri = uri }; diff --git a/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs b/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs index 7b9c222145ab4..aaf6a456fd226 100644 --- a/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs @@ -34,7 +34,7 @@ public async Task TestExecuteWorkspaceCommand(bool mutatingLspWorkspace) var request = new ExecuteCommandParams() { - Arguments = new object[] { JsonSerializer.Serialize(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\someFile.cs") }) }, + Arguments = new object[] { JsonSerializer.Serialize(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\someFile.cs") }) }, Command = TestWorkspaceCommandHandler.CommandName }; var response = await server.ExecuteRequestAsync(Methods.WorkspaceExecuteCommandName, request, CancellationToken.None); diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs index 24ff5d6d54dac..7748fa9c57d7c 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs @@ -317,7 +317,7 @@ void M() private static async Task AssertFormatDocumentAsync( TestLspServer testLspServer, - Uri uri, + DocumentUri uri, [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string expectedText, bool insertSpaces = true, int tabSize = 4 diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt index 7f8d403ef4ae5..ae3b53b6e80d9 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.txt @@ -542,6 +542,7 @@ Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGenerators Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGenerators(System.String) Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetGeneratorsForAllLanguages Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetHashCode +Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.ToString Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.add_AnalyzerLoadFailed(System.EventHandler{Microsoft.CodeAnalysis.Diagnostics.AnalyzerLoadFailureEventArgs}) Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.get_AssemblyLoader Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.get_Display From 9ffb219b7e7c607fc43597be8d115f3ea66e1780 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 14 Apr 2025 16:12:43 -0700 Subject: [PATCH 5/9] Respond to additional main changes --- .../GeneratorTest/ProjectStructureTests.vb | 6 ++-- .../GeneratorTest/Utilities/TestLsifOutput.vb | 6 ++-- .../CodeActions/CodeActionResolveTests.cs | 28 +++++++++---------- .../Razor/Features/RazorRequestContext.cs | 2 +- .../Razor/Features/WorkspaceExtensions.cs | 8 +++++- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb index 07854f60ea5c3..2ffc83d87fd6a 100644 --- a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb +++ b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb @@ -25,8 +25,8 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests Dim projectVertex = Assert.Single(lsif.Vertices.OfType(Of Graph.LsifProject)) Dim documentVertices = lsif.GetLinkedVertices(Of Graph.LsifDocument)(projectVertex, "contains") - Dim documentA = Assert.Single(documentVertices, Function(d) d.Uri.LocalPath = "Z:\A.cs") - Dim documentB = Assert.Single(documentVertices, Function(d) d.Uri.LocalPath = "Z:\B.cs") + Dim documentA = Assert.Single(documentVertices, Function(d) d.Uri.GetRequiredParsedUri().LocalPath = "Z:\A.cs") + Dim documentB = Assert.Single(documentVertices, Function(d) d.Uri.GetRequiredParsedUri().LocalPath = "Z:\B.cs") ' We don't include contents for normal files, just generated ones Assert.Null(documentA.Contents) @@ -57,7 +57,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests Dim contents = Encoding.UTF8.GetString(Convert.FromBase64String(contentBase64Encoded)) Dim compilation = Await workspace.CurrentSolution.Projects.Single().GetCompilationAsync() - Dim tree = Assert.Single(compilation.SyntaxTrees, Function(t) generatedDocumentVertex.Uri.OriginalString.Contains(Path.GetFileName(t.FilePath))) + Dim tree = Assert.Single(compilation.SyntaxTrees, Function(t) generatedDocumentVertex.Uri.GetRequiredParsedUri().OriginalString.Contains(Path.GetFileName(t.FilePath))) Assert.Equal(tree.GetText().ToString(), contents) Next diff --git a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb index c058f5fa0309d..92e6798501f9f 100644 --- a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb +++ b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb @@ -111,7 +111,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U For Each testDocument In _workspace.Documents Dim documentVertex = _testLsifJsonWriter.Vertices _ .OfType(Of Graph.LsifDocument) _ - .Where(Function(d) d.Uri.LocalPath = testDocument.FilePath) _ + .Where(Function(d) d.Uri.GetRequiredParsedUri().LocalPath = testDocument.FilePath) _ .Single() Dim rangeVertices = GetLinkedVertices(Of Range)(documentVertex, "contains") @@ -165,7 +165,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U Public Function GetFoldingRanges(document As Document) As LSP.FoldingRange() Dim documentVertex = _testLsifJsonWriter.Vertices. OfType(Of LsifDocument). - Where(Function(d) d.Uri.LocalPath = document.FilePath). + Where(Function(d) d.Uri.GetRequiredParsedUri().LocalPath = document.FilePath). Single() Dim foldingRangeVertex = GetLinkedVertices(Of FoldingRangeResult)(documentVertex, "textDocument/foldingRange").Single() Return foldingRangeVertex.Result @@ -174,7 +174,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U Public Function GetSemanticTokens(document As Document) As LSP.SemanticTokens Dim documentVertex = _testLsifJsonWriter.Vertices. OfType(Of LsifDocument). - Where(Function(d) d.Uri.LocalPath = document.FilePath). + Where(Function(d) d.Uri.GetRequiredParsedUri().LocalPath = document.FilePath). Single() Dim semanticTokensVertex = GetLinkedVertices(Of SemanticTokensResult)(documentVertex, "textDocument/semanticTokens/full").Single() diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs index 079f0ddd3d5c2..1483eda460d26 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs @@ -171,12 +171,12 @@ class {|caret:ABC|} diagnostics: null); var testWorkspace = testLspServer.TestWorkspace; - var documentBefore = testWorkspace.CurrentSolution.GetDocument(testWorkspace.Documents.Single().Id); + var documentBefore = testWorkspace.CurrentSolution.GetDocument(testWorkspace.Documents.Single().Id)!; var documentUriBefore = documentBefore.GetUriForRenamedDocument(); var actualResolvedAction = await RunGetCodeActionResolveAsync(testLspServer, unresolvedCodeAction); - var documentAfter = testWorkspace.CurrentSolution.GetDocument(testWorkspace.Documents.Single().Id); + var documentAfter = testWorkspace.CurrentSolution.GetDocument(testWorkspace.Documents.Single().Id)!; var documentUriAfter = documentBefore.WithName("ABC.cs").GetUriForRenamedDocument(); var expectedCodeAction = CodeActionsTests.CreateCodeAction( @@ -241,10 +241,10 @@ class C var actualResolvedAction = await RunGetCodeActionResolveAsync(testLspServer, unresolvedCodeAction); AssertEx.NotNull(actualResolvedAction.Edit); - var textDocumentEdit = (LSP.TextDocumentEdit[])actualResolvedAction.Edit.DocumentChanges.Value; + var textDocumentEdit = (LSP.TextDocumentEdit[])actualResolvedAction.Edit.DocumentChanges!.Value; Assert.Single(textDocumentEdit); - var originalText = await testLspServer.GetDocumentTextAsync(textDocumentEdit[0].TextDocument.Uri); - var edits = textDocumentEdit[0].Edits.Select(e => (LSP.TextEdit)e.Value).ToArray(); + var originalText = await testLspServer.GetDocumentTextAsync(textDocumentEdit[0].TextDocument.DocumentUri); + var edits = textDocumentEdit[0].Edits.Select(e => (LSP.TextEdit)e.Value!).ToArray(); var updatedText = ApplyTextEdits(edits, originalText); Assert.Equal(expectedText, updatedText); @@ -292,7 +292,7 @@ class BCD var actualResolvedAction = await RunGetCodeActionResolveAsync(testLspServer, unresolvedCodeAction); var project = testWorkspace.CurrentSolution.Projects.Single(); - var newDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(Path.Combine(Path.GetDirectoryName(project.FilePath), "ABC.cs")); + var newDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(Path.Combine(Path.GetDirectoryName(project.FilePath)!, "ABC.cs")); var existingDocumentUri = testWorkspace.CurrentSolution.GetRequiredDocument(testWorkspace.Documents.Single().Id).GetURI(); var workspaceEdit = new WorkspaceEdit() { @@ -303,7 +303,7 @@ class BCD // Add content to file new TextDocumentEdit() { - TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = newDocumentUri }, + TextDocument = new OptionalVersionedTextDocumentIdentifier { DocumentUri = newDocumentUri }, Edits = [ new TextEdit() @@ -331,7 +331,7 @@ class BCD // Remove the declaration from existing file new TextDocumentEdit() { - TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = existingDocumentUri }, + TextDocument = new OptionalVersionedTextDocumentIdentifier() { DocumentUri = existingDocumentUri }, Edits = [ new TextEdit() @@ -420,7 +420,7 @@ class {|caret:BCD|} Assert.Contains(Path.Combine("dir1", "dir2", "dir3"), existingDocument.FilePath); var newDocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri( - Path.Combine(Path.GetDirectoryName(existingDocument.FilePath), "BCD.cs")); + Path.Combine(Path.GetDirectoryName(existingDocument.FilePath)!, "BCD.cs")); var workspaceEdit = new WorkspaceEdit() { DocumentChanges = new SumType[] @@ -430,7 +430,7 @@ class {|caret:BCD|} // Add content to file new TextDocumentEdit() { - TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = newDocumentUri }, + TextDocument = new OptionalVersionedTextDocumentIdentifier { DocumentUri = newDocumentUri }, Edits = [ new TextEdit() @@ -457,7 +457,7 @@ class {|caret:BCD|} // Remove the declaration from existing file new TextDocumentEdit() { - TextDocument = new OptionalVersionedTextDocumentIdentifier() { Uri = existingDocumentUri }, + TextDocument = new OptionalVersionedTextDocumentIdentifier() { DocumentUri = existingDocumentUri }, Edits = [ new TextEdit() @@ -502,9 +502,9 @@ class {|caret:BCD|} TestLspServer testLspServer, VSInternalCodeAction unresolvedCodeAction) { - var result = (VSInternalCodeAction)await testLspServer.ExecuteRequestAsync( + var result = (VSInternalCodeAction?)await testLspServer.ExecuteRequestAsync( LSP.Methods.CodeActionResolveName, unresolvedCodeAction, CancellationToken.None); - return result; + return result!; } private static LSP.TextEdit GenerateTextEdit(string newText, LSP.Range range) @@ -525,7 +525,7 @@ private static WorkspaceEdit GenerateWorkspaceEdit( { TextDocument = new OptionalVersionedTextDocumentIdentifier { - Uri = locations.Single().Uri + DocumentUri = locations.Single().Uri }, Edits = edits, } diff --git a/src/Tools/ExternalAccess/Razor/Features/RazorRequestContext.cs b/src/Tools/ExternalAccess/Razor/Features/RazorRequestContext.cs index 56e0e89d376fb..dcc361d46aae6 100644 --- a/src/Tools/ExternalAccess/Razor/Features/RazorRequestContext.cs +++ b/src/Tools/ExternalAccess/Razor/Features/RazorRequestContext.cs @@ -11,7 +11,7 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; internal readonly struct RazorRequestContext(RequestContext context) { internal string Method => context.Method; - internal Uri? Uri => context.TextDocument?.GetURI(); + internal Uri? Uri => context.TextDocument?.GetURI().ParsedUri; /// internal Workspace? Workspace => context.Workspace; /// diff --git a/src/Tools/ExternalAccess/Razor/Features/WorkspaceExtensions.cs b/src/Tools/ExternalAccess/Razor/Features/WorkspaceExtensions.cs index 052493d4a6286..7c4743a5ed285 100644 --- a/src/Tools/ExternalAccess/Razor/Features/WorkspaceExtensions.cs +++ b/src/Tools/ExternalAccess/Razor/Features/WorkspaceExtensions.cs @@ -12,9 +12,15 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.Features; internal static class WorkspaceExtensions { + [Obsolete("Use GetTextDocumentAsync with DocumentUri instead.")] public static ValueTask GetTextDocumentAsync(this Workspace workspace, Uri uri, CancellationToken cancellationToken) { - var identifier = new TextDocumentIdentifier() { Uri = uri }; + return GetTextDocumentAsync(workspace, new DocumentUri(uri), cancellationToken); + } + + public static ValueTask GetTextDocumentAsync(this Workspace workspace, DocumentUri uri, CancellationToken cancellationToken) + { + var identifier = new TextDocumentIdentifier() { DocumentUri = uri }; return workspace.CurrentSolution.GetTextDocumentAsync(identifier, cancellationToken); } } From bb63a7960553f1ad6772c8481e58dccd3183509c Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 14 Apr 2025 16:13:03 -0700 Subject: [PATCH 6/9] Make TextDocumentIdentifier changes backwards compatible --- .../Api/AbstractVSTypeScriptRequestHandler.cs | 2 +- ...operSdkLspServiceDocumentRequestHandler.cs | 2 +- ...CopilotLspServiceDocumentRequestHandler.cs | 2 +- .../Internal/HotReloadDiagnosticSource.cs | 2 +- .../ServerInitializationTests.cs | 4 +-- ...LanguageServerClientTests.TestLspClient.cs | 2 +- .../AbstractLanguageServerClientTests.cs | 2 +- .../AbstractLanguageServerProtocolTests.cs | 8 ++--- .../Protocol/Extensions/Extensions.cs | 12 +++---- .../Extensions/ProtocolConversions.cs | 6 ++-- .../Razor/FormatNewFileHandler.cs | 2 +- .../CodeActions/CodeActionResolveHelper.cs | 4 +-- .../CodeLens/CodeLensResolveHandler.cs | 4 +-- .../AbstractPullDiagnosticHandler.cs | 2 +- .../AbstractDocumentDiagnosticSource.cs | 2 +- .../AbstractProjectDiagnosticSource.cs | 2 +- .../PublicWorkspacePullDiagnosticsHandler.cs | 6 ++-- .../DocumentChanges/DidChangeHandler.cs | 4 +-- .../DocumentChanges/DidCloseHandler.cs | 4 +-- .../Handler/MapCode/MapCodeHandler.cs | 12 +++---- .../GetTextDocumentWithContextHandler.cs | 2 +- .../Protocol/Handler/RequestContextFactory.cs | 2 +- .../AbstractSpellCheckingHandler.cs | 2 +- .../Protocol/TextDocumentIdentifier.cs | 12 ++++--- .../Protocol/RoslynLanguageServer.cs | 4 +-- .../Workspaces/LspWorkspaceManager.cs | 4 +-- .../CodeActions/RunCodeActionsTests.cs | 2 +- .../Commands/ExecuteWorkspaceCommandTests.cs | 2 +- .../DataTips/DataTipRangeHandlerTests.cs | 2 +- .../Definitions/GoToTypeDefinitionTests.cs | 2 +- .../AbstractPullDiagnosticTestsBase.cs | 10 +++--- .../Diagnostics/PullDiagnosticTests.cs | 14 ++++---- .../DocumentChangesTests.LinkedDocuments.cs | 2 +- .../FormatNewFile/FormatNewFileTests.cs | 4 +-- .../ProtocolUnitTests/HandlerTests.cs | 20 +++++------ .../ProtocolUnitTests/MapCode/MapCodeTests.cs | 2 +- .../LspMetadataAsSourceWorkspaceTests.cs | 2 +- .../LspMiscellaneousFilesWorkspaceTests.cs | 8 ++--- .../ProtocolConversionsTests.cs | 2 +- .../RelatedDocuments/RelatedDocumentsTests.cs | 2 +- .../ProtocolUnitTests/Rename/RenameTests.cs | 2 +- .../AbstractSemanticTokensTests.cs | 6 ++-- .../SpellCheck/SpellCheckTests.cs | 8 ++--- .../ProtocolUnitTests/UriTests.cs | 36 +++++++++---------- .../ValidateBreakableRangeTests.cs | 2 +- .../SourceGeneratedDocumentTests.cs | 28 +++++++-------- ...stractRazorCohostDocumentRequestHandler.cs | 2 +- .../Xaml/External/ResolveDataConversions.cs | 8 ++--- .../Xaml/External/XamlRequestHandlerBase.cs | 2 +- .../Xaml/Internal/XamlDiagnosticSource.cs | 2 +- .../DocumentOutlineViewModel_Utilities.cs | 2 +- .../Definitions/GoToDefinitionHandler.cs | 2 +- .../XamlRequestExecutionQueue.cs | 2 +- 53 files changed, 145 insertions(+), 141 deletions(-) diff --git a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs index 46b559222fb7c..55d4e1e48dc95 100644 --- a/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs +++ b/src/EditorFeatures/Core/ExternalAccess/VSTypeScript/Api/AbstractVSTypeScriptRequestHandler.cs @@ -31,7 +31,7 @@ internal abstract class AbstractVSTypeScriptRequestHandler RequiresLSPSolution; TextDocumentIdentifier ITextDocumentIdentifierHandler.GetTextDocumentIdentifier(TRequest request) - => new() { Uri = new(GetTextDocumentIdentifier(request)) }; + => new() { DocumentUri = new(GetTextDocumentIdentifier(request)) }; Task IRequestHandler.HandleRequestAsync(TRequest request, LspRequestContext context, CancellationToken cancellationToken) => HandleRequestAsync(request, new RequestContext(context), cancellationToken); } diff --git a/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs b/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs index 4aacd1e1ad8d7..b3eee482d75a7 100644 --- a/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs +++ b/src/LanguageServer/ExternalAccess/Copilot/Handler/AbstractCopilotLspServiceDocumentRequestHandler.cs @@ -21,7 +21,7 @@ internal abstract class AbstractCopilotLspServiceDocumentRequestHandler true; TextDocumentIdentifier ITextDocumentIdentifierHandler.GetTextDocumentIdentifier(TRequest request) - => new() { Uri = new(GetTextDocumentUri(request)) }; + => new() { DocumentUri = new(GetTextDocumentUri(request)) }; Task IRequestHandler.HandleRequestAsync(TRequest request, RequestContext context, CancellationToken cancellationToken) => HandleRequestAsync(request, new CopilotRequestContext(context), cancellationToken); diff --git a/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSource.cs b/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSource.cs index 64d157b4a1343..137716f79981a 100644 --- a/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSource.cs +++ b/src/LanguageServer/ExternalAccess/VisualDiagnostics/Internal/HotReloadDiagnosticSource.cs @@ -24,7 +24,7 @@ public async Task> GetDiagnosticsAsync(RequestCon return result; } - public TextDocumentIdentifier? GetDocumentIdentifier() => new() { Uri = textDocument.GetURI() }; + public TextDocumentIdentifier? GetDocumentIdentifier() => new() { DocumentUri = textDocument.GetURI() }; public ProjectOrDocumentId GetId() => new(textDocument.Id); public Project GetProject() => textDocument.Project; public bool IsLiveSource() => true; diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs index 4339dcb34f400..ce45eed29f628 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs @@ -18,12 +18,12 @@ public ServerInitializationTests(ITestOutputHelper testOutputHelper) : base(test public async Task TestServerHandlesTextSyncRequestsAsync() { await using var server = await CreateLanguageServerAsync(); - var document = new VersionedTextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteDocumentUri("C:\\\ue25b\ud86d\udeac.cs") }; + var document = new VersionedTextDocumentIdentifier { DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri("C:\\\ue25b\ud86d\udeac.cs") }; var response = await server.ExecuteRequestAsync(Methods.TextDocumentDidOpenName, new DidOpenTextDocumentParams { TextDocument = new TextDocumentItem { - Uri = document.Uri, + Uri = document.DocumentUri, Text = "Write" } }, CancellationToken.None); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs index 4362f7a5e0ff6..6c316b120015e 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.TestLspClient.cs @@ -229,7 +229,7 @@ public void ApplyWorkspaceEdit(WorkspaceEdit? workspaceEdit) foreach (var documentEdit in textDocumentEdits) { - var uri = documentEdit.TextDocument.Uri; + var uri = documentEdit.TextDocument.DocumentUri; var document = _documents[uri]; var changes = documentEdit.Edits diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs index 6fab2f99dfbe4..99a394edf4b6a 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs @@ -120,7 +120,7 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText private protected static TextDocumentIdentifier CreateTextDocumentIdentifier(DocumentUri uri, ProjectId? projectContext = null) { - var documentIdentifier = new VSTextDocumentIdentifier { Uri = uri }; + var documentIdentifier = new VSTextDocumentIdentifier { DocumentUri = uri }; if (projectContext != null) { diff --git a/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs index 829c69a78495a..cf6f0dc2b321e 100644 --- a/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs +++ b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs @@ -193,7 +193,7 @@ internal static LSP.SymbolInformation CreateSymbolInformation(LSP.SymbolKind kin private protected static LSP.TextDocumentIdentifier CreateTextDocumentIdentifier(DocumentUri uri, ProjectId? projectContext = null) { - var documentIdentifier = new LSP.VSTextDocumentIdentifier { Uri = uri }; + var documentIdentifier = new LSP.VSTextDocumentIdentifier { DocumentUri = uri }; if (projectContext != null) { @@ -513,7 +513,7 @@ private static LSP.DidChangeTextDocumentParams CreateDidChangeTextDocumentParams { TextDocument = new LSP.VersionedTextDocumentIdentifier { - Uri = documentUri + DocumentUri = documentUri }, ContentChanges = changeEvents }; @@ -535,7 +535,7 @@ private static LSP.DidCloseTextDocumentParams CreateDidCloseTextDocumentParams(D { TextDocument = new LSP.TextDocumentIdentifier { - Uri = uri + DocumentUri = uri } }; @@ -664,7 +664,7 @@ protected virtual RoslynLanguageServer CreateLanguageServer(Stream inputStream, public async Task GetDocumentAsync(DocumentUri uri) { - var document = await GetCurrentSolution().GetDocumentAsync(new LSP.TextDocumentIdentifier { Uri = uri }, CancellationToken.None).ConfigureAwait(false); + var document = await GetCurrentSolution().GetDocumentAsync(new LSP.TextDocumentIdentifier { DocumentUri = uri }, CancellationToken.None).ConfigureAwait(false); Contract.ThrowIfNull(document, $"Unable to find document with {uri} in solution"); return document; } diff --git a/src/LanguageServer/Protocol/Extensions/Extensions.cs b/src/LanguageServer/Protocol/Extensions/Extensions.cs index d192bd3d3576e..a5cd852ac55a8 100644 --- a/src/LanguageServer/Protocol/Extensions/Extensions.cs +++ b/src/LanguageServer/Protocol/Extensions/Extensions.cs @@ -116,15 +116,15 @@ public static ImmutableArray GetDocumentIds(this Solution solution, public static async ValueTask GetTextDocumentAsync(this Solution solution, TextDocumentIdentifier documentIdentifier, CancellationToken cancellationToken) { // If it's the URI scheme for source generated files, delegate to our other helper, otherwise we can handle anything else here. - if (documentIdentifier.Uri.ParsedUri?.Scheme == SourceGeneratedDocumentUri.Scheme) + if (documentIdentifier.DocumentUri.ParsedUri?.Scheme == SourceGeneratedDocumentUri.Scheme) { // In the case of a URI scheme for source generated files, we generate a different URI for each project, thus this URI cannot be linked into multiple projects; // this means we can safely call .SingleOrDefault() and not worry about calling FindDocumentInProjectContext. - var documentId = solution.GetDocumentIds(documentIdentifier.Uri).SingleOrDefault(); + var documentId = solution.GetDocumentIds(documentIdentifier.DocumentUri).SingleOrDefault(); return await solution.GetDocumentAsync(documentId, includeSourceGenerated: true, cancellationToken).ConfigureAwait(false); } - var documents = solution.GetTextDocuments(documentIdentifier.Uri); + var documents = solution.GetTextDocuments(documentIdentifier.DocumentUri); return documents.Length == 0 ? null : documents.FindDocumentInProjectContext(documentIdentifier, (sln, id) => sln.GetRequiredTextDocument(id)); @@ -178,12 +178,12 @@ public static T FindDocumentInProjectContext(this ImmutableArray documents public static Project? GetProject(this Solution solution, TextDocumentIdentifier projectIdentifier) { // We need to parse the URI (scheme, file path) to be able to lookup the URI in the solution. - if (projectIdentifier.Uri.ParsedUri is null) + if (projectIdentifier.DocumentUri.ParsedUri is null) { return null; } - var projects = solution.Projects.Where(project => project.FilePath == projectIdentifier.Uri.ParsedUri.LocalPath).ToImmutableArray(); + var projects = solution.Projects.Where(project => project.FilePath == projectIdentifier.DocumentUri.ParsedUri.LocalPath).ToImmutableArray(); return !projects.Any() ? null : FindItemInProjectContext(projects, projectIdentifier, projectIdGetter: (item) => item.Id, defaultGetter: () => projects[0]); @@ -191,7 +191,7 @@ public static T FindDocumentInProjectContext(this ImmutableArray documents public static TextDocument? GetAdditionalDocument(this Solution solution, TextDocumentIdentifier documentIdentifier) { - var documentIds = GetDocumentIds(solution, documentIdentifier.Uri); + var documentIds = GetDocumentIds(solution, documentIdentifier.DocumentUri); // We don't call GetRequiredAdditionalDocument as the id could be referring to a regular document. var additionalDocuments = documentIds.Select(solution.GetAdditionalDocument).WhereNotNull().ToImmutableArray(); diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 6d5f06331e7db..2bdb07a1d45f0 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -299,10 +299,10 @@ public static LSP.TextDocumentPositionParams PositionToTextDocumentPositionParam } public static LSP.TextDocumentIdentifier DocumentToTextDocumentIdentifier(TextDocument document) - => new() { Uri = document.GetURI() }; + => new() { DocumentUri = document.GetURI() }; public static LSP.VersionedTextDocumentIdentifier DocumentToVersionedTextDocumentIdentifier(Document document) - => new() { Uri = document.GetURI() }; + => new() { DocumentUri = document.GetURI() }; public static LinePosition PositionToLinePosition(LSP.Position position) => new(position.Line, position.Character); @@ -446,7 +446,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) var documentEdits = uriToTextEdits.GroupBy(uriAndEdit => uriAndEdit.Uri, uriAndEdit => new LSP.SumType(uriAndEdit.TextEdit), (uri, edits) => new LSP.TextDocumentEdit { - TextDocument = new LSP.OptionalVersionedTextDocumentIdentifier { Uri = uri }, + TextDocument = new LSP.OptionalVersionedTextDocumentIdentifier { DocumentUri = uri }, Edits = [.. edits], }).ToArray(); diff --git a/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs b/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs index 5a91057b1de6b..9f1e7ce63a1be 100644 --- a/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs +++ b/src/LanguageServer/Protocol/ExternalAccess/Razor/FormatNewFileHandler.cs @@ -46,7 +46,7 @@ public FormatNewFileHandler(IGlobalOptionService globalOptions) return null; } - var parsedUri = request.Document.Uri.GetRequiredParsedUri(); + var parsedUri = request.Document.DocumentUri.GetRequiredParsedUri(); // Create a document in-memory to represent the file Razor wants to add var filePath = ProtocolConversions.GetDocumentFilePathFromUri(parsedUri); diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs index 516a6be202c78..6dcf9eba1bcbb 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs @@ -258,7 +258,7 @@ async Task AddTextDocumentAdditionsAsync( var newText = await newTextDoc.GetValueTextAsync(cancellationToken).ConfigureAwait(false); var emptyDocumentRange = new LSP.Range { Start = new Position { Line = 0, Character = 0 }, End = new Position { Line = 0, Character = 0 } }; var edit = new TextEdit { Range = emptyDocumentRange, NewText = newText.ToString() }; - var documentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = uri }; + var documentIdentifier = new OptionalVersionedTextDocumentIdentifier { DocumentUri = uri }; textDocumentEdits.Add(new TextDocumentEdit { TextDocument = documentIdentifier, Edits = [edit] }); } } @@ -301,7 +301,7 @@ async Task AddTextDocumentEditsAsync( if (edits.Length > 0) { - var documentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = newTextDoc.GetURI() }; + var documentIdentifier = new OptionalVersionedTextDocumentIdentifier { DocumentUri = newTextDoc.GetURI() }; textDocumentEdits.Add(new TextDocumentEdit { TextDocument = documentIdentifier, Edits = edits }); } diff --git a/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs b/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs index e1d2a15d95d8d..9ccffd4c5a595 100644 --- a/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs +++ b/src/LanguageServer/Protocol/Handler/CodeLens/CodeLensResolveHandler.cs @@ -45,7 +45,7 @@ public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeLens request CommandIdentifier = ClientReferencesCommand, Arguments = [ - resolveData.TextDocument.Uri, + resolveData.TextDocument.DocumentUri, request.Range.Start ] }; @@ -73,7 +73,7 @@ public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeLens request CommandIdentifier = ClientReferencesCommand, Arguments = [ - resolveData.TextDocument.Uri, + resolveData.TextDocument.DocumentUri, request.Range.Start, ], }; diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs index d1f6ead2e0d06..a02b15863c3e9 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/AbstractPullDiagnosticHandler.cs @@ -299,7 +299,7 @@ private void HandleRemovedDocuments(RequestContext context, HashSet> GetDiagnosticsAsync( public TextDocumentIdentifier? GetDocumentIdentifier() => !string.IsNullOrEmpty(Document.FilePath) - ? new VSTextDocumentIdentifier { ProjectContext = ProtocolConversions.ProjectToProjectContext(Document.Project), Uri = Document.GetURI() } + ? new VSTextDocumentIdentifier { ProjectContext = ProtocolConversions.ProjectToProjectContext(Document.Project), DocumentUri = Document.GetURI() } : null; public string ToDisplayString() => $"{this.GetType().Name}: {Document.FilePath ?? Document.Name} in {Document.Project.Name}"; diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs index 3594527dcbd8b..545d5ffae0d25 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/DiagnosticSources/AbstractProjectDiagnosticSource.cs @@ -29,7 +29,7 @@ public static AbstractProjectDiagnosticSource CreateForCodeAnalysisDiagnostics(P public Project GetProject() => Project; public TextDocumentIdentifier? GetDocumentIdentifier() => !string.IsNullOrEmpty(Project.FilePath) - ? new VSTextDocumentIdentifier { ProjectContext = ProtocolConversions.ProjectToProjectContext(Project), Uri = ProtocolConversions.CreateAbsoluteDocumentUri(Project.FilePath) } + ? new VSTextDocumentIdentifier { ProjectContext = ProtocolConversions.ProjectToProjectContext(Project), DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(Project.FilePath) } : null; public string ToDisplayString() => Project.Name; diff --git a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs index 8b375e0059b3e..ebf08afad90b5 100644 --- a/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Diagnostics/Public/PublicWorkspacePullDiagnosticsHandler.cs @@ -43,7 +43,7 @@ protected override WorkspaceDiagnosticPartialReport CreateReport(TextDocumentIde [ new WorkspaceFullDocumentDiagnosticReport { - Uri = identifier.Uri, + Uri = identifier.DocumentUri, Items = diagnostics, // The documents provided by workspace reports are never open, so we return null. Version = null, @@ -59,7 +59,7 @@ protected override WorkspaceDiagnosticPartialReport CreateRemovedReport(TextDocu [ new WorkspaceFullDocumentDiagnosticReport { - Uri = identifier.Uri, + Uri = identifier.DocumentUri, Items = [], // The documents provided by workspace reports are never open, so we return null. Version = null, @@ -94,7 +94,7 @@ protected override bool TryCreateUnchangedReport(TextDocumentIdentifier identifi PreviousResultId = id.Value, TextDocument = new TextDocumentIdentifier { - Uri = id.Uri + DocumentUri = id.Uri } }).ToImmutableArray(); } diff --git a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs index b13b4ae983006..41241fe324d9e 100644 --- a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidChangeHandler.cs @@ -28,11 +28,11 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(DidChangeTextDocumentPar public Task HandleRequestAsync(DidChangeTextDocumentParams request, RequestContext context, CancellationToken cancellationToken) { - var text = context.GetTrackedDocumentSourceText(request.TextDocument.Uri); + var text = context.GetTrackedDocumentSourceText(request.TextDocument.DocumentUri); text = GetUpdatedSourceText(request.ContentChanges, text); - context.UpdateTrackedDocument(request.TextDocument.Uri, text); + context.UpdateTrackedDocument(request.TextDocument.DocumentUri, text); return SpecializedTasks.Default(); } diff --git a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidCloseHandler.cs b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidCloseHandler.cs index 3b8840b7c47a4..e095e7aeaab5c 100644 --- a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidCloseHandler.cs +++ b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidCloseHandler.cs @@ -31,8 +31,8 @@ public DidCloseHandler() public async Task HandleNotificationAsync(LSP.DidCloseTextDocumentParams request, RequestContext context, CancellationToken cancellationToken) { // GetTextDocumentIdentifier returns null to avoid creating the solution, so the queue is not able to log the uri. - context.TraceInformation($"didClose for {request.TextDocument.Uri}"); + context.TraceInformation($"didClose for {request.TextDocument.DocumentUri}"); - await context.StopTrackingAsync(request.TextDocument.Uri, cancellationToken).ConfigureAwait(false); + await context.StopTrackingAsync(request.TextDocument.DocumentUri, cancellationToken).ConfigureAwait(false); } } diff --git a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs index c0ba90e0d56c2..0261aa3f81bc7 100644 --- a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs @@ -64,7 +64,7 @@ public MapCodeHandler() { DocumentChanges = uriToEditsMap.Select(kvp => new TextDocumentEdit { - TextDocument = new OptionalVersionedTextDocumentIdentifier { Uri = kvp.Key }, + TextDocument = new OptionalVersionedTextDocumentIdentifier { DocumentUri = kvp.Key }, Edits = [.. kvp.Value.Select(v => new SumType(v))], }).ToArray() }; @@ -84,7 +84,7 @@ public MapCodeHandler() var document = await context.Solution.GetDocumentAsync(textDocument, cancellationToken).ConfigureAwait(false); if (document is null) - throw new ArgumentException($"mapCode sub-request for {textDocument.Uri} failed: can't find this document in the workspace."); + throw new ArgumentException($"mapCode sub-request for {textDocument.DocumentUri} failed: can't find this document in the workspace."); var codeMapper = document.GetRequiredLanguageService(); @@ -102,14 +102,14 @@ public MapCodeHandler() if (textChanges is null) { - context.TraceInformation($"mapCode sub-request for {textDocument.Uri} failed: 'IMapCodeService.MapCodeAsync' returns null."); + context.TraceInformation($"mapCode sub-request for {textDocument.DocumentUri} failed: 'IMapCodeService.MapCodeAsync' returns null."); return null; } var oldText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var textEdits = textChanges.Value.Select(change => ProtocolConversions.TextChangeToTextEdit(change, oldText)).ToArray(); - return (textDocument.Uri, textEdits); + return (textDocument.DocumentUri, textEdits); } async Task> ConvertFocusLocationsToDocumentAndSpansAsync( @@ -125,9 +125,9 @@ public MapCodeHandler() foreach (var location in locationsOfSamePriority) { // Ignore anything not in target document, which current code mapper doesn't handle anyway - if (!location.Uri.Equals(textDocumentIdentifier.Uri)) + if (!location.Uri.Equals(textDocumentIdentifier.DocumentUri)) { - context.TraceInformation($"A focus location in '{textDocumentIdentifier.Uri}' is skipped, only locations in corresponding MapCodeMapping.TextDocument is currently considered."); + context.TraceInformation($"A focus location in '{textDocumentIdentifier.DocumentUri}' is skipped, only locations in corresponding MapCodeMapping.TextDocument is currently considered."); continue; } diff --git a/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs b/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs index 4c6810aed171f..4373464f73195 100644 --- a/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs +++ b/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs @@ -28,7 +28,7 @@ public GetTextDocumentWithContextHandler() public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; - public TextDocumentIdentifier GetTextDocumentIdentifier(VSGetProjectContextsParams request) => new TextDocumentIdentifier { Uri = request.TextDocument.Uri }; + public TextDocumentIdentifier GetTextDocumentIdentifier(VSGetProjectContextsParams request) => new TextDocumentIdentifier { DocumentUri = request.TextDocument.Uri }; public Task HandleRequestAsync(VSGetProjectContextsParams request, RequestContext context, CancellationToken cancellationToken) { diff --git a/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs b/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs index 40d9a23b19cf2..1956417542e46 100644 --- a/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs +++ b/src/LanguageServer/Protocol/Handler/RequestContextFactory.cs @@ -46,7 +46,7 @@ public override Task CreateRequestContextAsync(IQ var textDocumentItem = uHandler.GetTextDocumentIdentifier(requestParam); textDocumentIdentifier = new TextDocumentIdentifier { - Uri = textDocumentItem.Uri, + DocumentUri = textDocumentItem.Uri, }; } else if (textDocumentIdentifierHandler is null) diff --git a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs index 0907eae628d81..dc7f44fd9b056 100644 --- a/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs +++ b/src/LanguageServer/Protocol/Handler/SpellCheck/AbstractSpellCheckingHandler.cs @@ -212,7 +212,7 @@ private async Task HandleRemovedDocumentsAsync( var document = await context.Solution.GetTextDocumentAsync(textDocument, cancellationToken).ConfigureAwait(false); if (document == null) { - context.TraceInformation($"Clearing spans for removed document: {textDocument.Uri}"); + context.TraceInformation($"Clearing spans for removed document: {textDocument.DocumentUri}"); // Client is asking server about a document that no longer exists (i.e. was removed/deleted from // the workspace). Report a (null-spans, null-result-id) response to the client as that means diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs index d39409239c219..9ac9665575288 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs @@ -6,6 +6,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// Class which identifies a text document. @@ -19,7 +20,10 @@ internal class TextDocumentIdentifier : IEquatable /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri Uri { get; set; } + public DocumentUri DocumentUri { get; set; } + + [Obsolete("Use DocumentUri instead. This property will be removed in a future version.")] + public Uri Uri => DocumentUri.GetRequiredParsedUri(); public static bool operator ==(TextDocumentIdentifier? value1, TextDocumentIdentifier? value2) { @@ -46,7 +50,7 @@ internal class TextDocumentIdentifier : IEquatable public bool Equals(TextDocumentIdentifier other) { return other is not null - && this.Uri == other.Uri; + && this.DocumentUri == other.DocumentUri; } /// @@ -65,12 +69,12 @@ public override bool Equals(object obj) /// public override int GetHashCode() { - return this.Uri == null ? 89 : this.Uri.GetHashCode(); + return this.DocumentUri == null ? 89 : this.DocumentUri.GetHashCode(); } /// public override string ToString() { - return this.Uri == null ? string.Empty : this.Uri.ToString(); + return this.DocumentUri == null ? string.Empty : this.DocumentUri.ToString(); } } diff --git a/src/LanguageServer/Protocol/RoslynLanguageServer.cs b/src/LanguageServer/Protocol/RoslynLanguageServer.cs index fb4acf9069509..2f63e89b80d37 100644 --- a/src/LanguageServer/Protocol/RoslynLanguageServer.cs +++ b/src/LanguageServer/Protocol/RoslynLanguageServer.cs @@ -195,7 +195,7 @@ public override bool TryGetLanguageForRequest(string methodName, object? seriali { var textDocumentIdentifier = JsonSerializer.Deserialize(textDocumentToken, ProtocolConversions.LspJsonSerializerOptions); Contract.ThrowIfNull(textDocumentIdentifier, "Failed to deserialize text document identifier property"); - uri = textDocumentIdentifier.Uri; + uri = textDocumentIdentifier.DocumentUri; } else if (parameters.TryGetProperty("data", out var dataToken)) { @@ -206,7 +206,7 @@ public override bool TryGetLanguageForRequest(string methodName, object? seriali //var dataToken = parameters["data"]; var data = JsonSerializer.Deserialize(dataToken, ProtocolConversions.LspJsonSerializerOptions); Contract.ThrowIfNull(data, "Failed to document resolve data object"); - uri = data.TextDocument.Uri; + uri = data.TextDocument.DocumentUri; } if (uri == null) diff --git a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs index 8b95326437e8a..bdab1bb9145b2 100644 --- a/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs +++ b/src/LanguageServer/Protocol/Workspaces/LspWorkspaceManager.cs @@ -234,7 +234,7 @@ public void UpdateTrackedDocument(DocumentUri uri, SourceText newSourceText) public async Task<(Workspace?, Solution?, TextDocument?)> GetLspDocumentInfoAsync(TextDocumentIdentifier textDocumentIdentifier, CancellationToken cancellationToken) { // Get the LSP view of all the workspace solutions. - var uri = textDocumentIdentifier.Uri; + var uri = textDocumentIdentifier.DocumentUri; var lspSolutions = await GetLspSolutionsAsync(cancellationToken).ConfigureAwait(false); // Find the matching document from the LSP solutions. @@ -264,7 +264,7 @@ public void UpdateTrackedDocument(DocumentUri uri, SourceText newSourceText) // We didn't find the document in any workspace, record a telemetry notification that we did not find it. // Depending on the host, this can be entirely normal (e.g. opening a loose file) var searchedWorkspaceKinds = string.Join(";", lspSolutions.SelectAsArray(lspSolution => lspSolution.Solution.Workspace.Kind)); - _logger.LogInformation($"Could not find '{textDocumentIdentifier.Uri}'. Searched {searchedWorkspaceKinds}"); + _logger.LogInformation($"Could not find '{textDocumentIdentifier.DocumentUri}'. Searched {searchedWorkspaceKinds}"); _requestTelemetryLogger.UpdateFindDocumentTelemetryData(success: false, workspaceKind: null); // Add the document to our loose files workspace (if we have one) if it iss open. diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs index 9cc98cb4c460f..735cb91c82ac6 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs @@ -45,7 +45,7 @@ class B var caretLocation = testLspServer.GetLocations("caret").Single(); var documentId = new LSP.TextDocumentIdentifier { - Uri = caretLocation.Uri + DocumentUri = caretLocation.Uri }; var titlePath = new[] { string.Format(FeaturesResources.Move_type_to_0, "B.cs") }; diff --git a/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs b/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs index a8bd0daadb453..7dc1146708bee 100644 --- a/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Commands/ExecuteWorkspaceCommandTests.cs @@ -34,7 +34,7 @@ public async Task TestExecuteWorkspaceCommand(bool mutatingLspWorkspace) var request = new ExecuteCommandParams() { - Arguments = new object[] { JsonSerializer.Serialize(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\someFile.cs") }) }, + Arguments = new object[] { JsonSerializer.Serialize(new TextDocumentIdentifier { DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\someFile.cs") }) }, Command = TestWorkspaceCommandHandler.CommandName }; var response = await server.ExecuteRequestAsync(Methods.WorkspaceExecuteCommandName, request, CancellationToken.None); diff --git a/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs index 0a7803beb3ba6..7073aa415c83c 100644 --- a/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs @@ -21,7 +21,7 @@ public sealed class DataTipRangeHandlerTests(ITestOutputHelper testOutputHelper) LSP.VSInternalMethods.TextDocumentDataTipRangeName, new LSP.TextDocumentPositionParams() { - TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, Position = caret.Range.Start, }, CancellationToken.None); diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs index 4ba27286eb431..c9f6829911c59 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs @@ -282,7 +282,7 @@ End Class private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, DocumentUri fileUri) { - var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None); + var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = fileUri }, CancellationToken.None); return lspWorkspace!; } } diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs index fbb43908859f1..c4025e83d9ffe 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/AbstractPullDiagnosticTestsBase.cs @@ -155,7 +155,7 @@ private static WorkspaceDiagnosticParams CreateProposedWorkspaceDiagnosticParams { var previousResultsLsp = previousResults?.Select(r => new PreviousResultId { - Uri = r.identifier.Uri, + Uri = r.identifier.DocumentUri, Value = r.resultId }).ToArray() ?? []; return new WorkspaceDiagnosticParams @@ -170,12 +170,12 @@ private static TestDiagnosticResult ConvertWorkspaceDiagnosticResult(SumType> RunGetDocume bool useProgress = false, string? category = null) { - return RunGetDocumentPullDiagnosticsAsync(testLspServer, new VSTextDocumentIdentifier { Uri = uri }, useVSDiagnostics, previousResultId, useProgress, category); + return RunGetDocumentPullDiagnosticsAsync(testLspServer, new VSTextDocumentIdentifier { DocumentUri = uri }, useVSDiagnostics, previousResultId, useProgress, category); } private protected static async Task> RunGetDocumentPullDiagnosticsAsync( @@ -365,7 +365,7 @@ private protected static InitializationOptions GetInitializationOptions( /// private protected sealed record TestDiagnosticResult(TextDocumentIdentifier TextDocument, string? ResultId, LSP.Diagnostic[]? Diagnostics) { - public DocumentUri Uri { get; } = TextDocument.Uri; + public DocumentUri Uri { get; } = TextDocument.DocumentUri; } [DiagnosticAnalyzer(InternalLanguageNames.TypeScript), PartNotDiscoverable] diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 458b689f0da0f..88c8cd72d0697 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -483,7 +483,7 @@ static VSTextDocumentIdentifier GetVsTextDocumentIdentifier(Document document) return new VSTextDocumentIdentifier { ProjectContext = projectContext, - Uri = document.GetURI(), + DocumentUri = document.GetURI(), }; } } @@ -1337,7 +1337,7 @@ static DiagnosticData CreateDiagnostic(string id, Project project, Document? doc static string Inspect(TestDiagnosticResult result) { - return $"{result.TextDocument.Uri} -> [{string.Join(",", result.Diagnostics?.Select(d => d.Code?.Value) ?? [])}]"; + return $"{result.TextDocument.DocumentUri} -> [{string.Join(",", result.Diagnostics?.Select(d => d.Code?.Value) ?? [])}]"; } } @@ -1420,7 +1420,7 @@ public async Task TestNoWorkspaceDiagnosticsForClosedFilesInProjectsWithIncorrec var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); - Assert.False(results.Any(r => r.TextDocument!.Uri.GetRequiredParsedUri().LocalPath.Contains(".ts"))); + Assert.False(results.Any(r => r.TextDocument!.DocumentUri.GetRequiredParsedUri().LocalPath.Contains(".ts"))); } [Theory, CombinatorialData] @@ -1584,7 +1584,7 @@ class A { var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal(ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test1.cs"), results[0].TextDocument!.Uri); + Assert.Equal(ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test1.cs"), results[0].TextDocument!.DocumentUri); Assert.Equal("CS1513", results[0].Diagnostics!.Single().Code); Assert.Equal(1, results[0].Diagnostics!.Single().Range.Start.Line); AssertEx.Empty(results[1].Diagnostics); @@ -2014,9 +2014,9 @@ public async Task TestWorkspaceDiagnosticsDoesNotThrowIfProjectWithoutFilePathEx var results = await RunGetWorkspacePullDiagnosticsAsync(testLspServer, useVSDiagnostics); Assert.Equal(3, results.Length); - Assert.Equal(@"C:/C.cs", results[0].TextDocument.Uri.GetRequiredParsedUri().AbsolutePath); - Assert.Equal(@"C:/CSProj1.csproj", results[1].TextDocument.Uri.GetRequiredParsedUri().AbsolutePath); - Assert.Equal(@"C:/C2.cs", results[2].TextDocument.Uri.GetRequiredParsedUri().AbsolutePath); + Assert.Equal(@"C:/C.cs", results[0].TextDocument.DocumentUri.GetRequiredParsedUri().AbsolutePath); + Assert.Equal(@"C:/CSProj1.csproj", results[1].TextDocument.DocumentUri.GetRequiredParsedUri().AbsolutePath); + Assert.Equal(@"C:/C2.cs", results[2].TextDocument.DocumentUri.GetRequiredParsedUri().AbsolutePath); } [Theory, CombinatorialData] diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs index 6a2c676cdcea5..ef7c4122c57bb 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs @@ -101,7 +101,7 @@ void M() private static async Task GetLSPSolutionAsync(TestLspServer testLspServer, DocumentUri uri) { - var (_, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new TextDocumentIdentifier { Uri = uri }, CancellationToken.None).ConfigureAwait(false); + var (_, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new TextDocumentIdentifier { DocumentUri = uri }, CancellationToken.None).ConfigureAwait(false); Contract.ThrowIfNull(lspDocument); return lspDocument.Project.Solution; } diff --git a/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs b/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs index b7769c0c25762..9ac2af9cc4561 100644 --- a/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/FormatNewFile/FormatNewFileTests.cs @@ -74,11 +74,11 @@ public partial class MyComponent { Project = new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(project.FilePath) + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(project.FilePath) }, Document = new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(newFilePath) + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(newFilePath) }, Contents = input }; diff --git a/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs index 686139bb6d054..0585ecea6f238 100644 --- a/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/HandlerTests.cs @@ -43,7 +43,7 @@ public async Task CanExecuteRequestHandler(bool mutatingLspWorkspace) var request = new TestRequestTypeOne(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var response = await server.ExecuteRequestAsync(TestDocumentHandler.MethodName, request, CancellationToken.None); Assert.Equal(typeof(TestDocumentHandler).Name, response); @@ -65,7 +65,7 @@ public async Task CanExecuteNotificationHandler(bool mutatingLspWorkspace) var request = new TestRequestTypeOne(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); await server.ExecuteNotificationAsync(TestNotificationHandler.MethodName, request); @@ -90,7 +90,7 @@ public async Task CanExecuteLanguageSpecificHandler(bool mutatingLspWorkspace) var request = new TestRequestTypeOne(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.fs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.fs") }); var response = await server.ExecuteRequestAsync(TestDocumentHandler.MethodName, request, CancellationToken.None); Assert.Equal(typeof(TestLanguageSpecificHandler).Name, response); @@ -103,7 +103,7 @@ public async Task CanExecuteLanguageSpecificHandlerWithDifferentRequestTypes(boo var request = new TestRequestTypeTwo(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.vb") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.vb") }); var response = await server.ExecuteRequestAsync(TestDocumentHandler.MethodName, request, CancellationToken.None); Assert.Equal(typeof(TestLanguageSpecificHandlerWithDifferentParams).Name, response); @@ -144,7 +144,7 @@ public async Task NonMutatingHandlerExceptionNFWIsReported(bool mutatingLspWorks var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -172,7 +172,7 @@ public async Task NonMutatingHandlerExceptionNFWIsNotReportedForLocalRpcExceptio var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -200,7 +200,7 @@ public async Task MutatingHandlerExceptionNFWIsReported(bool mutatingLspWorkspac var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -230,7 +230,7 @@ public async Task NonMutatingHandlerCancellationExceptionNFWIsNotReported(bool m var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -258,7 +258,7 @@ public async Task MutatingHandlerCancellationExceptionNFWIsNotReported(bool muta var request = new TestRequestWithDocument(new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\test.cs") }); var didReport = false; @@ -290,7 +290,7 @@ public async Task TestMutatingHandlerCrashesIfUnableToDetermineLanguage(bool mut var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"untitled:untitledFile"); var request = new TestRequestTypeOne(new TextDocumentIdentifier { - Uri = looseFileUri + DocumentUri = looseFileUri }); await Assert.ThrowsAnyAsync(async () => await testLspServer.ExecuteRequestAsync(TestDocumentHandler.MethodName, request, CancellationToken.None)).ConfigureAwait(false); diff --git a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs index 8129121109319..f865885282b6b 100644 --- a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs @@ -119,7 +119,7 @@ static void Main(string[] args) Assert.NotNull(results.DocumentChanges); var textDocumentEdits = results.DocumentChanges!.Value.First.Single(); - Assert.Equal(textDocumentEdits.TextDocument.Uri, mapCodeParams.Mappings.Single().TextDocument!.Uri); + Assert.Equal(textDocumentEdits.TextDocument.DocumentUri, mapCodeParams.Mappings.Single().TextDocument!.DocumentUri); edits = [.. textDocumentEdits.Edits.Select(e => e.Unify())]; } diff --git a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs index 61fb20c2a0a4b..0fb34dd1410fb 100644 --- a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs @@ -123,7 +123,7 @@ public static void WriteLine(string value) {} private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, DocumentUri fileUri) { - var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None); + var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = fileUri }, CancellationToken.None); return lspWorkspace!; } diff --git a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index c84ce9d7e5421..7c7e2d0442952 100644 --- a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -148,12 +148,12 @@ void M() // Open an empty loose file and make a request to verify it gets added to the misc workspace. // Include some Unicode characters to test URL handling. var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri("C:\\\ue25b\ud86d\udeac.cs"); - var looseFileTextDocumentIdentifier = new LSP.TextDocumentIdentifier { Uri = looseFileUri }; + var looseFileTextDocumentIdentifier = new LSP.TextDocumentIdentifier { DocumentUri = looseFileUri }; await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false); // Verify that the file returned by the manager is in the lsp misc files workspace. await AssertFileInMiscWorkspaceAsync(testLspServer, looseFileUri).ConfigureAwait(false); - var (miscWorkspace, _, miscDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = looseFileUri }, CancellationToken.None); + var (miscWorkspace, _, miscDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = looseFileUri }, CancellationToken.None); Contract.ThrowIfNull(miscWorkspace); Contract.ThrowIfNull(miscDocument); Assert.True(miscWorkspace.CurrentSolution.ContainsDocument(miscDocument.Id)); @@ -291,13 +291,13 @@ void M() private static async Task AssertFileInMiscWorkspaceAsync(TestLspServer testLspServer, DocumentUri fileUri) { - var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None); + var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = fileUri }, CancellationToken.None); Assert.Equal(testLspServer.GetManagerAccessor().GetLspMiscellaneousFilesWorkspace(), lspWorkspace); } private static async Task AssertFileInMainWorkspaceAsync(TestLspServer testLspServer, DocumentUri fileUri) { - var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileUri }, CancellationToken.None).ConfigureAwait(false); + var (lspWorkspace, _, _) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = fileUri }, CancellationToken.None).ConfigureAwait(false); Assert.Equal(testLspServer.TestWorkspace, lspWorkspace); } diff --git a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs index 46d741ebe3b44..5eb39df178ed9 100644 --- a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs @@ -337,7 +337,7 @@ void M() internal static async Task GetTextDocumentAsync(TestLspServer testLspServer, DocumentUri uri) { - var (_, _, textDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new TextDocumentIdentifier { Uri = uri }, CancellationToken.None); + var (_, _, textDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new TextDocumentIdentifier { DocumentUri = uri }, CancellationToken.None); return textDocument; } } diff --git a/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs index 111273f1ab22d..a45a552c66a5e 100644 --- a/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/RelatedDocuments/RelatedDocumentsTests.cs @@ -29,7 +29,7 @@ private static async Task RunGetRelatedDocume VSInternalMethods.CopilotRelatedDocumentsName, new VSInternalRelatedDocumentParams { - TextDocument = new TextDocumentIdentifier { Uri = uri }, + TextDocument = new TextDocumentIdentifier { DocumentUri = uri }, PartialResultToken = progress, }, CancellationToken.None).ConfigureAwait(false); diff --git a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs index 8bb90b96b0892..65658b74ddbc0 100644 --- a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs @@ -181,7 +181,7 @@ void M2() var expectedMappedDocument = TestSpanMapper.MappedFileLocation.Uri; var documentEdit = results.DocumentChanges.Value.First.Single(); - Assert.Equal(expectedMappedDocument, documentEdit.TextDocument.Uri); + Assert.Equal(expectedMappedDocument, documentEdit.TextDocument.DocumentUri); Assert.Equal(expectedMappedRanges, documentEdit.Edits.Select(edit => edit.Unify().Range)); Assert.True(documentEdit.Edits.All(edit => edit.Unify().NewText == renameText)); } diff --git a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs index bcdb896c31833..ed4fd0f53eb4f 100644 --- a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs @@ -54,20 +54,20 @@ private protected static IReadOnlyDictionary GetTokenTypeToIndex(Te private static LSP.SemanticTokensFullParams CreateSemanticTokensFullParams(LSP.Location caret) => new LSP.SemanticTokensFullParams { - TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri } + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri } }; private static LSP.SemanticTokensRangeParams CreateSemanticTokensRangeParams(LSP.Location caret, LSP.Range range) => new LSP.SemanticTokensRangeParams { - TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, Range = range }; private static SemanticTokensRangesParams CreateSemanticTokensRangesParams(LSP.Location caret, Range[] ranges) => new SemanticTokensRangesParams { - TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, Ranges = ranges }; diff --git a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs index 867abc040b22b..be7d2a2f1a781 100644 --- a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs @@ -352,7 +352,7 @@ public async Task TestNoWorkspaceDiagnosticsForClosedFilesInProjectsWithIncorrec var results = await RunGetWorkspaceSpellCheckSpansAsync(testLspServer); - Assert.True(results.All(r => r.TextDocument!.Uri.GetRequiredParsedUri().LocalPath == "C:\\C.cs")); + Assert.True(results.All(r => r.TextDocument!.DocumentUri.GetRequiredParsedUri().LocalPath == "C:\\C.cs")); } // [Fact] @@ -639,7 +639,7 @@ private static VSInternalDocumentSpellCheckableParams CreateDocumentParams( { return new VSInternalDocumentSpellCheckableParams { - TextDocument = new TextDocumentIdentifier { Uri = uri }, + TextDocument = new TextDocumentIdentifier { DocumentUri = uri }, PreviousResultId = previousResultId, PartialResultToken = progress, }; @@ -651,14 +651,14 @@ private static VSInternalWorkspaceSpellCheckableParams CreateWorkspaceParams( { return new VSInternalWorkspaceSpellCheckableParams { - PreviousResults = previousResults?.Select(r => new VSInternalStreamingParams { PreviousResultId = r.resultId, TextDocument = new TextDocumentIdentifier { Uri = r.uri } }).ToArray(), + PreviousResults = previousResults?.Select(r => new VSInternalStreamingParams { PreviousResultId = r.resultId, TextDocument = new TextDocumentIdentifier { DocumentUri = r.uri } }).ToArray(), PartialResultToken = progress, }; } private static ImmutableArray<(string resultId, DocumentUri uri)> CreateParamsFromPreviousReports(VSInternalWorkspaceSpellCheckableReport[] results) { - return [.. results.Select(r => (r.ResultId!, r.TextDocument.Uri))]; + return [.. results.Select(r => (r.ResultId!, Uri:r.TextDocument.DocumentUri))]; } } } \ No newline at end of file diff --git a/src/LanguageServer/ProtocolUnitTests/UriTests.cs b/src/LanguageServer/ProtocolUnitTests/UriTests.cs index 22b2c38cf3eba..202a9ee678791 100644 --- a/src/LanguageServer/ProtocolUnitTests/UriTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/UriTests.cs @@ -50,7 +50,7 @@ void M() await testLspServer.OpenDocumentAsync(looseFileUri, source, languageId: "csharp").ConfigureAwait(false); // Verify file is added to the misc file workspace. - var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = looseFileUri }, CancellationToken.None); + var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = looseFileUri }, CancellationToken.None); Assert.True(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); @@ -76,7 +76,7 @@ void M() await testLspServer.OpenDocumentAsync(looseFileUri, source, languageId: "csharp").ConfigureAwait(false); // Verify file is added to the misc file workspace. - var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = looseFileUri }, CancellationToken.None); + var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = looseFileUri }, CancellationToken.None); Assert.True(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); @@ -108,7 +108,7 @@ public class A // Verify file is not added to the misc file workspace. { - var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = expectedDocumentUri }, CancellationToken.None); + var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = expectedDocumentUri }, CancellationToken.None); Assert.False(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); Assert.Equal(expectedDocumentUri, document.GetURI()); @@ -119,7 +119,7 @@ public class A { var lowercaseUri = ProtocolConversions.CreateAbsoluteDocumentUri(documentFilePath.ToLowerInvariant()); Assert.NotEqual(expectedDocumentUri.GetRequiredParsedUri().AbsolutePath, lowercaseUri.GetRequiredParsedUri().AbsolutePath); - var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = lowercaseUri }, CancellationToken.None); + var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = lowercaseUri }, CancellationToken.None); Assert.False(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); Assert.Equal(expectedDocumentUri, document.GetURI()); @@ -146,14 +146,14 @@ public async Task TestWorkspaceDocument_WithFileAndGitScheme(bool mutatingLspWor await testLspServer.OpenDocumentAsync(gitDocumentUri, gitDocumentText); // Verify file is added to the workspace and the text matches the file document - var (workspace, _, fileDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = fileDocumentUri }, CancellationToken.None); + var (workspace, _, fileDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = fileDocumentUri }, CancellationToken.None); AssertEx.NotNull(fileDocument); var fileTextResult = await fileDocument.GetTextAsync(); Assert.Equal(fileDocumentUri, fileDocument.GetURI()); Assert.Equal(fileDocumentText, fileTextResult.ToString()); // Verify file is added to the workspace and the text matches the git document - var (gitWorkspace, _, gitDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = gitDocumentUri }, CancellationToken.None); + var (gitWorkspace, _, gitDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = gitDocumentUri }, CancellationToken.None); AssertEx.NotNull(gitDocument); var gitText = await gitDocument.GetTextAsync(); Assert.Equal(gitDocumentUri, gitDocument.GetURI()); @@ -182,7 +182,7 @@ public async Task TestFindsExistingDocumentWhenUriHasDifferentEncodingAsync(bool var unencodedUri = JsonSerializer.Deserialize(jsonDocument, JsonSerializerOptions)!.TextDocument.Uri; // Access the document using the unencoded URI to make sure we find it in the C# misc files. - var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = unencodedUri }, CancellationToken.None).ConfigureAwait(false); + var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = unencodedUri }, CancellationToken.None).ConfigureAwait(false); AssertEx.NotNull(lspDocument); Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); @@ -193,11 +193,11 @@ public async Task TestFindsExistingDocumentWhenUriHasDifferentEncodingAsync(bool var encodedUriString = @"git:/c:/Users/dabarbet/source/repos/ConsoleApp10/ConsoleApp10/Program.cs?%7B%7B%22path%22:%22c:%5C%5CUsers%5C%5Cdabarbet%5C%5Csource%5C%5Crepos%5C%5CConsoleApp10%5C%5CConsoleApp10%5C%5CProgram.cs%22,%22ref%22:%22~%22%7D%7D"; var encodedUri = new DocumentUri(encodedUriString); var info = await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, - new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = encodedUri }), CancellationToken.None); + new CustomResolveParams(new LSP.TextDocumentIdentifier { DocumentUri = encodedUri }), CancellationToken.None); Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); - var (encodedWorkspace, _, encodedDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = encodedUri }, CancellationToken.None).ConfigureAwait(false); + var (encodedWorkspace, _, encodedDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = encodedUri }, CancellationToken.None).ConfigureAwait(false); Assert.Same(workspace, encodedWorkspace); AssertEx.NotNull(encodedDocument); Assert.Equal(LanguageNames.CSharp, encodedDocument.Project.Language); @@ -230,7 +230,7 @@ public async Task TestFindsExistingDocumentWhenUriHasDifferentCasingForCaseInsen await testLspServer.ExecutePreSerializedRequestAsync(LSP.Methods.TextDocumentDidOpenName, jsonDocument); // Access the document using the upper case to make sure we find it in the C# misc files. - var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = upperCaseUri }, CancellationToken.None).ConfigureAwait(false); + var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = upperCaseUri }, CancellationToken.None).ConfigureAwait(false); AssertEx.NotNull(lspDocument); Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); @@ -239,11 +239,11 @@ public async Task TestFindsExistingDocumentWhenUriHasDifferentCasingForCaseInsen // Now make a request using different case. var info = await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, - new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = lowerCaseUri }), CancellationToken.None); + new CustomResolveParams(new LSP.TextDocumentIdentifier { DocumentUri = lowerCaseUri }), CancellationToken.None); Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); - var (lowerCaseWorkspace, _, lowerCaseDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = lowerCaseUri }, CancellationToken.None).ConfigureAwait(false); + var (lowerCaseWorkspace, _, lowerCaseDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = lowerCaseUri }, CancellationToken.None).ConfigureAwait(false); Assert.Same(workspace, lowerCaseWorkspace); AssertEx.NotNull(lowerCaseDocument); Assert.Equal(LanguageNames.CSharp, lowerCaseDocument.Project.Language); @@ -276,7 +276,7 @@ public async Task TestUsesDifferentDocumentForDifferentCaseWithNonUncUriAsync(bo await testLspServer.ExecutePreSerializedRequestAsync(LSP.Methods.TextDocumentDidOpenName, jsonDocument); // Access the document using the upper case to make sure we find it in the C# misc files. - var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = upperCaseUri }, CancellationToken.None).ConfigureAwait(false); + var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = upperCaseUri }, CancellationToken.None).ConfigureAwait(false); AssertEx.NotNull(lspDocument); Assert.Equal(WorkspaceKind.MiscellaneousFiles, workspace?.Kind); Assert.Equal(LanguageNames.CSharp, lspDocument.Project.Language); @@ -286,7 +286,7 @@ public async Task TestUsesDifferentDocumentForDifferentCaseWithNonUncUriAsync(bo // Now make a request using different case. This should throw since we have not opened a document with the URI with different case (and not UNC). await Assert.ThrowsAnyAsync(async () => await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, - new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = lowerCaseUri }), CancellationToken.None)); + new CustomResolveParams(new LSP.TextDocumentIdentifier { DocumentUri = lowerCaseUri }), CancellationToken.None)); } [Theory, CombinatorialData] @@ -300,7 +300,7 @@ public async Task TestDoesNotCrashIfUnableToDetermineLanguageInfo(bool mutatingL await testLspServer.OpenDocumentAsync(looseFileUri, "hello", languageId: "csharp").ConfigureAwait(false); // Verify file is added to the misc file workspace. - var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = looseFileUri }, CancellationToken.None); + var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = looseFileUri }, CancellationToken.None); Assert.True(workspace is LspMiscellaneousFilesWorkspace); AssertEx.NotNull(document); Assert.Equal(looseFileUri, document.GetURI()); @@ -312,7 +312,7 @@ public async Task TestDoesNotCrashIfUnableToDetermineLanguageInfo(bool mutatingL // Assert that the request throws but the server does not crash. await Assert.ThrowsAnyAsync(async () => await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, - new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = looseFileUri }), CancellationToken.None)); + new CustomResolveParams(new LSP.TextDocumentIdentifier { DocumentUri = looseFileUri }), CancellationToken.None)); Assert.False(testLspServer.GetServerAccessor().HasShutdownStarted()); Assert.False(testLspServer.GetQueueAccessor()!.Value.IsComplete()); } @@ -342,13 +342,13 @@ public async Task TestOpenDocumentWithInvalidUri(bool mutatingLspWorkspace, stri // Verify requests succeed and that the file is in misc. var info = await testLspServer.ExecuteRequestAsync(CustomResolveHandler.MethodName, - new CustomResolveParams(new LSP.TextDocumentIdentifier { Uri = invalidUri }), CancellationToken.None); + new CustomResolveParams(new LSP.TextDocumentIdentifier { DocumentUri = invalidUri }), CancellationToken.None); Assert.Equal(WorkspaceKind.MiscellaneousFiles, info!.WorkspaceKind); Assert.Equal(LanguageNames.CSharp, info.ProjectLanguage); // Verify we can modify the document in misc. await testLspServer.InsertTextAsync(invalidUri, (0, 0, "hello")); - var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { Uri = invalidUri }, CancellationToken.None); + var (workspace, _, document) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = invalidUri }, CancellationToken.None); Assert.Equal("hello", (await document!.GetTextAsync()).ToString()); } diff --git a/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs b/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs index efb5e3b3028c3..39381b743b70f 100644 --- a/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs @@ -262,7 +262,7 @@ void M() LSP.VSInternalMethods.TextDocumentValidateBreakableRangeName, new LSP.VSInternalValidateBreakableRangeParams() { - TextDocument = new LSP.TextDocumentIdentifier { Uri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, Range = caret.Range }, CancellationToken.None); diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs index 630b1d5b059dc..71d677c3c6a72 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs @@ -30,7 +30,7 @@ public async Task ReturnsTextForSourceGeneratedDocument(bool mutatingLspWorkspac var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal("// Hello, World", text.Text); @@ -46,7 +46,7 @@ public async Task OpenCloseSourceGeneratedDocument(bool mutatingLspWorkspace) var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal("// Hello, World", text.Text); @@ -71,7 +71,7 @@ public async Task OpenMultipleSourceGeneratedDocument(bool mutatingLspWorkspace) foreach (var sourceGeneratorDocumentUri in sourceGeneratorDocumentUris) { var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text?.Text); await testLspServer.OpenDocumentAsync(sourceGeneratorDocumentUri, text.Text); } @@ -115,7 +115,7 @@ public async Task ReturnsGeneratedSourceForOpenDocument(bool mutatingLspWorkspac await testLspServer.OpenDocumentAsync(sourceGeneratorDocumentUri, "LSP Open Document Text"); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal(sourceGeneratorSource, text.Text); @@ -131,14 +131,14 @@ public async Task TestReturnsUnchangedResult(bool mutatingLspWorkspace) var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal("// Hello, World", text.Text); // Make a second request - since nothing has changed we should get back the same resultId. var secondRequest = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); AssertEx.NotNull(secondRequest); Assert.Null(secondRequest.Text); Assert.Equal(text.ResultId, secondRequest.ResultId); @@ -160,7 +160,7 @@ internal async Task TestReturnsGeneratedSourceWhenDocumentChanges(bool mutatingL var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal("// callCount: 0", text.Text); @@ -173,7 +173,7 @@ internal async Task TestReturnsGeneratedSourceWhenDocumentChanges(bool mutatingL // Ask for the source generated text again. var secondRequest = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); if (sourceGeneratorExecution == SourceGeneratorExecutionPreference.Automatic) { @@ -207,7 +207,7 @@ internal async Task TestReturnsGeneratedSourceWhenManuallyRefreshed(bool mutatin var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal("// callCount: 0", text.Text); @@ -217,7 +217,7 @@ internal async Task TestReturnsGeneratedSourceWhenManuallyRefreshed(bool mutatin await testLspServer.WaitForSourceGeneratorsAsync(); var secondRequest = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); AssertEx.NotNull(secondRequest); Assert.NotEqual(text.ResultId, secondRequest.ResultId); Assert.Equal("// callCount: 1", secondRequest.Text); @@ -235,7 +235,7 @@ public async Task TestReturnsNullForRemovedClosedGeneratedFile(bool mutatingLspW var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal("// Hello, World", text.Text); @@ -243,7 +243,7 @@ public async Task TestReturnsNullForRemovedClosedGeneratedFile(bool mutatingLspW await RemoveGeneratorAsync(generatorReference, testLspServer.TestWorkspace); var secondRequest = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); Assert.NotNull(secondRequest); Assert.Null(secondRequest.Text); @@ -261,7 +261,7 @@ public async Task TestReturnsNullForRemovedOpenedGeneratedFile(bool mutatingLspW var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); var text = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: null), CancellationToken.None); AssertEx.NotNull(text); Assert.Equal("// Hello, World", text.Text); @@ -273,7 +273,7 @@ public async Task TestReturnsNullForRemovedOpenedGeneratedFile(bool mutatingLspW await RemoveGeneratorAsync(generatorReference, testLspServer.TestWorkspace); var secondRequest = await testLspServer.ExecuteRequestAsync(SourceGeneratedDocumentGetTextHandler.MethodName, - new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { Uri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); + new SourceGeneratorGetTextParams(new LSP.TextDocumentIdentifier { DocumentUri = sourceGeneratorDocumentUri }, ResultId: text.ResultId), CancellationToken.None); Assert.NotNull(secondRequest); Assert.Null(secondRequest.Text); diff --git a/src/Tools/ExternalAccess/Razor/Features/Cohost/AbstractRazorCohostDocumentRequestHandler.cs b/src/Tools/ExternalAccess/Razor/Features/Cohost/AbstractRazorCohostDocumentRequestHandler.cs index 53a3706e7c329..beb4fe048a530 100644 --- a/src/Tools/ExternalAccess/Razor/Features/Cohost/AbstractRazorCohostDocumentRequestHandler.cs +++ b/src/Tools/ExternalAccess/Razor/Features/Cohost/AbstractRazorCohostDocumentRequestHandler.cs @@ -20,7 +20,7 @@ internal abstract class AbstractRazorCohostDocumentRequestHandler new DataResolveData(data, new LSP.TextDocumentIdentifier { Uri = new(uri) }); + => new DataResolveData(data, new LSP.TextDocumentIdentifier { DocumentUri = new(uri) }); public static (object? data, Uri? uri) FromResolveData(object? requestData) { Contract.ThrowIfNull(requestData); var resolveData = JsonSerializer.Deserialize((JsonElement)requestData); - return (resolveData?.Data, resolveData?.Document.Uri.GetRequiredParsedUri()); + return (resolveData?.Data, resolveData?.Document.DocumentUri.GetRequiredParsedUri()); } internal static object ToCachedResolveData(object data, Uri uri, ResolveDataCache resolveDataCache) { var dataId = resolveDataCache.UpdateCache(data); - return new DataIdResolveData(dataId, new LSP.TextDocumentIdentifier { Uri = new(uri) }); + return new DataIdResolveData(dataId, new LSP.TextDocumentIdentifier { DocumentUri = new(uri) }); } internal static (object? data, Uri? uri) FromCachedResolveData(object? lspData, ResolveDataCache resolveDataCache) @@ -50,6 +50,6 @@ internal static (object? data, Uri? uri) FromCachedResolveData(object? lspData, var data = resolveDataCache.GetCachedEntry(resolveData.DataId); var document = resolveData.Document; - return (data, document.Uri.GetRequiredParsedUri()); + return (data, document.DocumentUri.GetRequiredParsedUri()); } } diff --git a/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs b/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs index 7256368655b43..d48c2dd7f4b76 100644 --- a/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs +++ b/src/Tools/ExternalAccess/Xaml/External/XamlRequestHandlerBase.cs @@ -25,7 +25,7 @@ public XamlRequestHandlerBase(IXamlRequestHandler? xamlRequ public bool RequiresLSPSolution => true; public LSP.TextDocumentIdentifier GetTextDocumentIdentifier(TRequest request) - => new() { Uri = new(GetTextDocumentUri(request)) }; + => new() { DocumentUri = new(GetTextDocumentUri(request)) }; public abstract Uri GetTextDocumentUri(TRequest request); diff --git a/src/Tools/ExternalAccess/Xaml/Internal/XamlDiagnosticSource.cs b/src/Tools/ExternalAccess/Xaml/Internal/XamlDiagnosticSource.cs index 1cee9dbe1b173..2da252a3ab76a 100644 --- a/src/Tools/ExternalAccess/Xaml/Internal/XamlDiagnosticSource.cs +++ b/src/Tools/ExternalAccess/Xaml/Internal/XamlDiagnosticSource.cs @@ -19,7 +19,7 @@ internal sealed class XamlDiagnosticSource(IXamlDiagnosticSource xamlDiagnosticS bool IDiagnosticSource.IsLiveSource() => true; Project IDiagnosticSource.GetProject() => document.Project; ProjectOrDocumentId IDiagnosticSource.GetId() => new(document.Id); - TextDocumentIdentifier? IDiagnosticSource.GetDocumentIdentifier() => new() { Uri = document.GetURI() }; + TextDocumentIdentifier? IDiagnosticSource.GetDocumentIdentifier() => new() { DocumentUri = document.GetURI() }; string IDiagnosticSource.ToDisplayString() => $"{this.GetType().Name}: {document.FilePath ?? document.Name} in {document.Project.Name}"; async Task> IDiagnosticSource.GetDiagnosticsAsync(RequestContext context, CancellationToken cancellationToken) diff --git a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs index bc93359b89082..f43638369658f 100644 --- a/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs +++ b/src/VisualStudio/Core/Def/DocumentOutline/DocumentOutlineViewModel_Utilities.cs @@ -46,7 +46,7 @@ internal sealed partial class DocumentOutlineViewModel { TextDocument = new TextDocumentIdentifier { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(textViewFilePath), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(textViewFilePath), }, UseHierarchicalSymbols = true }; diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs index 7c8b5b8e8f96f..bdb2f1ccc8413 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs @@ -115,7 +115,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe if (sourceDefinition.Span != null) { // If the Span is not null, use the span. - var document = await solution.GetTextDocumentAsync(new TextDocumentIdentifier { Uri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath) }, cancellationToken).ConfigureAwait(false); + var document = await solution.GetTextDocumentAsync(new TextDocumentIdentifier { DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath) }, cancellationToken).ConfigureAwait(false); if (document != null) { return await ProtocolConversions.TextSpanToLocationAsync( diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs index 58c8a001d7c44..3bb231f779f24 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/XamlRequestExecutionQueue.cs @@ -24,7 +24,7 @@ public XamlRequestExecutionQueue( protected internal override void BeforeRequest(TRequest request) { - if (request is ITextDocumentParams { TextDocument.Uri: { ParsedUri: not null } documentUri }) + if (request is ITextDocumentParams { TextDocument.DocumentUri: { ParsedUri: not null } documentUri }) { _projectService.TrackOpenDocument(documentUri.ParsedUri.LocalPath); } From 8842f8cec668528d6be327f9211f2f5e3e3e2f0e Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 14 Apr 2025 16:34:06 -0700 Subject: [PATCH 7/9] Add backwards compatible properties for Uris used by Xaml/Razor --- .../ServerInitializationTests.cs | 2 +- .../Services/ExtractRefactoringTests.cs | 2 +- .../AbstractLanguageServerClientTests.cs | 4 +- .../AbstractLanguageServerProtocolTests.cs | 16 +++--- .../ProtocolConversions.Diagnostics.cs | 2 +- .../Extensions/ProtocolConversions.cs | 6 +-- .../CodeActions/CodeActionResolveHelper.cs | 6 +-- .../AbstractGoToDefinitionHandler.cs | 2 +- .../Handler/DocumentChanges/DidOpenHandler.cs | 4 +- .../Handler/MapCode/MapCodeHandler.cs | 2 +- .../GetTextDocumentWithContextHandler.cs | 4 +- .../References/FindUsagesLSPContext.cs | 4 +- .../Protocol/Handler/RequestContextFactory.cs | 2 +- .../Handler/Symbols/DocumentSymbolsHandler.cs | 2 +- .../Protocol/Protocol/CreateFile.cs | 11 +++- .../Protocol/Protocol/DeleteFile.cs | 11 +++- .../Protocol/Protocol/DocumentLink.cs | 11 +++- .../Protocol/Protocol/InitializeParams.cs | 11 +++- .../Protocol/Protocol/Location.cs | 17 +++++-- .../Protocol/Protocol/RenameFile.cs | 21 +++++++- .../Protocol/TextDocumentIdentifier.cs | 7 ++- .../Protocol/Protocol/TextDocumentItem.cs | 11 +++- .../Protocol/Protocol/WorkspaceFolder.cs | 11 +++- .../CodeActions/CodeActionResolveTests.cs | 8 +-- .../CodeActions/CodeActionsTests.cs | 12 ++--- .../CodeActions/RunCodeActionsTests.cs | 2 +- .../Completion/CompletionFeaturesTests.cs | 32 ++++++------ .../Completion/CompletionTests.cs | 28 +++++------ .../DataTips/DataTipRangeHandlerTests.cs | 2 +- .../Definitions/GoToDefinitionTests.cs | 8 +-- .../Definitions/GoToTypeDefinitionTests.cs | 6 +-- .../Diagnostics/PullDiagnosticTests.cs | 4 +- .../DocumentChangesTests.LinkedDocuments.cs | 14 +++--- ...umentChangesTests.WithFindAllReferences.cs | 10 ++-- .../DocumentChanges/DocumentChangesTests.cs | 50 +++++++++---------- .../Formatting/FormatDocumentOnTypeTests.cs | 4 +- .../Formatting/FormatDocumentRangeTests.cs | 6 +-- .../Formatting/FormatDocumentTests.cs | 18 +++---- .../InlineCompletionsTests.cs | 4 +- .../LanguageServerTargetTests.cs | 4 +- .../ProtocolUnitTests/MapCode/MapCodeTests.cs | 2 +- .../LspMetadataAsSourceWorkspaceTests.cs | 14 +++--- .../LspMiscellaneousFilesWorkspaceTests.cs | 4 +- .../OnAutoInsert/OnAutoInsertTests.cs | 6 +-- .../Ordering/RequestOrderingTests.cs | 6 +-- .../GetTextDocumentWithContextHandlerTests.cs | 8 +-- .../ProtocolConversionsTests.cs | 2 +- .../FindAllReferencesHandlerTests.cs | 4 +- .../References/FindImplementationsTests.cs | 2 +- .../Rename/PrepareRenameTests.cs | 2 +- .../ProtocolUnitTests/Rename/RenameTests.cs | 6 +-- .../AbstractSemanticTokensTests.cs | 6 +-- .../SimplifyMethod/SimplifyMethodTests.cs | 2 +- .../ProtocolUnitTests/UriTests.cs | 2 +- .../ValidateBreakableRangeTests.cs | 2 +- .../SourceGeneratedDocumentTests.cs | 2 +- .../LspCompletionSerializationBenchmarks.cs | 2 +- .../Client/RemoteLanguageServiceWorkspace.cs | 2 +- .../Definitions/GoToDefinitionHandler.cs | 6 +-- 59 files changed, 273 insertions(+), 188 deletions(-) diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs index ce45eed29f628..359b95da3458b 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/ServerInitializationTests.cs @@ -23,7 +23,7 @@ public async Task TestServerHandlesTextSyncRequestsAsync() { TextDocument = new TextDocumentItem { - Uri = document.DocumentUri, + DocumentUri = document.DocumentUri, Text = "Write" } }, CancellationToken.None); diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Services/ExtractRefactoringTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Services/ExtractRefactoringTests.cs index c65ad07d3a9ab..dfdaee88a9ab0 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Services/ExtractRefactoringTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Services/ExtractRefactoringTests.cs @@ -93,7 +93,7 @@ private static async Task TestCodeActionAsync( testLspClient.ApplyWorkspaceEdit(resolvedCodeAction.Edit); - var updatedCode = testLspClient.GetDocumentText(caretLocation.Uri); + var updatedCode = testLspClient.GetDocumentText(caretLocation.DocumentUri); AssertEx.Equal(expected, updatedCode); } diff --git a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs index 99a394edf4b6a..cf2a6c5e807cb 100644 --- a/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs +++ b/src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer.UnitTests/Utilities/AbstractLanguageServerClientTests.cs @@ -110,7 +110,7 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText { var location = new LSP.Location { - Uri = documentUri, + DocumentUri = documentUri, Range = ProtocolConversions.TextSpanToRange(span, text), }; @@ -138,7 +138,7 @@ private protected static TextDocumentIdentifier CreateTextDocumentIdentifier(Doc private protected static CodeActionParams CreateCodeActionParams(LSP.Location location) => new() { - TextDocument = CreateTextDocumentIdentifier(location.Uri), + TextDocument = CreateTextDocumentIdentifier(location.DocumentUri), Range = location.Range, Context = new CodeActionContext { diff --git a/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs index cf6f0dc2b321e..5aa54f9f00c67 100644 --- a/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs +++ b/src/LanguageServer/Protocol.TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs @@ -68,7 +68,7 @@ internal sealed class TestSpanMapper : ISpanMappingService internal static readonly LSP.Location MappedFileLocation = new LSP.Location { Range = ProtocolConversions.LinePositionToRange(s_mappedLinePosition), - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(s_mappedFilePath) + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(s_mappedFilePath) }; /// @@ -153,7 +153,7 @@ private protected static int CompareLocations(LSP.Location? l1, LSP.Location? l2 if (l2 is null) return 1; - var compareDocument = l1.Uri.UriString.CompareTo(l2.Uri.UriString); + var compareDocument = l1.DocumentUri.UriString.CompareTo(l2.DocumentUri.UriString); var compareRange = CompareRange(l1.Range, l2.Range); return compareDocument != 0 ? compareDocument : compareRange; } @@ -207,7 +207,7 @@ private protected static LSP.TextDocumentIdentifier CreateTextDocumentIdentifier private protected static LSP.TextDocumentPositionParams CreateTextDocumentPositionParams(LSP.Location caret, ProjectId? projectContext = null) => new LSP.TextDocumentPositionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri, projectContext), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri, projectContext), Position = caret.Range.Start }; @@ -225,7 +225,7 @@ private protected static LSP.CompletionParams CreateCompletionParams( LSP.CompletionTriggerKind triggerKind) => new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.VSInternalCompletionContext() { @@ -292,7 +292,7 @@ private protected static LSP.TextEdit GenerateTextEdit(string newText, int start }; private protected static CodeActionResolveData CreateCodeActionResolveData(string uniqueIdentifier, LSP.Location location, string[] codeActionPath, IEnumerable? customTags = null) - => new(uniqueIdentifier, customTags.ToImmutableArrayOrEmpty(), location.Range, CreateTextDocumentIdentifier(location.Uri), fixAllFlavors: null, nestedCodeActions: null, codeActionPath: codeActionPath); + => new(uniqueIdentifier, customTags.ToImmutableArrayOrEmpty(), location.Range, CreateTextDocumentIdentifier(location.DocumentUri), fixAllFlavors: null, nestedCodeActions: null, codeActionPath: codeActionPath); private protected Task CreateTestLspServerAsync([StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string markup, bool mutatingLspWorkspace, LSP.ClientCapabilities clientCapabilities, bool callInitialized = true) => CreateTestLspServerAsync([markup], LanguageNames.CSharp, mutatingLspWorkspace, new InitializationOptions { ClientCapabilities = clientCapabilities, CallInitialized = callInitialized }); @@ -478,7 +478,7 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText { var location = new LSP.Location { - Uri = documentUri, + DocumentUri = documentUri, Range = ProtocolConversions.TextSpanToRange(span, text), }; @@ -491,7 +491,7 @@ private protected static LSP.Location GetLocationPlusOne(LSP.Location originalLo var newPosition = new LSP.Position { Character = originalLocation.Range.Start.Character + 1, Line = originalLocation.Range.Start.Line }; return new LSP.Location { - Uri = originalLocation.Uri, + DocumentUri = originalLocation.DocumentUri, Range = new LSP.Range { Start = newPosition, End = newPosition } }; } @@ -525,7 +525,7 @@ private static LSP.DidOpenTextDocumentParams CreateDidOpenTextDocumentParams(Doc TextDocument = new LSP.TextDocumentItem { Text = source, - Uri = uri, + DocumentUri = uri, LanguageId = languageId } }; diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs index 4f6d615ad522d..0bf58091d3323 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.Diagnostics.cs @@ -82,7 +82,7 @@ internal static partial class ProtocolConversions Location = new LSP.Location { Range = GetRange(l), - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(l.UnmappedFileSpan.Path) + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(l.UnmappedFileSpan.Path) }, Message = diagnostic.Message }).ToArray(); diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 2bdb07a1d45f0..1b0ef2b6e740e 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -378,7 +378,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) return location == null ? null : new LSP.VSInternalLocation { - Uri = location.Uri, + DocumentUri = location.DocumentUri, Range = location.Range, Text = text }; @@ -497,7 +497,7 @@ public static LSP.Range TextSpanToRange(TextSpan textSpan, SourceText text) return new LSP.Location { - Uri = uri, + DocumentUri = uri, Range = MappedSpanResultToRange(mappedSpan) }; @@ -527,7 +527,7 @@ static LSP.Location ConvertTextSpanWithTextToLocation(TextSpan span, SourceText { var location = new LSP.Location { - Uri = documentUri, + DocumentUri = documentUri, Range = TextSpanToRange(span, text), }; diff --git a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs index 6dcf9eba1bcbb..de8d79e7abd92 100644 --- a/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs +++ b/src/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHelper.cs @@ -220,7 +220,7 @@ Task AddTextDocumentDeletionsAsync( var oldTextDoc = getOldDocument(docId); Contract.ThrowIfNull(oldTextDoc); - textDocumentEdits.Add(new DeleteFile { Uri = oldTextDoc.GetURI() }); + textDocumentEdits.Add(new DeleteFile { DocumentUri = oldTextDoc.GetURI() }); } return Task.CompletedTask; @@ -252,7 +252,7 @@ async Task AddTextDocumentAdditionsAsync( Contract.Fail($"Can't find uri for document: {newTextDoc.Name}."); } - textDocumentEdits.Add(new CreateFile { Uri = uri }); + textDocumentEdits.Add(new CreateFile { DocumentUri = uri }); // And then give it content var newText = await newTextDoc.GetValueTextAsync(cancellationToken).ConfigureAwait(false); @@ -312,7 +312,7 @@ async Task AddTextDocumentEditsAsync( // So we would like to first edit the old document, then rename it. if (oldTextDoc.Name != newTextDoc.Name) { - textDocumentEdits.Add(new RenameFile() { OldUri = oldTextDoc.GetURI(), NewUri = newTextDoc.GetUriForRenamedDocument() }); + textDocumentEdits.Add(new RenameFile() { OldDocumentUri = oldTextDoc.GetURI(), NewDocumentUri = newTextDoc.GetUriForRenamedDocument() }); } var linkedDocuments = solution.GetRelatedDocumentIds(docId); diff --git a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs index da1640dc08ffd..9d1f1f4075bdc 100644 --- a/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Definitions/AbstractGoToDefinitionHandler.cs @@ -88,7 +88,7 @@ await definition.Document.GetRequiredDocumentAsync(document.Project.Solution, ca var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(declarationFile.FilePath!), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(declarationFile.FilePath!), Range = ProtocolConversions.LinePositionToRange(linePosSpan), }); } diff --git a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs index 29342b158afd7..eb6f36942b79a 100644 --- a/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs +++ b/src/LanguageServer/Protocol/Handler/DocumentChanges/DidOpenHandler.cs @@ -32,13 +32,13 @@ public DidOpenHandler() public async Task HandleNotificationAsync(LSP.DidOpenTextDocumentParams request, RequestContext context, CancellationToken cancellationToken) { // GetTextDocumentIdentifier returns null to avoid creating the solution, so the queue is not able to log the uri. - context.TraceInformation($"didOpen for {request.TextDocument.Uri}"); + context.TraceInformation($"didOpen for {request.TextDocument.DocumentUri}"); // Add the document and ensure the text we have matches whats on the client // TODO (https://github.com/dotnet/roslyn/issues/63583): // Create SourceText from binary representation of the document, retrieve encoding from the request and checksum algorithm from the project. var sourceText = SourceText.From(request.TextDocument.Text, System.Text.Encoding.UTF8, SourceHashAlgorithms.OpenDocumentChecksumAlgorithm); - await context.StartTrackingAsync(request.TextDocument.Uri, sourceText, request.TextDocument.LanguageId, cancellationToken).ConfigureAwait(false); + await context.StartTrackingAsync(request.TextDocument.DocumentUri, sourceText, request.TextDocument.LanguageId, cancellationToken).ConfigureAwait(false); } } diff --git a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs index 0261aa3f81bc7..eda5bf4dd5a52 100644 --- a/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs +++ b/src/LanguageServer/Protocol/Handler/MapCode/MapCodeHandler.cs @@ -125,7 +125,7 @@ public MapCodeHandler() foreach (var location in locationsOfSamePriority) { // Ignore anything not in target document, which current code mapper doesn't handle anyway - if (!location.Uri.Equals(textDocumentIdentifier.DocumentUri)) + if (!location.DocumentUri.Equals(textDocumentIdentifier.DocumentUri)) { context.TraceInformation($"A focus location in '{textDocumentIdentifier.DocumentUri}' is skipped, only locations in corresponding MapCodeMapping.TextDocument is currently considered."); continue; diff --git a/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs b/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs index 4373464f73195..73191ad66716d 100644 --- a/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs +++ b/src/LanguageServer/Protocol/Handler/ProjectContext/GetTextDocumentWithContextHandler.cs @@ -28,7 +28,7 @@ public GetTextDocumentWithContextHandler() public bool MutatesSolutionState => false; public bool RequiresLSPSolution => true; - public TextDocumentIdentifier GetTextDocumentIdentifier(VSGetProjectContextsParams request) => new TextDocumentIdentifier { DocumentUri = request.TextDocument.Uri }; + public TextDocumentIdentifier GetTextDocumentIdentifier(VSGetProjectContextsParams request) => new TextDocumentIdentifier { DocumentUri = request.TextDocument.DocumentUri }; public Task HandleRequestAsync(VSGetProjectContextsParams request, RequestContext context, CancellationToken cancellationToken) { @@ -37,7 +37,7 @@ public GetTextDocumentWithContextHandler() // We specifically don't use context.Document here because we want multiple. We also don't need // all of the document info, just the Id is enough - var documentIds = context.Solution.GetDocumentIds(request.TextDocument.Uri); + var documentIds = context.Solution.GetDocumentIds(request.TextDocument.DocumentUri); if (!documentIds.Any()) { diff --git a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs index d1577a0e77f8d..1cfabad69bc18 100644 --- a/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs +++ b/src/LanguageServer/Protocol/Handler/References/FindUsagesLSPContext.cs @@ -218,7 +218,7 @@ public override async ValueTask OnReferencesFoundAsync(IAsyncEnumerable CreateRequestContextAsync(IQ var textDocumentItem = uHandler.GetTextDocumentIdentifier(requestParam); textDocumentIdentifier = new TextDocumentIdentifier { - DocumentUri = textDocumentItem.Uri, + DocumentUri = textDocumentItem.DocumentUri, }; } else if (textDocumentIdentifierHandler is null) diff --git a/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs b/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs index e731894961e0f..7d1dff87ea08a 100644 --- a/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs +++ b/src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs @@ -95,7 +95,7 @@ internal static async Task> GetDo var kind = ProtocolConversions.GlyphToSymbolKind(item.Glyph); var location = new LSP.Location() { - Uri = document.GetURI(), + DocumentUri = document.GetURI(), Range = ProtocolConversions.TextSpanToRange(symbolItem.Location.InDocumentInfo.Value.navigationSpan, text), }; diff --git a/src/LanguageServer/Protocol/Protocol/CreateFile.cs b/src/LanguageServer/Protocol/Protocol/CreateFile.cs index d6d886ca32286..2399fc2e20cb7 100644 --- a/src/LanguageServer/Protocol/Protocol/CreateFile.cs +++ b/src/LanguageServer/Protocol/Protocol/CreateFile.cs @@ -6,6 +6,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// Class representing a create file operation. @@ -30,12 +31,20 @@ internal sealed class CreateFile : IAnnotatedChange [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri Uri + public DocumentUri DocumentUri { get; set; } + [Obsolete("Use DocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri Uri + { + get => DocumentUri.GetRequiredParsedUri(); + set => DocumentUri = new DocumentUri(value); + } + /// /// Gets or sets the additional options. /// diff --git a/src/LanguageServer/Protocol/Protocol/DeleteFile.cs b/src/LanguageServer/Protocol/Protocol/DeleteFile.cs index e27f0f075673f..c13bb18500c06 100644 --- a/src/LanguageServer/Protocol/Protocol/DeleteFile.cs +++ b/src/LanguageServer/Protocol/Protocol/DeleteFile.cs @@ -6,6 +6,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// Class representing a delete file operation. @@ -30,12 +31,20 @@ internal sealed class DeleteFile : IAnnotatedChange [JsonPropertyName("uri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri Uri + public DocumentUri DocumentUri { get; set; } + [Obsolete("Use DocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri Uri + { + get => DocumentUri.GetRequiredParsedUri(); + set => DocumentUri = new DocumentUri(value); + } + /// /// Gets or sets the additional options. /// diff --git a/src/LanguageServer/Protocol/Protocol/DocumentLink.cs b/src/LanguageServer/Protocol/Protocol/DocumentLink.cs index 11b5679897fc8..630cb5e9d9861 100644 --- a/src/LanguageServer/Protocol/Protocol/DocumentLink.cs +++ b/src/LanguageServer/Protocol/Protocol/DocumentLink.cs @@ -6,6 +6,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// A document link is a range in a text document that links to an internal or @@ -32,12 +33,20 @@ public Range Range [JsonPropertyName("target")] [JsonConverter(typeof(DocumentUriConverter))] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public DocumentUri? Target + public DocumentUri? DocumentTarget { get; set; } + [Obsolete("Use DocumentTarget instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri Target + { + get => DocumentTarget.GetRequiredParsedUri(); + set => DocumentTarget = new DocumentUri(value); + } + /// /// The tooltip text when you hover over this link. /// diff --git a/src/LanguageServer/Protocol/Protocol/InitializeParams.cs b/src/LanguageServer/Protocol/Protocol/InitializeParams.cs index e2cfce1ec6c83..29bd0abb68fa6 100644 --- a/src/LanguageServer/Protocol/Protocol/InitializeParams.cs +++ b/src/LanguageServer/Protocol/Protocol/InitializeParams.cs @@ -7,6 +7,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.ComponentModel; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// Class which represents the parameter sent with an initialize method request. @@ -67,12 +68,20 @@ public string? RootPath [JsonPropertyName("rootUri")] [Obsolete("Deprecated in favor of WorkspaceFolders")] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri? RootUri + public DocumentUri? RootDocumentUri { get; set; } + [Obsolete("Use RootDocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri RootUri + { + get => RootDocumentUri.GetRequiredParsedUri(); + set => RootDocumentUri = new DocumentUri(value); + } + /// /// Gets or sets the initialization options as specified by the client. /// diff --git a/src/LanguageServer/Protocol/Protocol/Location.cs b/src/LanguageServer/Protocol/Protocol/Location.cs index 94f77bbfe0cc5..aa3d983412d8e 100644 --- a/src/LanguageServer/Protocol/Protocol/Location.cs +++ b/src/LanguageServer/Protocol/Protocol/Location.cs @@ -7,6 +7,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.Collections.Generic; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// Class representing a location in a document. @@ -20,12 +21,20 @@ internal class Location : IEquatable /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri Uri + public DocumentUri DocumentUri { get; set; } + [Obsolete("Use DocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri Uri + { + get => DocumentUri.GetRequiredParsedUri(); + set => DocumentUri = new DocumentUri(value); + } + /// /// Gets or sets the range of the location in the document. /// @@ -45,14 +54,14 @@ public override bool Equals(object obj) public bool Equals(Location? other) { - return other != null && this.Uri != null && other.Uri != null && - this.Uri.Equals(other.Uri) && + return other != null && this.DocumentUri != null && other.DocumentUri != null && + this.DocumentUri.Equals(other.DocumentUri) && EqualityComparer.Default.Equals(this.Range, other.Range); } public override int GetHashCode() { var hashCode = 1486144663; - hashCode = (hashCode * -1521134295) + this.Uri.GetHashCode(); + hashCode = (hashCode * -1521134295) + this.DocumentUri.GetHashCode(); hashCode = (hashCode * -1521134295) + EqualityComparer.Default.GetHashCode(this.Range); return hashCode; } diff --git a/src/LanguageServer/Protocol/Protocol/RenameFile.cs b/src/LanguageServer/Protocol/Protocol/RenameFile.cs index 2ca6261bbc35e..234f5a7639c0f 100644 --- a/src/LanguageServer/Protocol/Protocol/RenameFile.cs +++ b/src/LanguageServer/Protocol/Protocol/RenameFile.cs @@ -6,6 +6,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// Class representing a rename file operation. @@ -30,24 +31,40 @@ internal sealed class RenameFile : IAnnotatedChange [JsonPropertyName("oldUri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri OldUri + public DocumentUri OldDocumentUri { get; set; } + [Obsolete("Use OldDocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri OldUri + { + get => OldDocumentUri.GetRequiredParsedUri(); + set => OldDocumentUri = new DocumentUri(value); + } + /// /// Gets or sets the new location. /// [JsonPropertyName("newUri")] [JsonRequired] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri NewUri + public DocumentUri NewDocumentUri { get; set; } + [Obsolete("Use NewDocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri NewUri + { + get => NewDocumentUri.GetRequiredParsedUri(); + set => NewDocumentUri = new DocumentUri(value); + } + /// /// Gets or sets the rename options. /// diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs index 9ac9665575288..baa2e341ce9a3 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentIdentifier.cs @@ -23,7 +23,12 @@ internal class TextDocumentIdentifier : IEquatable public DocumentUri DocumentUri { get; set; } [Obsolete("Use DocumentUri instead. This property will be removed in a future version.")] - public Uri Uri => DocumentUri.GetRequiredParsedUri(); + [JsonIgnore] + public Uri Uri + { + get => DocumentUri.GetRequiredParsedUri(); + set => DocumentUri = new DocumentUri(value); + } public static bool operator ==(TextDocumentIdentifier? value1, TextDocumentIdentifier? value2) { diff --git a/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs b/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs index 6d58da53f9693..17025b8f699a5 100644 --- a/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs +++ b/src/LanguageServer/Protocol/Protocol/TextDocumentItem.cs @@ -6,6 +6,7 @@ namespace Roslyn.LanguageServer.Protocol; using System; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; /// /// Class which represents a text document. @@ -19,12 +20,20 @@ internal sealed class TextDocumentItem /// [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] - public DocumentUri Uri + public DocumentUri DocumentUri { get; set; } + [Obsolete("Use DocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri Uri + { + get => DocumentUri.GetRequiredParsedUri(); + set => DocumentUri = new DocumentUri(value); + } + /// /// Gets or sets the document language identifier. /// diff --git a/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs b/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs index f1b06048bbea1..051e9d514e20a 100644 --- a/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs +++ b/src/LanguageServer/Protocol/Protocol/WorkspaceFolder.cs @@ -4,6 +4,7 @@ using System; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis.LanguageServer; namespace Roslyn.LanguageServer.Protocol; @@ -17,7 +18,15 @@ internal sealed class WorkspaceFolder [JsonPropertyName("uri")] [JsonConverter(typeof(DocumentUriConverter))] [JsonRequired] - public DocumentUri Uri { get; init; } + public DocumentUri DocumentUri { get; init; } + + [Obsolete("Use DocumentUri instead. This property will be removed in a future version.")] + [JsonIgnore] + public Uri Uri + { + get => DocumentUri.GetRequiredParsedUri(); + init => DocumentUri = new DocumentUri(value); + } /// /// The name of the workspace folder used in the UI. diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs index 1483eda460d26..65eddc8a20079 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionResolveTests.cs @@ -299,7 +299,7 @@ class BCD DocumentChanges = new SumType[] { // Create file - new CreateFile() { Uri = newDocumentUri }, + new CreateFile() { DocumentUri = newDocumentUri }, // Add content to file new TextDocumentEdit() { @@ -426,7 +426,7 @@ class {|caret:BCD|} DocumentChanges = new SumType[] { // Create file - new CreateFile() { Uri = newDocumentUri }, + new CreateFile() { DocumentUri = newDocumentUri }, // Add content to file new TextDocumentEdit() { @@ -525,7 +525,7 @@ private static WorkspaceEdit GenerateWorkspaceEdit( { TextDocument = new OptionalVersionedTextDocumentIdentifier { - DocumentUri = locations.Single().Uri + DocumentUri = locations.Single().DocumentUri }, Edits = edits, } @@ -536,6 +536,6 @@ private static WorkspaceEdit GenerateRenameFileEdit(IList<(DocumentUri oldUri, D => new() { DocumentChanges = renameLocations.Select( - locations => new SumType(new RenameFile() { OldUri = locations.oldUri, NewUri = locations.newUri })).ToArray() + locations => new SumType(new RenameFile() { OldDocumentUri = locations.oldUri, NewDocumentUri = locations.newUri })).ToArray() }; } diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs index 438cc921acd6d..19e58be47f208 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/CodeActionsTests.cs @@ -114,7 +114,7 @@ void M() var caret = testLspServer.GetLocations("caret").Single(); var codeActionParams = new CodeActionParams { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Range = caret.Range, Context = new CodeActionContext { @@ -155,7 +155,7 @@ class ABC var caret = testLspServer.GetLocations("caret").Single(); var codeActionParams = new CodeActionParams { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Range = caret.Range, Context = new CodeActionContext { @@ -195,7 +195,7 @@ private void XYZ() var caret = testLspServer.GetLocations("caret").Single(); var codeActionParams = new CodeActionParams { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Range = caret.Range, Context = new CodeActionContext { @@ -238,7 +238,7 @@ class ABC var caret = testLspServer.GetLocations("caret").Single(); var codeActionParams = new CodeActionParams { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Range = caret.Range, Context = new CodeActionContext { @@ -286,7 +286,7 @@ private void XYZ() var caret = testLspServer.GetLocations("caret").Single(); var codeActionParams = new CodeActionParams { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Range = caret.Range, Context = new CodeActionContext { @@ -327,7 +327,7 @@ private static async Task RunGetCodeActionResolveAsync( internal static CodeActionParams CreateCodeActionParams(LSP.Location caret) => new CodeActionParams { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Range = caret.Range, Context = new CodeActionContext { diff --git a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs index 735cb91c82ac6..65b93acd76529 100644 --- a/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs @@ -45,7 +45,7 @@ class B var caretLocation = testLspServer.GetLocations("caret").Single(); var documentId = new LSP.TextDocumentIdentifier { - DocumentUri = caretLocation.Uri + DocumentUri = caretLocation.DocumentUri }; var titlePath = new[] { string.Format(FeaturesResources.Move_type_to_0, "B.cs") }; diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs index e4542b30769bb..87a59e7148e13 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionFeaturesTests.cs @@ -79,7 +79,7 @@ public int M() var caret = testLspServer.GetLocations("caret").Single(); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -319,7 +319,7 @@ public void M(string someText) await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, DefaultClientCapabilities); var caretLocation = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caretLocation.Uri); + await testLspServer.OpenDocumentAsync(caretLocation.DocumentUri); testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp, true); @@ -345,7 +345,7 @@ public void M(string someText) Assert.True(!someTextItem.Preselect && someTextItem.CommitCharacters == null); } - await testLspServer.InsertTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "s")); + await testLspServer.InsertTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "s")); completionParams = CreateCompletionParams( GetLocationPlusOne(caretLocation), @@ -446,7 +446,7 @@ public async Task TestUsingServerDefaultCommitCharacters(bool mutatingLspWorkspa var caret = testLspServer.GetLocations("caret").Single(); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -638,7 +638,7 @@ public async Task EditRangeShouldEndAtCursorPosition(bool mutatingLspWorkspace) var caret = testLspServer.GetLocations("caret").Single(); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -741,7 +741,7 @@ public Foo(List myList) var caret = testLspServer.GetLocations("caret").Single(); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -771,11 +771,11 @@ public async Task TestSoftSelectionWhenFilterTextIsEmptyForPreselectItemAsync(bo mockService.ItemCounts = (10, 10); var caret = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caret.Uri); + await testLspServer.OpenDocumentAsync(caret.DocumentUri); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -792,7 +792,7 @@ public async Task TestSoftSelectionWhenFilterTextIsEmptyForPreselectItemAsync(bo foreach (var item in results.Items) Assert.Null(item.CommitCharacters); - await testLspServer.InsertTextAsync(caret.Uri, (caret.Range.End.Line, caret.Range.End.Character, "i")); + await testLspServer.InsertTextAsync(caret.DocumentUri, (caret.Range.End.Line, caret.Range.End.Character, "i")); completionParams = CreateCompletionParams( GetLocationPlusOne(caret), @@ -825,7 +825,7 @@ public void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, DefaultClientCapabilities); var caretLocation = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caretLocation.Uri); + await testLspServer.OpenDocumentAsync(caretLocation.DocumentUri); testLspServer.TestWorkspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.TriggerInArgumentLists, LanguageNames.CSharp, true); @@ -844,7 +844,7 @@ public void M() Assert.Equal("_someDiscard", actualItem.Label); Assert.Null(actualItem.CommitCharacters); - await testLspServer.InsertTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "s")); + await testLspServer.InsertTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "s")); completionParams = CreateCompletionParams( GetLocationPlusOne(caretLocation), @@ -941,7 +941,7 @@ public async Task TestHandleExceptionFromGetCompletionChange(bool mutatingLspWor var caret = testLspServer.GetLocations("caret").Single(); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -1010,7 +1010,7 @@ public class MyClass : BaseClass var caret = testLspServer.GetLocations("caret").Single(); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -1060,11 +1060,11 @@ public int M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, DefaultClientCapabilities); var caret = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caret.Uri); + await testLspServer.OpenDocumentAsync(caret.DocumentUri); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { @@ -1084,7 +1084,7 @@ public int M() Assert.Equal(listMaxSize, results.Items.Length); Assert.False(results.Items.Any(i => i.Label == "if")); - await testLspServer.InsertTextAsync(caret.Uri, (caret.Range.End.Line, caret.Range.End.Character, "f")); + await testLspServer.InsertTextAsync(caret.DocumentUri, (caret.Range.End.Line, caret.Range.End.Character, "f")); completionParams = CreateCompletionParams( GetLocationPlusOne(caret), diff --git a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs index c90294ad4ddbc..6a1b74784b9d8 100644 --- a/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Completion/CompletionTests.cs @@ -927,7 +927,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, s_vsCompletionCapabilities); var caretLocation = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caretLocation.Uri); + await testLspServer.OpenDocumentAsync(caretLocation.DocumentUri); var completionParams = CreateCompletionParams( caretLocation, @@ -940,7 +940,7 @@ void M() Assert.True(results.IsIncomplete); Assert.Equal("T", results.Items.First().Label); - await testLspServer.InsertTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "a")); + await testLspServer.InsertTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "a")); completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), @@ -993,7 +993,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, s_vsCompletionCapabilities); var caretLocation = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caretLocation.Uri); + await testLspServer.OpenDocumentAsync(caretLocation.DocumentUri); var completionParams = CreateCompletionParams( caretLocation, @@ -1006,7 +1006,7 @@ void M() Assert.True(results.IsIncomplete); Assert.Equal("T", results.Items.First().Label); - await testLspServer.InsertTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "C")); + await testLspServer.InsertTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "C")); completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), @@ -1059,7 +1059,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, s_vsCompletionCapabilities); var caretLocation = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caretLocation.Uri); + await testLspServer.OpenDocumentAsync(caretLocation.DocumentUri); // Insert 'T' to make 'T' and trigger completion. var completionParams = CreateCompletionParams( @@ -1073,7 +1073,7 @@ void M() Assert.Equal("T", results.Items.First().Label); // Insert 'ask' to make 'Task' and trigger completion. - await testLspServer.InsertTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "ask")); + await testLspServer.InsertTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "ask")); completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), invokeKind: LSP.VSInternalCompletionInvokeKind.Typing, @@ -1085,7 +1085,7 @@ void M() Assert.Equal("Task", results.Items.First().Label); // Delete 'ask' to make 'T' and trigger completion on deletion. - await testLspServer.DeleteTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, caretLocation.Range.End.Line, caretLocation.Range.End.Character + 3)); + await testLspServer.DeleteTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, caretLocation.Range.End.Line, caretLocation.Range.End.Character + 3)); completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), invokeKind: LSP.VSInternalCompletionInvokeKind.Deletion, @@ -1098,7 +1098,7 @@ void M() Assert.Equal("T", results.Items.First().Label); // Insert 'i' to make 'Ti' and trigger completion. - await testLspServer.InsertTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "i")); + await testLspServer.InsertTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "i")); completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), invokeKind: LSP.VSInternalCompletionInvokeKind.Typing, @@ -1154,7 +1154,7 @@ void M2() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, s_vsCompletionCapabilities); var firstCaret = testLspServer.GetLocations("firstCaret").Single(); - await testLspServer.OpenDocumentAsync(firstCaret.Uri); + await testLspServer.OpenDocumentAsync(firstCaret.DocumentUri); // Make a completion request that returns an incomplete list. var completionParams = CreateCompletionParams( @@ -1277,7 +1277,7 @@ void M2() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, s_vsCompletionCapabilities); var firstCaretLocation = testLspServer.GetLocations("firstCaret").Single(); - await testLspServer.OpenDocumentAsync(firstCaretLocation.Uri); + await testLspServer.OpenDocumentAsync(firstCaretLocation.DocumentUri); // Create request to on insertion of 'T' var completionParams = CreateCompletionParams( @@ -1293,7 +1293,7 @@ void M2() // Insert 'S' at the second caret var secondCaretLocation = testLspServer.GetLocations("secondCaret").Single(); - await testLspServer.InsertTextAsync(secondCaretLocation.Uri, (secondCaretLocation.Range.End.Line, secondCaretLocation.Range.End.Character, "S")); + await testLspServer.InsertTextAsync(secondCaretLocation.DocumentUri, (secondCaretLocation.Range.End.Line, secondCaretLocation.Range.End.Character, "S")); // Trigger completion on 'S' var triggerLocation = GetLocationPlusOne(secondCaretLocation); @@ -1308,7 +1308,7 @@ void M2() Assert.Equal("Saaa", results.Items.First().Label); // Now type 'a' in M1 after 'T' - await testLspServer.InsertTextAsync(firstCaretLocation.Uri, (firstCaretLocation.Range.End.Line, firstCaretLocation.Range.End.Character, "a")); + await testLspServer.InsertTextAsync(firstCaretLocation.DocumentUri, (firstCaretLocation.Range.End.Line, firstCaretLocation.Range.End.Character, "a")); // Trigger completion on 'a' (using incomplete as we previously returned incomplete completions from 'T'). triggerLocation = GetLocationPlusOne(firstCaretLocation); @@ -1393,7 +1393,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, s_vsCompletionCapabilities); var caretLocation = testLspServer.GetLocations("caret").Single(); - await testLspServer.OpenDocumentAsync(caretLocation.Uri); + await testLspServer.OpenDocumentAsync(caretLocation.DocumentUri); var completionParams = CreateCompletionParams( caretLocation, @@ -1406,7 +1406,7 @@ void M() Assert.True(results.IsIncomplete); Assert.Equal("T", results.Items.First().Label); - await testLspServer.InsertTextAsync(caretLocation.Uri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "z")); + await testLspServer.InsertTextAsync(caretLocation.DocumentUri, (caretLocation.Range.End.Line, caretLocation.Range.End.Character, "z")); completionParams = CreateCompletionParams( testLspServer.GetLocations("caret").Single(), diff --git a/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs index 7073aa415c83c..935fa82bf47ee 100644 --- a/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/DataTips/DataTipRangeHandlerTests.cs @@ -21,7 +21,7 @@ public sealed class DataTipRangeHandlerTests(ITestOutputHelper testOutputHelper) LSP.VSInternalMethods.TextDocumentDataTipRangeName, new LSP.TextDocumentPositionParams() { - TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.DocumentUri }, Position = caret.Range.Start, }, CancellationToken.None); diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs index 897b8b8face60..1ffac96a03262 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs @@ -38,7 +38,7 @@ void M() var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); // Verify that as originally serialized, the URI had a file scheme. - Assert.True(results.Single().Uri.GetRequiredParsedUri().OriginalString.StartsWith("file")); + Assert.True(results.Single().DocumentUri.GetRequiredParsedUri().OriginalString.StartsWith("file")); AssertLocationsEqual(testLspServer.GetLocations("definition"), results); } @@ -88,7 +88,7 @@ void M() var position = new LSP.Position { Line = 5, Character = 18 }; var results = await RunGotoDefinitionAsync(testLspServer, new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), Range = new LSP.Range { Start = position, End = position } }); AssertLocationsEqual([TestSpanMapper.MappedFileLocation], results); @@ -300,7 +300,7 @@ class B var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); var result = Assert.Single(results); - Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.GetRequiredParsedUri().Scheme); + Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.DocumentUri.GetRequiredParsedUri().Scheme); } [Theory, CombinatorialData] @@ -319,7 +319,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var results = await RunGotoDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); - Assert.True(results.Single().Uri.GetRequiredParsedUri().OriginalString.EndsWith("String.cs")); + Assert.True(results.Single().DocumentUri.GetRequiredParsedUri().OriginalString.EndsWith("String.cs")); } private static async Task RunGotoDefinitionAsync(TestLspServer testLspServer, LSP.Location caret) diff --git a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs index c9f6829911c59..61a6bb0462c18 100644 --- a/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Definitions/GoToTypeDefinitionTests.cs @@ -217,7 +217,7 @@ class B var results = await RunGotoTypeDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); var result = Assert.Single(results); - Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.Uri.GetRequiredParsedUri().Scheme); + Assert.Equal(SourceGeneratedDocumentUri.Scheme, result.DocumentUri.GetRequiredParsedUri().Scheme); } [Theory, CombinatorialData] @@ -242,9 +242,9 @@ void Rethrow(NotImplementedException exception) var results = await RunGotoTypeDefinitionAsync(testLspServer, testLspServer.GetLocations("caret").Single()); // Open the metadata file and verify it gets added to the metadata workspace. - await testLspServer.OpenDocumentAsync(results.Single().Uri, text: string.Empty).ConfigureAwait(false); + await testLspServer.OpenDocumentAsync(results.Single().DocumentUri, text: string.Empty).ConfigureAwait(false); - Assert.Equal(WorkspaceKind.MetadataAsSource, (await GetWorkspaceForDocument(testLspServer, results.Single().Uri)).Kind); + Assert.Equal(WorkspaceKind.MetadataAsSource, (await GetWorkspaceForDocument(testLspServer, results.Single().DocumentUri)).Kind); } [Theory, CombinatorialData] diff --git a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs index 88c8cd72d0697..aab9adbec58e5 100644 --- a/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Diagnostics/PullDiagnosticTests.cs @@ -688,7 +688,7 @@ public partial class C if (mutatingLspWorkspace) { // In the mutating workspace, we just need to update the LSP text (which will flow into the workspace). - await testLspServer.ReplaceTextAsync(textLocation.Uri, (textEdit.Range, textEdit.NewText)); + await testLspServer.ReplaceTextAsync(textLocation.DocumentUri, (textEdit.Range, textEdit.NewText)); await WaitForWorkspaceOperationsAsync(testLspServer.TestWorkspace); } else @@ -697,7 +697,7 @@ public partial class C var workspaceText = await document.GetTextAsync(CancellationToken.None); var textChange = ProtocolConversions.TextEditToTextChange(textEdit, workspaceText); await testLspServer.TestWorkspace.ChangeDocumentAsync(document.Id, workspaceText.WithChanges(textChange)); - await testLspServer.ReplaceTextAsync(textLocation.Uri, (textEdit.Range, textEdit.NewText)); + await testLspServer.ReplaceTextAsync(textLocation.DocumentUri, (textEdit.Range, textEdit.NewText)); } await testLspServer.WaitForSourceGeneratorsAsync(); diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs index ef7c4122c57bb..5084d841dc6ac 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.LinkedDocuments.cs @@ -31,19 +31,19 @@ public async Task LinkedDocuments_AllTracked(bool mutatingLspWorkspace) await using var testLspServer = await CreateXmlTestLspServerAsync(workspaceXml, mutatingLspWorkspace); var caretLocation = testLspServer.GetLocations("caret").Single(); - await DidOpen(testLspServer, caretLocation.Uri); + await DidOpen(testLspServer, caretLocation.DocumentUri); var trackedDocuments = testLspServer.GetTrackedTexts(); Assert.Equal(1, trackedDocuments.Length); - var solution = await GetLSPSolutionAsync(testLspServer, caretLocation.Uri).ConfigureAwait(false); + var solution = await GetLSPSolutionAsync(testLspServer, caretLocation.DocumentUri).ConfigureAwait(false); foreach (var document in solution.Projects.First().Documents) { Assert.Equal(documentText, document.GetTextSynchronously(CancellationToken.None).ToString()); } - await DidClose(testLspServer, caretLocation.Uri); + await DidClose(testLspServer, caretLocation.DocumentUri); Assert.Empty(testLspServer.GetTrackedTexts()); } @@ -81,20 +81,20 @@ void M() } }"; - await DidOpen(testLspServer, caretLocation.Uri); + await DidOpen(testLspServer, caretLocation.DocumentUri); Assert.Equal(1, testLspServer.GetTrackedTexts().Length); - await DidChange(testLspServer, caretLocation.Uri, (4, 8, "// hi there")); + await DidChange(testLspServer, caretLocation.DocumentUri, (4, 8, "// hi there")); - var solution = await GetLSPSolutionAsync(testLspServer, caretLocation.Uri).ConfigureAwait(false); + var solution = await GetLSPSolutionAsync(testLspServer, caretLocation.DocumentUri).ConfigureAwait(false); foreach (var document in solution.Projects.First().Documents) { Assert.Equal(updatedText, document.GetTextSynchronously(CancellationToken.None).ToString()); } - await DidClose(testLspServer, caretLocation.Uri); + await DidClose(testLspServer, caretLocation.DocumentUri); Assert.Empty(testLspServer.GetTrackedTexts()); } diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs index fe3551bb98d29..23dc511af4f2c 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.WithFindAllReferences.cs @@ -35,7 +35,7 @@ void M2() { Assert.Empty(testLspServer.GetTrackedTexts()); - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); var originalDocument = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(); @@ -45,7 +45,7 @@ void M2() Assert.Equal("A", findResults[0].ContainingType); // Declare a local inside A.M() - await DidChange(testLspServer, locationTyped.Uri, (5, 0, "var i = someInt + 1;\r\n")); + await DidChange(testLspServer, locationTyped.DocumentUri, (5, 0, "var i = someInt + 1;\r\n")); findResults = await FindAllReferencesHandlerTests.RunFindAllReferencesAsync(testLspServer, locationTyped); Assert.Equal(2, findResults.Length); @@ -54,7 +54,7 @@ void M2() Assert.Equal("M", findResults[1].ContainingMember); // Declare a field in B - await DidChange(testLspServer, locationTyped.Uri, (10, 0, "int someInt = A.someInt + 1;\r\n")); + await DidChange(testLspServer, locationTyped.DocumentUri, (10, 0, "int someInt = A.someInt + 1;\r\n")); findResults = await FindAllReferencesHandlerTests.RunFindAllReferencesAsync(testLspServer, locationTyped); Assert.Equal(3, findResults.Length); @@ -64,7 +64,7 @@ void M2() Assert.Equal("M", findResults[1].ContainingMember); // Declare a local inside B.M2() - await DidChange(testLspServer, locationTyped.Uri, (13, 0, "var j = someInt + A.someInt;\r\n")); + await DidChange(testLspServer, locationTyped.DocumentUri, (13, 0, "var j = someInt + A.someInt;\r\n")); findResults = await FindAllReferencesHandlerTests.RunFindAllReferencesAsync(testLspServer, locationTyped); Assert.Equal(4, findResults.Length); @@ -80,7 +80,7 @@ void M2() // state will have been updated by back channels (text buffer sync, file changed on disk, etc.) This // is validating that the above didn't succeed by any means except the FAR handler being passed the // updated document, so if we regress and get lucky, we still know about it. - await DidClose(testLspServer, locationTyped.Uri); + await DidClose(testLspServer, locationTyped.DocumentUri); findResults = await FindAllReferencesHandlerTests.RunFindAllReferencesAsync(testLspServer, locationTyped); Assert.Single(findResults); diff --git a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs index d2539b368d187..d9a4e4e11c902 100644 --- a/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/DocumentChanges/DocumentChangesTests.cs @@ -45,19 +45,19 @@ void M() { Assert.Empty(testLspServer.GetTrackedTexts()); - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); Assert.Single(testLspServer.GetTrackedTexts()); var document = testLspServer.GetTrackedTexts().Single(); Assert.Equal(documentText, document.ToString()); - await DidChange(testLspServer, locationTyped.Uri, (4, 8, "// hi there")); + await DidChange(testLspServer, locationTyped.DocumentUri, (4, 8, "// hi there")); document = testLspServer.GetTrackedTexts().Single(); Assert.Equal(expected, document.ToString()); - await DidClose(testLspServer, locationTyped.Uri); + await DidClose(testLspServer, locationTyped.DocumentUri); Assert.Empty(testLspServer.GetTrackedTexts()); } @@ -78,7 +78,7 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); var document = testLspServer.GetTrackedTexts().FirstOrDefault(); @@ -102,9 +102,9 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await Assert.ThrowsAnyAsync(() => DidOpen(testLspServer, locationTyped.Uri)); + await Assert.ThrowsAnyAsync(() => DidOpen(testLspServer, locationTyped.DocumentUri)); await testLspServer.AssertServerShuttingDownAsync(); } } @@ -124,7 +124,7 @@ void M() await using (testLspServer) { - await Assert.ThrowsAnyAsync(() => DidClose(testLspServer, locationTyped.Uri)); + await Assert.ThrowsAnyAsync(() => DidClose(testLspServer, locationTyped.DocumentUri)); await testLspServer.AssertServerShuttingDownAsync(); } } @@ -144,7 +144,7 @@ void M() await using (testLspServer) { - await Assert.ThrowsAnyAsync(() => DidChange(testLspServer, locationTyped.Uri, (0, 0, "goo"))); + await Assert.ThrowsAnyAsync(() => DidChange(testLspServer, locationTyped.DocumentUri, (0, 0, "goo"))); await testLspServer.AssertServerShuttingDownAsync(); } } @@ -165,9 +165,9 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await DidClose(testLspServer, locationTyped.Uri); + await DidClose(testLspServer, locationTyped.DocumentUri); Assert.Empty(testLspServer.GetTrackedTexts()); } @@ -197,9 +197,9 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await DidChange(testLspServer, locationTyped.Uri, (4, 8, "// hi there")); + await DidChange(testLspServer, locationTyped.DocumentUri, (4, 8, "// hi there")); var document = testLspServer.GetTrackedTexts().FirstOrDefault(); @@ -232,11 +232,11 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await DidChange(testLspServer, locationTyped.Uri, (4, 8, "// hi there")); + await DidChange(testLspServer, locationTyped.DocumentUri, (4, 8, "// hi there")); - var documentTextFromWorkspace = (await testLspServer.GetDocumentTextAsync(locationTyped.Uri)).ToString(); + var documentTextFromWorkspace = (await testLspServer.GetDocumentTextAsync(locationTyped.DocumentUri)).ToString(); Assert.NotNull(documentTextFromWorkspace); Assert.Equal(documentText, documentTextFromWorkspace); @@ -275,9 +275,9 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await DidChange(testLspServer, locationTyped.Uri, (4, 8, "// hi there"), (5, 0, " // this builds on that\r\n")); + await DidChange(testLspServer, locationTyped.DocumentUri, (4, 8, "// hi there"), (5, 0, " // this builds on that\r\n")); var document = testLspServer.GetTrackedTexts().FirstOrDefault(); @@ -314,9 +314,9 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await DidChange(testLspServer, locationTyped.Uri, (4, 8, "// there"), (4, 11, "hi ")); + await DidChange(testLspServer, locationTyped.DocumentUri, (4, 8, "// there"), (4, 11, "hi ")); var document = testLspServer.GetTrackedTexts().FirstOrDefault(); @@ -354,9 +354,9 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await DidChange(testLspServer, locationTyped.Uri, (5, 0, " // this builds on that\r\n"), (4, 8, "// hi there")); + await DidChange(testLspServer, locationTyped.DocumentUri, (5, 0, " // this builds on that\r\n"), (4, 8, "// hi there")); var document = testLspServer.GetTrackedTexts().FirstOrDefault(); @@ -437,10 +437,10 @@ void M() await using (testLspServer) { - await DidOpen(testLspServer, locationTyped.Uri); + await DidOpen(testLspServer, locationTyped.DocumentUri); - await DidChange(testLspServer, locationTyped.Uri, (4, 8, "// hi there")); - await DidChange(testLspServer, locationTyped.Uri, (5, 0, " // this builds on that\r\n")); + await DidChange(testLspServer, locationTyped.DocumentUri, (4, 8, "// hi there")); + await DidChange(testLspServer, locationTyped.DocumentUri, (5, 0, " // this builds on that\r\n")); var document = testLspServer.GetTrackedTexts().FirstOrDefault(); @@ -453,7 +453,7 @@ void M() { var testLspServer = await CreateTestLspServerAsync(source, mutatingLspWorkspace, CapabilitiesWithVSExtensions); var locationTyped = testLspServer.GetLocations("type").Single(); - var documentText = await testLspServer.GetDocumentTextAsync(locationTyped.Uri); + var documentText = await testLspServer.GetDocumentTextAsync(locationTyped.DocumentUri); return (testLspServer, locationTyped, documentText.ToString()); } diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs index 99c624177e239..ff924df053087 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentOnTypeTests.cs @@ -117,7 +117,7 @@ private static async Task AssertFormatDocumentOnTypeAsync( bool insertSpaces = true, int tabSize = 4) { - var documentText = await testLspServer.GetDocumentTextAsync(locationTyped.Uri); + var documentText = await testLspServer.GetDocumentTextAsync(locationTyped.DocumentUri); var results = await testLspServer.ExecuteRequestAsync( LSP.Methods.TextDocumentOnTypeFormattingName, CreateDocumentOnTypeFormattingParams(characterTyped, locationTyped, insertSpaces, tabSize), @@ -135,7 +135,7 @@ private static LSP.DocumentOnTypeFormattingParams CreateDocumentOnTypeFormatting { Position = locationTyped.Range.Start, Character = characterTyped, - TextDocument = CreateTextDocumentIdentifier(locationTyped.Uri), + TextDocument = CreateTextDocumentIdentifier(locationTyped.DocumentUri), Options = new LSP.FormattingOptions() { InsertSpaces = insertSpaces, diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs index a784ab664a026..ea8962004af3d 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentRangeTests.cs @@ -41,7 +41,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var rangeToFormat = testLspServer.GetLocations("format").Single(); - var documentText = await testLspServer.GetDocumentTextAsync(rangeToFormat.Uri); + var documentText = await testLspServer.GetDocumentTextAsync(rangeToFormat.DocumentUri); var results = await RunFormatDocumentRangeAsync(testLspServer, rangeToFormat); var actualText = ApplyTextEdits(results, documentText); @@ -69,7 +69,7 @@ void M() }"; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var rangeToFormat = testLspServer.GetLocations("format").Single(); - var documentText = await testLspServer.GetDocumentTextAsync(rangeToFormat.Uri); + var documentText = await testLspServer.GetDocumentTextAsync(rangeToFormat.DocumentUri); var results = await RunFormatDocumentRangeAsync(testLspServer, rangeToFormat, insertSpaces: false, tabSize: 4); var actualText = ApplyTextEdits(results, documentText); @@ -95,7 +95,7 @@ private static LSP.DocumentRangeFormattingParams CreateDocumentRangeFormattingPa => new LSP.DocumentRangeFormattingParams() { Range = location.Range, - TextDocument = CreateTextDocumentIdentifier(location.Uri), + TextDocument = CreateTextDocumentIdentifier(location.DocumentUri), Options = new LSP.FormattingOptions() { InsertSpaces = insertSpaces, diff --git a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs index 058318f720310..c2d126efc857e 100644 --- a/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Formatting/FormatDocumentTests.cs @@ -45,7 +45,7 @@ void M() } """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected); } @@ -80,7 +80,7 @@ class A }; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, options); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected); } @@ -115,7 +115,7 @@ class A }; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, options); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected); } @@ -150,7 +150,7 @@ class A }; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, options); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected); } @@ -185,7 +185,7 @@ class A }; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, options); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected); } @@ -228,7 +228,7 @@ void M() }; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, options); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected); } @@ -255,7 +255,7 @@ class A """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected); } @@ -283,7 +283,7 @@ void M() } """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected, insertSpaces: false, tabSize: 4); } @@ -311,7 +311,7 @@ void M() } """; await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); - var documentURI = testLspServer.GetLocations("caret").Single().Uri; + var documentURI = testLspServer.GetLocations("caret").Single().DocumentUri; await AssertFormatDocumentAsync(testLspServer, documentURI, expected, insertSpaces: true, tabSize: 2); } diff --git a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs index 7df63885c7a16..1012538901672 100644 --- a/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/InlineCompletions/InlineCompletionsTests.cs @@ -270,7 +270,7 @@ private async Task VerifyMarkupAndExpected(string markup, string expected, bool await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var locationTyped = testLspServer.GetLocations("tab").Single(); - var document = testLspServer.GetDocumentAsync(locationTyped.Uri); + var document = testLspServer.GetDocumentAsync(locationTyped.DocumentUri); var result = await GetInlineCompletionsAsync(testLspServer, locationTyped, options ?? new LSP.FormattingOptions { InsertSpaces = true, TabSize = 4 }); @@ -296,7 +296,7 @@ private async Task VerifyMarkupAndExpected(string markup, string expected, bool TriggerKind = LSP.VSInternalInlineCompletionTriggerKind.Explicit }, Position = locationTyped.Range.Start, - TextDocument = CreateTextDocumentIdentifier(locationTyped.Uri), + TextDocument = CreateTextDocumentIdentifier(locationTyped.DocumentUri), Options = options }; diff --git a/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs b/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs index 9a0d2e826afe9..d6bcb287fa3be 100644 --- a/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/LanguageServerTargetTests.cs @@ -93,7 +93,7 @@ public async Task LanguageServerSucceedsAfterInitializedCalled(bool mutatingLspW TextDocument = new TextDocumentItem { Text = "sometext", - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\location\file.json"), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\location\file.json"), } }; @@ -111,7 +111,7 @@ public async Task LanguageServerRejectsRequestsBeforeInitialized(bool mutatingLs TextDocument = new TextDocumentItem { Text = "sometext", - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\location\file.json"), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\location\file.json"), } }; var ex = await Assert.ThrowsAsync(async () => await server.ExecuteRequestAsync(Methods.TextDocumentDidOpenName, didOpenParams, CancellationToken.None)); diff --git a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs index f865885282b6b..db39d420042c3 100644 --- a/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/MapCode/MapCodeTests.cs @@ -92,7 +92,7 @@ static void Main(string[] args) await using var testLspServer = await CreateTestLspServerAsync(code, mutatingLspWorkspace, CreateClientCapabilities(supportDocumentChanges)); var ranges = testLspServer.GetLocations("range").ToArray(); - var documentUri = ranges.Single().Uri; + var documentUri = ranges.Single().DocumentUri; var mapCodeParams = new LSP.VSInternalMapCodeParams() { Mappings = diff --git a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs index 0fb34dd1410fb..c7df1d9fa6554 100644 --- a/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Metadata/LspMetadataAsSourceWorkspaceTests.cs @@ -46,13 +46,13 @@ void M() AssertEx.NotNull(definition); // Open the metadata file and verify it gets added to the metadata workspace. - await testLspServer.OpenDocumentAsync(definition.Single().Uri, text: string.Empty).ConfigureAwait(false); + await testLspServer.OpenDocumentAsync(definition.Single().DocumentUri, text: string.Empty).ConfigureAwait(false); - Assert.Equal(WorkspaceKind.MetadataAsSource, (await GetWorkspaceForDocument(testLspServer, definition.Single().Uri)).Kind); + Assert.Equal(WorkspaceKind.MetadataAsSource, (await GetWorkspaceForDocument(testLspServer, definition.Single().DocumentUri)).Kind); AssertMiscFileWorkspaceEmpty(testLspServer); // Close the metadata file and verify it gets removed from the metadata workspace. - await testLspServer.CloseDocumentAsync(definition.Single().Uri).ConfigureAwait(false); + await testLspServer.CloseDocumentAsync(definition.Single().DocumentUri).ConfigureAwait(false); AssertMetadataFileWorkspaceEmpty(testLspServer); } @@ -94,8 +94,8 @@ public static void WriteLine(string value) {} // Open the metadata file and verify it gets added to the metadata workspace. // We don't have the real metadata source, so just populate it with our fake metadata source. - await testLspServer.OpenDocumentAsync(definition.Single().Uri, text: metadataSource).ConfigureAwait(false); - var workspaceForDocument = await GetWorkspaceForDocument(testLspServer, definition.Single().Uri); + await testLspServer.OpenDocumentAsync(definition.Single().DocumentUri, text: metadataSource).ConfigureAwait(false); + var workspaceForDocument = await GetWorkspaceForDocument(testLspServer, definition.Single().DocumentUri); Assert.Equal(WorkspaceKind.MetadataAsSource, workspaceForDocument.Kind); AssertMiscFileWorkspaceEmpty(testLspServer); @@ -105,7 +105,7 @@ public static void WriteLine(string value) {} var locationOfStringKeyword = new LSP.Location { - Uri = definition.Single().Uri, + DocumentUri = definition.Single().DocumentUri, Range = new LSP.Range { Start = new LSP.Position { Line = 4, Character = 40 }, @@ -118,7 +118,7 @@ public static void WriteLine(string value) {} Assert.NotNull(definitionFromMetadata); Assert.NotEmpty(definitionFromMetadata); - Assert.Contains("String.cs", definitionFromMetadata.Single().Uri.UriString); + Assert.Contains("String.cs", definitionFromMetadata.Single().DocumentUri.UriString); } private static async Task GetWorkspaceForDocument(TestLspServer testLspServer, DocumentUri fileUri) diff --git a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index 7c7e2d0442952..02414498fadf7 100644 --- a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -74,7 +74,7 @@ void M() // Make a text change to the loose file and verify requests appropriately reflect the changes. await testLspServer.InsertTextAsync(looseFileUri, (0, 0, source)).ConfigureAwait(false); - var caret = new LSP.Location { Range = new() { Start = new(0, 6), End = new(0, 7) }, Uri = looseFileUri }; + var caret = new LSP.Location { Range = new() { Start = new(0, 6), End = new(0, 7) }, DocumentUri = looseFileUri }; var hover = await RunGetHoverAsync(testLspServer, caret).ConfigureAwait(false); Assert.Contains("class A", hover.Contents.Fourth.Value); await AssertFileInMiscWorkspaceAsync(testLspServer, looseFileUri).ConfigureAwait(false); @@ -268,7 +268,7 @@ void M() var result = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentDefinitionName, CreateTextDocumentPositionParams(new LSP.Location { - Uri = looseFileUri, + DocumentUri = looseFileUri, Range = new LSP.Range { Start = new(4, 8) diff --git a/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs b/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs index e8982d36fa6f6..f46df97f98259 100644 --- a/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/OnAutoInsert/OnAutoInsertTests.cs @@ -403,7 +403,7 @@ private async Task VerifyMarkupAndExpected( await using var testLspServer = await testLspServerTask; var locationTyped = testLspServer.GetLocations("type").Single(); - var document = await testLspServer.GetDocumentAsync(locationTyped.Uri); + var document = await testLspServer.GetDocumentAsync(locationTyped.DocumentUri); var documentText = await document.GetTextAsync(); var result = await RunOnAutoInsertAsync(testLspServer, characterTyped, locationTyped, insertSpaces, tabSize); @@ -418,7 +418,7 @@ private async Task VerifyNoResult(string characterTyped, string markup, bool mut { await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace); var locationTyped = testLspServer.GetLocations("type").Single(); - var documentText = await (await testLspServer.GetDocumentAsync(locationTyped.Uri)).GetTextAsync(); + var documentText = await (await testLspServer.GetDocumentAsync(locationTyped.DocumentUri)).GetTextAsync(); var result = await RunOnAutoInsertAsync(testLspServer, characterTyped, locationTyped, insertSpaces, tabSize); @@ -445,7 +445,7 @@ private static LSP.VSInternalDocumentOnAutoInsertParams CreateDocumentOnAutoInse { Position = locationTyped.Range.Start, Character = characterTyped, - TextDocument = CreateTextDocumentIdentifier(locationTyped.Uri), + TextDocument = CreateTextDocumentIdentifier(locationTyped.DocumentUri), Options = new LSP.FormattingOptions { InsertSpaces = insertSpaces, diff --git a/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs b/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs index 9b5ca9a2ebe52..541af789c375e 100644 --- a/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs @@ -196,7 +196,7 @@ public async Task NonMutatingRequestsOperateOnTheSameSolutionAfterMutation(bool Assert.Equal(expectedSolution, solution); // Open a document, to get a forked solution - await ExecuteDidOpen(testLspServer, testLspServer.GetLocations("caret").First().Uri); + await ExecuteDidOpen(testLspServer, testLspServer.GetLocations("caret").First().DocumentUri); // solution should be different because there has been a mutation solution = await GetLSPSolution(testLspServer, NonMutatingRequestHandler.MethodName); @@ -245,7 +245,7 @@ public async Task HandlerThatSkipsBuildingLSPSolutionGetsWorkspaceSolution(bool Assert.Null(solution); // Open a document, to create a change that LSP handlers wouldn normally see - await ExecuteDidOpen(testLspServer, testLspServer.GetLocations("caret").First().Uri); + await ExecuteDidOpen(testLspServer, testLspServer.GetLocations("caret").First().DocumentUri); // solution shouldn't have changed solution = await GetLSPSolution(testLspServer, NonLSPSolutionRequestHandler.MethodName); @@ -258,7 +258,7 @@ private static async Task ExecuteDidOpen(TestLspServer testLspServer, DocumentUr { TextDocument = new LSP.TextDocumentItem { - Uri = documentUri, + DocumentUri = documentUri, Text = "// hi there" } }; diff --git a/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs index 702d36d374289..56479be597e6e 100644 --- a/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ProjectContext/GetTextDocumentWithContextHandlerTests.cs @@ -31,7 +31,7 @@ public async Task SingleDocumentReturnsSingleContext(bool mutatingLspWorkspace) "; await using var testLspServer = await CreateXmlTestLspServerAsync(workspaceXml, mutatingLspWorkspace); - var documentUri = testLspServer.GetLocations("caret").Single().Uri; + var documentUri = testLspServer.GetLocations("caret").Single().DocumentUri; var result = await RunGetProjectContext(testLspServer, documentUri); Assert.NotNull(result); @@ -57,7 +57,7 @@ public async Task MultipleDocumentsReturnsMultipleContexts(bool mutatingLspWorks "; await using var testLspServer = await CreateXmlTestLspServerAsync(workspaceXml, mutatingLspWorkspace); - var documentUri = testLspServer.GetLocations("caret").Single().Uri; + var documentUri = testLspServer.GetLocations("caret").Single().DocumentUri; var result = await RunGetProjectContext(testLspServer, documentUri); Assert.NotNull(result); @@ -86,7 +86,7 @@ public async Task SwitchingContextsChangesDefaultContext(bool mutatingLspWorkspa var document = testLspServer.TestWorkspace.Documents.First(); await testLspServer.OpenDocumentInWorkspaceAsync(document.Id, openAllLinkedDocuments: true); - var documentUri = testLspServer.GetLocations("caret").Single().Uri; + var documentUri = testLspServer.GetLocations("caret").Single().DocumentUri; foreach (var project in testLspServer.GetCurrentSolution().Projects) { @@ -107,6 +107,6 @@ public async Task SwitchingContextsChangesDefaultContext(bool mutatingLspWorkspa private static LSP.VSGetProjectContextsParams CreateGetProjectContextParams(DocumentUri uri) => new LSP.VSGetProjectContextsParams() { - TextDocument = new LSP.TextDocumentItem { Uri = uri } + TextDocument = new LSP.TextDocumentItem { DocumentUri = uri } }; } \ No newline at end of file diff --git a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs index 5eb39df178ed9..5c3f6c389e87b 100644 --- a/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ProtocolConversionsTests.cs @@ -300,7 +300,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(source, mutatingLspWorkspace, new InitializationOptions { ServerKind = WellKnownLspServerKinds.CSharpVisualBasicLspServer }); var caret = testLspServer.GetLocations("caret").Single(); - var document = await GetTextDocumentAsync(testLspServer, caret.Uri); + var document = await GetTextDocumentAsync(testLspServer, caret.DocumentUri); Assert.NotNull(document); var projectContext = ProtocolConversions.ProjectToProjectContext(document.Project); diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs index 7e1a4efb1bbf5..4c1fc1b13264f 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindAllReferencesHandlerTests.cs @@ -202,7 +202,7 @@ void M() await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, CapabilitiesWithVSExtensions); var results = await RunFindAllReferencesAsync(testLspServer, testLspServer.GetLocations("caret").First()); - Assert.NotNull(results[0].Location!.Uri); + Assert.NotNull(results[0].Location!.DocumentUri); AssertHighlightCount(results, expectedDefinitionCount: 0, expectedWrittenReferenceCount: 0, expectedReferenceCount: 1); } @@ -303,7 +303,7 @@ class PREPROCESSING_SYMBOL private static LSP.ReferenceParams CreateReferenceParams(LSP.Location caret, IProgress progress) => new LSP.ReferenceParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.ReferenceContext(), PartialResultToken = progress diff --git a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs index 51112e3211b53..3409f41ed31ee 100644 --- a/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/References/FindImplementationsTests.cs @@ -90,7 +90,7 @@ void IA.M() var position = new LSP.Position { Line = 2, Character = 9 }; var results = await RunFindImplementationAsync(testLspServer, new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), Range = new LSP.Range { Start = position, End = position } }); AssertLocationsEqual([TestSpanMapper.MappedFileLocation], results); diff --git a/src/LanguageServer/ProtocolUnitTests/Rename/PrepareRenameTests.cs b/src/LanguageServer/ProtocolUnitTests/Rename/PrepareRenameTests.cs index a7dc51a2878a2..8c13aabe0c85a 100644 --- a/src/LanguageServer/ProtocolUnitTests/Rename/PrepareRenameTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Rename/PrepareRenameTests.cs @@ -88,7 +88,7 @@ private static LSP.PrepareRenameParams CreatePrepareRenameParams(LSP.Location lo => new LSP.PrepareRenameParams() { Position = location.Range.Start, - TextDocument = CreateTextDocumentIdentifier(location.Uri) + TextDocument = CreateTextDocumentIdentifier(location.DocumentUri) }; private static async Task RunPrepareRenameAsync(TestLspServer testLspServer, LSP.PrepareRenameParams prepareRenameParams) diff --git a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs index 65658b74ddbc0..8b91d83e8184e 100644 --- a/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Rename/RenameTests.cs @@ -170,7 +170,7 @@ void M2() var renameText = "RENAME"; var renameParams = CreateRenameParams(new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri($"C:\\{TestSpanMapper.GeneratedFileName}"), Range = new LSP.Range { Start = startPosition, End = endPosition } }, "RENAME"); @@ -178,7 +178,7 @@ void M2() // There are two rename locations, so we expect two mapped locations. var expectedMappedRanges = ImmutableArray.Create(TestSpanMapper.MappedFileLocation.Range, TestSpanMapper.MappedFileLocation.Range); - var expectedMappedDocument = TestSpanMapper.MappedFileLocation.Uri; + var expectedMappedDocument = TestSpanMapper.MappedFileLocation.DocumentUri; var documentEdit = results.DocumentChanges.Value.First.Single(); Assert.Equal(expectedMappedDocument, documentEdit.TextDocument.DocumentUri); @@ -191,7 +191,7 @@ private static LSP.RenameParams CreateRenameParams(LSP.Location location, string { NewName = newName, Position = location.Range.Start, - TextDocument = CreateTextDocumentIdentifier(location.Uri) + TextDocument = CreateTextDocumentIdentifier(location.DocumentUri) }; private static async Task RunRenameAsync(TestLspServer testLspServer, LSP.RenameParams renameParams) diff --git a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs index ed4fd0f53eb4f..93add1510ac89 100644 --- a/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SemanticTokens/AbstractSemanticTokensTests.cs @@ -54,20 +54,20 @@ private protected static IReadOnlyDictionary GetTokenTypeToIndex(Te private static LSP.SemanticTokensFullParams CreateSemanticTokensFullParams(LSP.Location caret) => new LSP.SemanticTokensFullParams { - TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri } + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.DocumentUri } }; private static LSP.SemanticTokensRangeParams CreateSemanticTokensRangeParams(LSP.Location caret, LSP.Range range) => new LSP.SemanticTokensRangeParams { - TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.DocumentUri }, Range = range }; private static SemanticTokensRangesParams CreateSemanticTokensRangesParams(LSP.Location caret, Range[] ranges) => new SemanticTokensRangesParams { - TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.DocumentUri }, Ranges = ranges }; diff --git a/src/LanguageServer/ProtocolUnitTests/SimplifyMethod/SimplifyMethodTests.cs b/src/LanguageServer/ProtocolUnitTests/SimplifyMethod/SimplifyMethodTests.cs index 73e4685f44198..2bcb3db2248ba 100644 --- a/src/LanguageServer/ProtocolUnitTests/SimplifyMethod/SimplifyMethodTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SimplifyMethod/SimplifyMethodTests.cs @@ -54,7 +54,7 @@ class A private static SimplifyMethodParams CreateSimplifyMethodParams(LSP.Location location, string newText) => new SimplifyMethodParams() { - TextDocument = CreateTextDocumentIdentifier(location.Uri), + TextDocument = CreateTextDocumentIdentifier(location.DocumentUri), TextEdit = new TextEdit() { Range = location.Range, NewText = newText }, }; } diff --git a/src/LanguageServer/ProtocolUnitTests/UriTests.cs b/src/LanguageServer/ProtocolUnitTests/UriTests.cs index 202a9ee678791..11be252279cdf 100644 --- a/src/LanguageServer/ProtocolUnitTests/UriTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/UriTests.cs @@ -179,7 +179,7 @@ public async Task TestFindsExistingDocumentWhenUriHasDifferentEncodingAsync(bool await testLspServer.ExecutePreSerializedRequestAsync(LSP.Methods.TextDocumentDidOpenName, jsonDocument); // Retrieve the URI from the json - this is the unencoded (and not JSON escaped) version of the URI. - var unencodedUri = JsonSerializer.Deserialize(jsonDocument, JsonSerializerOptions)!.TextDocument.Uri; + var unencodedUri = JsonSerializer.Deserialize(jsonDocument, JsonSerializerOptions)!.TextDocument.DocumentUri; // Access the document using the unencoded URI to make sure we find it in the C# misc files. var (workspace, _, lspDocument) = await testLspServer.GetManager().GetLspDocumentInfoAsync(new LSP.TextDocumentIdentifier { DocumentUri = unencodedUri }, CancellationToken.None).ConfigureAwait(false); diff --git a/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs b/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs index 39381b743b70f..47ab1d809610b 100644 --- a/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/ValidateBreakableRange/ValidateBreakableRangeTests.cs @@ -262,7 +262,7 @@ void M() LSP.VSInternalMethods.TextDocumentValidateBreakableRangeName, new LSP.VSInternalValidateBreakableRangeParams() { - TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.Uri }, + TextDocument = new LSP.TextDocumentIdentifier { DocumentUri = caret.DocumentUri }, Range = caret.Range }, CancellationToken.None); diff --git a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs index 71d677c3c6a72..fb298c5fbcc1e 100644 --- a/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Workspaces/SourceGeneratedDocumentTests.cs @@ -91,7 +91,7 @@ public async Task RequestOnSourceGeneratedDocument(bool mutatingLspWorkspace) var sourceGeneratedDocumentIdentity = sourceGeneratedDocuments.Single().Identity; var sourceGeneratorDocumentUri = SourceGeneratedDocumentUri.Create(sourceGeneratedDocumentIdentity); - var location = new LSP.Location { Uri = sourceGeneratorDocumentUri, Range = new LSP.Range { Start = new LSP.Position(0, 6), End = new LSP.Position(0, 6) } }; + var location = new LSP.Location { DocumentUri = sourceGeneratorDocumentUri, Range = new LSP.Range { Start = new LSP.Position(0, 6), End = new LSP.Position(0, 6) } }; var hover = await testLspServer.ExecuteRequestAsync(LSP.Methods.TextDocumentHoverName, CreateTextDocumentPositionParams(location), CancellationToken.None); diff --git a/src/Tools/IdeBenchmarks/Lsp/LspCompletionSerializationBenchmarks.cs b/src/Tools/IdeBenchmarks/Lsp/LspCompletionSerializationBenchmarks.cs index 05e984071c481..1ec6d144d8899 100644 --- a/src/Tools/IdeBenchmarks/Lsp/LspCompletionSerializationBenchmarks.cs +++ b/src/Tools/IdeBenchmarks/Lsp/LspCompletionSerializationBenchmarks.cs @@ -105,7 +105,7 @@ void M() var caret = testServer.GetLocations("caret").Single(); var completionParams = new LSP.CompletionParams() { - TextDocument = CreateTextDocumentIdentifier(caret.Uri), + TextDocument = CreateTextDocumentIdentifier(caret.DocumentUri), Position = caret.Range.Start, Context = new LSP.CompletionContext() { diff --git a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs index d36c26cc757dc..279c21cd13a1a 100644 --- a/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs +++ b/src/VisualStudio/LiveShare/Impl/Client/RemoteLanguageServiceWorkspace.cs @@ -287,7 +287,7 @@ public async Task RefreshAllFilesAsync() public async Task GetDocumentSpanFromLocationAsync(LSP.Location location, CancellationToken cancellationToken) { - var document = GetOrAddDocument(location.Uri.GetRequiredParsedUri().LocalPath); + var document = GetOrAddDocument(location.DocumentUri.GetRequiredParsedUri().LocalPath); if (document == null) { return null; diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs index bdb2f1ccc8413..2b2b38d725e74 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/Definitions/GoToDefinitionHandler.cs @@ -132,7 +132,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe var sourceText = SourceText.From(fileStream); return new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath), Range = ProtocolConversions.TextSpanToRange(sourceDefinition.Span.Value, sourceText) }; } @@ -144,7 +144,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe return new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(sourceDefinition.FilePath), Range = new LSP.Range() { Start = position, End = position } }; } @@ -182,7 +182,7 @@ public GoToDefinitionHandler(IMetadataAsSourceFileService metadataAsSourceFileSe var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span; locations.Add(new LSP.Location { - Uri = ProtocolConversions.CreateAbsoluteDocumentUri(declarationFile.FilePath), + DocumentUri = ProtocolConversions.CreateAbsoluteDocumentUri(declarationFile.FilePath), Range = ProtocolConversions.LinePositionToRange(linePosSpan), }); } From 89c8c549789554e816469178e6c02432dbdfcdd9 Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 14 Apr 2025 18:17:00 -0700 Subject: [PATCH 8/9] Fix issues from merge --- src/Features/Lsif/Generator/Generator.cs | 4 ++-- src/Features/Lsif/Generator/Graph/LsifDocument.cs | 4 ++-- src/Features/Lsif/Generator/Graph/LsifProject.cs | 4 ++-- src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb | 6 +++--- src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb | 6 +++--- .../Protocol/Extensions/ProtocolConversions.cs | 1 + .../ProtocolUnitTests/SpellCheck/SpellCheckTests.cs | 6 +++--- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Features/Lsif/Generator/Generator.cs b/src/Features/Lsif/Generator/Generator.cs index cd870f57f3498..1c714a8e9fc13 100644 --- a/src/Features/Lsif/Generator/Generator.cs +++ b/src/Features/Lsif/Generator/Generator.cs @@ -102,7 +102,7 @@ public async Task GenerateForProjectAsync( var projectVertex = new Graph.LsifProject( kind: GetLanguageKind(compilation.Language), - ProtocolConversions.CreateAbsoluteDocumentUri(projectPath), + ProtocolConversions.CreateAbsoluteUri(projectPath), Path.GetFileNameWithoutExtension(projectPath), _idFactory); @@ -212,7 +212,7 @@ public async Task GenerateForProjectAsync( var contentBase64Encoded = await GetBase64EncodedContentAsync(document, cancellationToken); - var documentVertex = new Graph.LsifDocument(document.GetURI(), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); + var documentVertex = new Graph.LsifDocument(document.GetURI().GetRequiredParsedUri(), GetLanguageKind(semanticModel.Language), contentBase64Encoded, idFactory); lsifJsonWriter.Write(documentVertex); lsifJsonWriter.Write(new Event(Event.EventKind.Begin, documentVertex.GetId(), idFactory)); diff --git a/src/Features/Lsif/Generator/Graph/LsifDocument.cs b/src/Features/Lsif/Generator/Graph/LsifDocument.cs index a9d2fec1b9b25..e500e3b6172e3 100644 --- a/src/Features/Lsif/Generator/Graph/LsifDocument.cs +++ b/src/Features/Lsif/Generator/Graph/LsifDocument.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Graph; /// internal sealed class LsifDocument : Vertex { - public DocumentUri Uri { get; } + public Uri Uri { get; } public string LanguageId { get; } /// @@ -23,7 +23,7 @@ internal sealed class LsifDocument : Vertex /// public string? Contents { get; } - public LsifDocument(DocumentUri uri, string languageId, string? contents, IdFactory idFactory) + public LsifDocument(Uri uri, string languageId, string? contents, IdFactory idFactory) : base(label: "document", idFactory) { this.Uri = uri; diff --git a/src/Features/Lsif/Generator/Graph/LsifProject.cs b/src/Features/Lsif/Generator/Graph/LsifProject.cs index f3b8dade8c5e3..69de2a285604d 100644 --- a/src/Features/Lsif/Generator/Graph/LsifProject.cs +++ b/src/Features/Lsif/Generator/Graph/LsifProject.cs @@ -13,10 +13,10 @@ namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.Graph; internal sealed class LsifProject : Vertex { public string Kind { get; } - public DocumentUri? Resource { get; } + public Uri? Resource { get; } public string Name { get; } - public LsifProject(string kind, DocumentUri? resource, string name, IdFactory idFactory) + public LsifProject(string kind, Uri? resource, string name, IdFactory idFactory) : base(label: "project", idFactory) { Kind = kind; diff --git a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb index 2ffc83d87fd6a..07854f60ea5c3 100644 --- a/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb +++ b/src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb @@ -25,8 +25,8 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests Dim projectVertex = Assert.Single(lsif.Vertices.OfType(Of Graph.LsifProject)) Dim documentVertices = lsif.GetLinkedVertices(Of Graph.LsifDocument)(projectVertex, "contains") - Dim documentA = Assert.Single(documentVertices, Function(d) d.Uri.GetRequiredParsedUri().LocalPath = "Z:\A.cs") - Dim documentB = Assert.Single(documentVertices, Function(d) d.Uri.GetRequiredParsedUri().LocalPath = "Z:\B.cs") + Dim documentA = Assert.Single(documentVertices, Function(d) d.Uri.LocalPath = "Z:\A.cs") + Dim documentB = Assert.Single(documentVertices, Function(d) d.Uri.LocalPath = "Z:\B.cs") ' We don't include contents for normal files, just generated ones Assert.Null(documentA.Contents) @@ -57,7 +57,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests Dim contents = Encoding.UTF8.GetString(Convert.FromBase64String(contentBase64Encoded)) Dim compilation = Await workspace.CurrentSolution.Projects.Single().GetCompilationAsync() - Dim tree = Assert.Single(compilation.SyntaxTrees, Function(t) generatedDocumentVertex.Uri.GetRequiredParsedUri().OriginalString.Contains(Path.GetFileName(t.FilePath))) + Dim tree = Assert.Single(compilation.SyntaxTrees, Function(t) generatedDocumentVertex.Uri.OriginalString.Contains(Path.GetFileName(t.FilePath))) Assert.Equal(tree.GetText().ToString(), contents) Next diff --git a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb index 92e6798501f9f..c058f5fa0309d 100644 --- a/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb +++ b/src/Features/Lsif/GeneratorTest/Utilities/TestLsifOutput.vb @@ -111,7 +111,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U For Each testDocument In _workspace.Documents Dim documentVertex = _testLsifJsonWriter.Vertices _ .OfType(Of Graph.LsifDocument) _ - .Where(Function(d) d.Uri.GetRequiredParsedUri().LocalPath = testDocument.FilePath) _ + .Where(Function(d) d.Uri.LocalPath = testDocument.FilePath) _ .Single() Dim rangeVertices = GetLinkedVertices(Of Range)(documentVertex, "contains") @@ -165,7 +165,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U Public Function GetFoldingRanges(document As Document) As LSP.FoldingRange() Dim documentVertex = _testLsifJsonWriter.Vertices. OfType(Of LsifDocument). - Where(Function(d) d.Uri.GetRequiredParsedUri().LocalPath = document.FilePath). + Where(Function(d) d.Uri.LocalPath = document.FilePath). Single() Dim foldingRangeVertex = GetLinkedVertices(Of FoldingRangeResult)(documentVertex, "textDocument/foldingRange").Single() Return foldingRangeVertex.Result @@ -174,7 +174,7 @@ Namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator.UnitTests.U Public Function GetSemanticTokens(document As Document) As LSP.SemanticTokens Dim documentVertex = _testLsifJsonWriter.Vertices. OfType(Of LsifDocument). - Where(Function(d) d.Uri.GetRequiredParsedUri().LocalPath = document.FilePath). + Where(Function(d) d.Uri.LocalPath = document.FilePath). Single() Dim semanticTokensVertex = GetLinkedVertices(Of SemanticTokensResult)(documentVertex, "textDocument/semanticTokens/full").Single() diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 1b0ef2b6e740e..1d0be6244de58 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -108,6 +108,7 @@ public static JsonSerializerOptions AddLspSerializerOptions(this JsonSerializerO { LSP.VSInternalExtensionUtilities.AddVSInternalExtensionConverters(options); options.Converters.Add(new LSP.NaturalObjectConverter()); + options.Converters.Add(new DocumentUriConverter()); return options; } diff --git a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs index be7d2a2f1a781..62f545adec200 100644 --- a/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/SpellCheck/SpellCheckTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -658,7 +658,7 @@ private static VSInternalWorkspaceSpellCheckableParams CreateWorkspaceParams( private static ImmutableArray<(string resultId, DocumentUri uri)> CreateParamsFromPreviousReports(VSInternalWorkspaceSpellCheckableReport[] results) { - return [.. results.Select(r => (r.ResultId!, Uri:r.TextDocument.DocumentUri))]; + return [.. results.Select(r => (r.ResultId!, Uri: r.TextDocument.DocumentUri))]; } } -} \ No newline at end of file +} From b6fab9e728b21aa6ceac15ad1366347b3e659b5a Mon Sep 17 00:00:00 2001 From: David Barbet Date: Mon, 5 May 2025 11:35:32 -0700 Subject: [PATCH 9/9] react to main changes --- .../Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs index 9eca269cdd6bb..20e5e24b9e017 100644 --- a/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Miscellaneous/LspMiscellaneousFilesWorkspaceTests.cs @@ -192,7 +192,7 @@ public async Task TestLooseFile_RazorFile(bool mutatingLspWorkspace) Assert.Null(GetMiscellaneousAdditionalDocument(testLspServer)); // Open an empty loose file and make a request to verify it gets added to the misc workspace. - var looseFileUri = ProtocolConversions.CreateAbsoluteUri(@"C:\SomeFile.razor"); + var looseFileUri = ProtocolConversions.CreateAbsoluteDocumentUri(@"C:\SomeFile.razor"); await testLspServer.OpenDocumentAsync(looseFileUri, source).ConfigureAwait(false); // Trigger a request and assert we got a file in the misc workspace.