Skip to content

Commit

Permalink
Merge pull request #54397 from dibarbet/active_context_16
Browse files Browse the repository at this point in the history
Query workspace for active document when we are not passed a project context in an LSP request
  • Loading branch information
dibarbet committed Jun 28, 2021
2 parents d547c1e + 5605038 commit b24e9ad
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 25 deletions.
27 changes: 17 additions & 10 deletions src/Features/LanguageServer/Protocol/Extensions/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,31 @@ private static ImmutableArray<Document> FilterDocumentsByClientName(ImmutableArr
return documents.FindDocumentInProjectContext(documentIdentifier);
}

public static T FindDocumentInProjectContext<T>(this ImmutableArray<T> documents, TextDocumentIdentifier documentIdentifier) where T : TextDocument
public static Document FindDocumentInProjectContext(this ImmutableArray<Document> documents, TextDocumentIdentifier documentIdentifier)
{
if (documents.Length > 1)
{
// We have more than one document; try to find the one that matches the right context
if (documentIdentifier is VSTextDocumentIdentifier vsDocumentIdentifier)
if (documentIdentifier is VSTextDocumentIdentifier vsDocumentIdentifier && vsDocumentIdentifier.ProjectContext != null)
{
if (vsDocumentIdentifier.ProjectContext != null)
{
var projectId = ProtocolConversions.ProjectContextToProjectId(vsDocumentIdentifier.ProjectContext);
var matchingDocument = documents.FirstOrDefault(d => d.Project.Id == projectId);
var projectId = ProtocolConversions.ProjectContextToProjectId(vsDocumentIdentifier.ProjectContext);
var matchingDocument = documents.FirstOrDefault(d => d.Project.Id == projectId);

if (matchingDocument != null)
{
return matchingDocument;
}
if (matchingDocument != null)
{
return matchingDocument;
}
}
else
{
// We were not passed a project context. This can happen when the LSP powered NavBar is not enabled.
// This branch should be removed when we're using the LSP based navbar in all scenarios.

var solution = documents.First().Project.Solution;
// Lookup which of the linked documents is currently active in the workspace.
var documentIdInCurrentContext = solution.Workspace.GetDocumentIdInCurrentContext(documents.First().Id);
return solution.GetRequiredDocument(documentIdInCurrentContext);
}
}

// We either have only one document or have multiple, but none of them matched our context. In the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Test;
using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Experiments;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.CodeAnalysis.Test.Utilities;
Expand All @@ -35,7 +37,7 @@ public async Task TestNoDocumentDiagnosticsForClosedFilesWithFSAOff()

var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single();

var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI());

Assert.Empty(results);
}
Expand All @@ -55,7 +57,7 @@ public async Task TestDocumentDiagnosticsForOpenFilesWithFSAOff()
await OpenDocumentAsync(testLspServer, document);

var results = await RunGetDocumentPullDiagnosticsAsync(
testLspServer, testLspServer.GetCurrentSolution().Projects.Single().Documents.Single());
testLspServer, document.GetURI());

Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code);
}
Expand All @@ -74,7 +76,7 @@ public async Task TestNoDocumentDiagnosticsForOpenFilesWithFSAOffIfInPushMode()

await OpenDocumentAsync(testLspServer, document);

var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI());

Assert.Empty(results.Single().Diagnostics);
}
Expand Down Expand Up @@ -139,7 +141,7 @@ public async Task TestDocumentDiagnosticsForRemovedDocument()
await WaitForDiagnosticsAsync(workspace);
var results = await testLspServer.ExecuteRequestAsync<DocumentDiagnosticsParams, DiagnosticReport[]>(
MSLSPMethods.DocumentPullDiagnosticName,
CreateDocumentDiagnosticParams(document),
CreateDocumentDiagnosticParams(document.GetURI()),
new LSP.ClientCapabilities(),
clientName: null,
CancellationToken.None);
Expand Down Expand Up @@ -177,13 +179,13 @@ public async Task TestNoChangeIfDocumentDiagnosticsCalledTwice()

await OpenDocumentAsync(testLspServer, document);

var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI());

Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code);

var resultId = results.Single().ResultId;
results = await RunGetDocumentPullDiagnosticsAsync(
testLspServer, testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(), previousResultId: resultId);
testLspServer, document.GetURI(), previousResultId: resultId);

Assert.Null(results.Single().Diagnostics);
Assert.Equal(resultId, results.Single().ResultId);
Expand All @@ -203,13 +205,13 @@ public async Task TestDocumentDiagnosticsRemovedAfterErrorIsFixed()

await OpenDocumentAsync(testLspServer, document);

var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI());

Assert.Equal("CS1513", results[0].Diagnostics.Single().Code);

await InsertTextAsync(testLspServer, document, buffer.CurrentSnapshot.Length, "}");

results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, testLspServer.GetCurrentSolution().Projects.Single().Documents.Single());
results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI());

Assert.Empty(results[0].Diagnostics);
}
Expand All @@ -227,7 +229,7 @@ public async Task TestDocumentDiagnosticsRemainAfterErrorIsNotFixed()
var document = testLspServer.GetCurrentSolution().Projects.Single().Documents.Single();

await OpenDocumentAsync(testLspServer, document);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI());

Assert.Equal("CS1513", results[0].Diagnostics.Single().Code);
Assert.Equal(new Position { Line = 0, Character = 9 }, results[0].Diagnostics.Single().Range.Start);
Expand All @@ -236,7 +238,7 @@ public async Task TestDocumentDiagnosticsRemainAfterErrorIsNotFixed()
await InsertTextAsync(testLspServer, document, position: 0, text: " ");

