Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not parse URIs during LSP serialization/deserialization #76691

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal abstract class AbstractVSTypeScriptRequestHandler<TRequestType, TRespon

var textDocumentIdentifier = new VSTextDocumentIdentifier
{
Uri = typeScriptIdentifier.Value.Uri,
Uri = new(typeScriptIdentifier.Value.Uri),
};

if (typeScriptIdentifier.Value.ProjectId != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
using Microsoft.CodeAnalysis.Text;
using Microsoft.CommonLanguageServerProtocol.Framework;
using Nerdbank.Streams;
using Roslyn.LanguageServer.Protocol;
using Roslyn.Utilities;
using StreamJsonRpc;
using Xunit;
Expand Down Expand Up @@ -74,7 +75,7 @@ internal class TestSpanMapper : ISpanMappingService
internal static readonly LSP.Location MappedFileLocation = new LSP.Location
{
Range = ProtocolConversions.LinePositionToRange(s_mappedLinePosition),
Uri = ProtocolConversions.CreateAbsoluteUri(s_mappedFilePath)
Uri = ProtocolConversions.CreateAbsoluteDocumentUri(s_mappedFilePath)
};

/// <summary>
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 };

Expand Down Expand Up @@ -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
{
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -650,14 +651,14 @@ private static RoslynLanguageServer CreateLanguageServer(Stream inputStream, Str
return languageServer;
}

public async Task<Document> GetDocumentAsync(Uri uri)
public async Task<Document> 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<SourceText> GetDocumentTextAsync(Uri uri)
public async Task<SourceText> GetDocumentTextAsync(DocumentUri uri)
{
var document = await GetDocumentAsync(uri).ConfigureAwait(false);
return await document.GetTextAsync(CancellationToken.None).ConfigureAwait(false);
Expand Down Expand Up @@ -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)
{
Expand All @@ -706,15 +707,15 @@ public async Task OpenDocumentAsync(Uri documentUri, string? text = null, string
await ExecuteRequestAsync<LSP.DidOpenTextDocumentParams, object>(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,
[.. changes]);
return ExecuteRequestAsync<LSP.DidChangeTextDocumentParams, object>(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
{
Expand All @@ -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
{
Expand All @@ -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.DidCloseTextDocumentParams, object>(LSP.Methods.TextDocumentDidCloseName, didCloseParams, CancellationToken.None);
Expand Down Expand Up @@ -790,7 +791,7 @@ internal async Task WaitForDiagnosticsAsync()

internal T GetRequiredLspService<T>() where T : class, ILspService => LanguageServer.GetTestAccessor().GetRequiredLspService<T>();

internal ImmutableArray<SourceText> GetTrackedTexts() => [.. GetManager().GetTrackedLspText().Values.Select(v => v.Text)];
internal ImmutableArray<SourceText> GetTrackedTexts() => [.. GetManager().GetTrackedLspText().Values.Select(v => v.SourceText)];

internal Task RunCodeAnalysisAsync(ProjectId? projectId)
=> _codeAnalysisService.RunAnalysisAsync(GetCurrentSolution(), projectId, onAfterProjectAnalyzed: _ => { }, CancellationToken.None);
Expand Down
2 changes: 1 addition & 1 deletion src/Features/Lsif/Generator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
2 changes: 1 addition & 1 deletion src/Features/Lsif/GeneratorTest/ProjectStructureTests.vb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal abstract class AbstractCompilerDeveloperSdkLspServiceDocumentRequestHan
bool ISolutionRequiredHandler.RequiresLSPSolution => RequiresLSPSolution;

TextDocumentIdentifier ITextDocumentIdentifierHandler<TRequest, TextDocumentIdentifier>.GetTextDocumentIdentifier(TRequest request)
=> new() { Uri = GetTextDocumentIdentifier(request) };
=> new() { Uri = new(GetTextDocumentIdentifier(request)) };
Task<TResponse> IRequestHandler<TRequest, TResponse, LspRequestContext>.HandleRequestAsync(TRequest request, LspRequestContext context, CancellationToken cancellationToken)
=> HandleRequestAsync(request, new RequestContext(context), cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DidOpenTextDocumentParams, object>(Methods.TextDocumentDidOpenName, new DidOpenTextDocumentParams
{
TextDocument = new TextDocumentItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<RazorDynamicFileUpdate> _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<SourceText> _emptySourceText = new Lazy<SourceText>(() =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand All @@ -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)
{
Expand Down Expand Up @@ -113,7 +115,7 @@ public Task RemoveDynamicFileInfoAsync(ProjectId projectId, string? projectFileP
{
CSharpDocument = new()
{
Uri = ProtocolConversions.CreateAbsoluteUri(filePath)
Uri = ProtocolConversions.CreateAbsoluteDocumentUri(filePath)
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -38,9 +39,9 @@ public Task<ProjectDebugConfiguration[]> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Loading
Loading