results = await RunGetDocumentPullDiagnosticsAsync(
testLspServer, testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(),
testLspServer, document.GetURI(),
previousResultId: results[0].ResultId);

Assert.Equal("CS1513", results[0].Diagnostics.Single().Code);
Expand Down Expand Up @@ -274,12 +276,56 @@ public async Task TestStreamingDocumentDiagnostics()
await OpenDocumentAsync(testLspServer, document);

var progress = BufferedProgress.Create<DiagnosticReport>(null);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, testLspServer.GetCurrentSolution().Projects.Single().Documents.Single(), progress: progress);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, document.GetURI(), progress: progress);

Assert.Null(results);
Assert.Equal("CS1513", progress.GetValues()!.Single().Diagnostics.Single().Code);
}

[Fact]
public async Task TestDocumentDiagnosticsForOpenFilesUsesActiveContext()
{
var documentText =
@"#if ONE
class A {
#endif
class B {";
var workspaceXml =
@$"<Workspace>
<Project Language=""C#"" CommonReferences=""true"" AssemblyName=""CSProj1"" PreprocessorSymbols=""ONE"">
<Document FilePath=""C:\C.cs"">{documentText}</Document>
</Project>
<Project Language=""C#"" CommonReferences=""true"" AssemblyName=""CSProj2"">
<Document IsLinkFile=""true"" LinkFilePath=""C:\C.cs"" LinkAssemblyName=""CSProj1"">{documentText}</Document>
</Project>
</Workspace>";

using var testLspServer = CreateTestWorkspaceFromXml(workspaceXml, BackgroundAnalysisScope.OpenFilesAndProjects);

var csproj1Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj1").Single().Documents.First();
var csproj2Document = testLspServer.GetCurrentSolution().Projects.Where(p => p.Name == "CSProj2").Single().Documents.First();

// Open either of the documents via LSP, we're tracking the URI and text.
await OpenDocumentAsync(testLspServer, csproj1Document);

// This opens all documents in the workspace and ensures buffers are created.
testLspServer.TestWorkspace.GetTestDocument(csproj1Document.Id).GetTextBuffer();

// Set CSProj2 as the active context and get diagnostics.
testLspServer.TestWorkspace.SetDocumentContext(csproj2Document.Id);
var results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, csproj2Document.GetURI());
Assert.Equal("CS1513", results.Single().Diagnostics.Single().Code);
var vsDiagnostic = (LSP.VSDiagnostic)results.Single().Diagnostics.Single();
Assert.Equal("CSProj2", vsDiagnostic.Projects.Single().ProjectName);

// Set CSProj1 as the active context and get diagnostics.
testLspServer.TestWorkspace.SetDocumentContext(csproj1Document.Id);
results = await RunGetDocumentPullDiagnosticsAsync(testLspServer, csproj1Document.GetURI());
Assert.Equal(2, results.Single().Diagnostics!.Length);
Assert.All(results.Single().Diagnostics, d => Assert.Equal("CS1513", d.Code));
Assert.All(results.Single().Diagnostics, d => Assert.Equal("CSProj1", ((VSDiagnostic)d).Projects.Single().ProjectName));
}

#endregion

#region Workspace Diagnostics
Expand Down Expand Up @@ -480,15 +526,15 @@ public async Task TestStreamingWorkspaceDiagnostics()

private static async Task<DiagnosticReport[]> RunGetDocumentPullDiagnosticsAsync(
TestLspServer testLspServer,
Document document,
Uri uri,
string? previousResultId = null,
IProgress<DiagnosticReport[]>? progress = null)
{
await WaitForDiagnosticsAsync(testLspServer.TestWorkspace);

var result = await testLspServer.ExecuteRequestAsync<DocumentDiagnosticsParams, DiagnosticReport[]>(
MSLSPMethods.DocumentPullDiagnosticName,
CreateDocumentDiagnosticParams(document, previousResultId, progress),
CreateDocumentDiagnosticParams(uri, previousResultId, progress),
new LSP.ClientCapabilities(),
clientName: null,
CancellationToken.None);
Expand Down Expand Up @@ -523,13 +569,13 @@ private static async Task WaitForDiagnosticsAsync(TestWorkspace workspace)
}

private static DocumentDiagnosticsParams CreateDocumentDiagnosticParams(
Document document,
Uri uri,
string? previousResultId = null,
IProgress<DiagnosticReport[]>? progress = null)
{
return new DocumentDiagnosticsParams
{
TextDocument = ProtocolConversions.DocumentToTextDocumentIdentifier(document),
TextDocument = new LSP.TextDocumentIdentifier { Uri = uri },
PreviousResultId = previousResultId,
PartialResultToken = progress,
};
Expand All @@ -556,6 +602,13 @@ private TestLspServer CreateTestWorkspaceWithDiagnostics(string markup, Backgrou
return testLspServer;
}

private TestLspServer CreateTestWorkspaceFromXml(string xmlMarkup, BackgroundAnalysisScope scope, bool pullDiagnostics = true)
{
var testLspServer = CreateXmlTestLspServer(xmlMarkup, out _);
InitializeDiagnostics(scope, testLspServer.TestWorkspace, pullDiagnostics);
return testLspServer;
}

private TestLspServer CreateTestWorkspaceWithDiagnostics(string[] markups, BackgroundAnalysisScope scope, bool pullDiagnostics = true)
{
var testLspServer = CreateTestLspServer(markups, out _);
Expand Down

0 comments on commit b24e9ad

Please sign in to comment.