Skip to content

Commit

Permalink
Provide SourceGeneratedFileInfo for workspace symbolls requests (#2431)
Browse files Browse the repository at this point in the history
* Provide SourceGeneratedFileInfo for workspace symbolls requests

Updates the workspace symbols requests to provide a SourceGeneratedFileInfo when the symbol is from a source generated file, so aware editors can retrieve information about the file and display it correctly, rather than showing no information.

* Add tests, filed dotnet/roslyn#63375 on roslyn.
  • Loading branch information
333fred committed Aug 13, 2022
1 parent 46d4c98 commit e06a8bf
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 25 deletions.
8 changes: 6 additions & 2 deletions src/OmniSharp.Abstractions/Models/v1/SymbolLocation.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
namespace OmniSharp.Models
using OmniSharp.Models.v1.SourceGeneratedFile;

namespace OmniSharp.Models
{
public class SymbolLocation : QuickFix
{
public string Kind { get; set; }
public string ContainingSymbolName { get; set; }
public SourceGeneratedFileInfo GeneratedFileInfo { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static IEnumerable<IJsonRpcHandler> Enumerate(RequestHandlers handlers)
{
Name = x.Text,
Kind = Helpers.ToSymbolKind(x.Kind),
ContainerName = x.ContainingSymbolName,
Location = new OmniSharp.Extensions.LanguageServer.Protocol.Models.Location
{
Uri = Helpers.ToUri(x.FileName),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using OmniSharp.Extensions;
using OmniSharp.Models.v1.SourceGeneratedFile;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -44,21 +42,5 @@ internal static class GoToDefinitionHelpers

return null;
}

internal static SourceGeneratedFileInfo? GetSourceGeneratedFileInfo(OmniSharpWorkspace workspace, Location location)
{
Debug.Assert(location.IsInSource);
var document = workspace.CurrentSolution.GetDocument(location.SourceTree);
if (document is not SourceGeneratedDocument)
{
return null;
}

return new SourceGeneratedFileInfo
{
ProjectGuid = document.Project.Id.Id,
DocumentGuid = document.Id.Id
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public async Task<GotoDefinitionResponse> Handle(GotoDefinitionRequest request)
FileName = lineSpan.Path,
Line = lineSpan.StartLinePosition.Line,
Column = lineSpan.StartLinePosition.Character,
SourceGeneratedInfo = GoToDefinitionHelpers.GetSourceGeneratedFileInfo(_workspace, location)
SourceGeneratedInfo = SolutionExtensions.GetSourceGeneratedFileInfo(document.Project.Solution, location)
};
}
else if (location.IsInMetadata && request.WantMetadata)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public async Task<GotoDefinitionResponse> Handle(GotoDefinitionRequest request)
}
else
{
sourceGeneratedFileInfo = GoToDefinitionHelpers.GetSourceGeneratedFileInfo(_workspace, location);
sourceGeneratedFileInfo = SolutionExtensions.GetSourceGeneratedFileInfo(document.Project.Solution, location);
}
return new Definition
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async Task<GotoTypeDefinitionResponse> Handle(GotoTypeDefinitionRequest r
.Select(location => new TypeDefinition
{
Location = location.GetMappedLineSpan().GetLocationFromFileLinePositionSpan(),
SourceGeneratedFileInfo = GoToDefinitionHelpers.GetSourceGeneratedFileInfo(_workspace, location)
SourceGeneratedFileInfo = SolutionExtensions.GetSourceGeneratedFileInfo(document.Project.Solution, location)
})
.ToList()
};
Expand Down
26 changes: 24 additions & 2 deletions src/OmniSharp.Roslyn/Extensions/SolutionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using OmniSharp.Models;
using OmniSharp.Models.v1.SourceGeneratedFile;

#nullable enable

namespace OmniSharp.Extensions
{
Expand Down Expand Up @@ -67,7 +71,7 @@ private static QuickFix ConvertSymbol(Solution solution, ISymbol symbol, Locatio
var lineSpan = location.GetLineSpan();
var path = lineSpan.Path;
var projects = solution.GetDocumentIdsWithFilePath(path)
.Select(documentId => solution.GetProject(documentId.ProjectId).Name)
.Select(documentId => solution.GetProject(documentId.ProjectId)!.Name)
.ToArray();

var format = SymbolDisplayFormat.MinimallyQualifiedFormat;
Expand All @@ -86,7 +90,25 @@ private static QuickFix ConvertSymbol(Solution solution, ISymbol symbol, Locatio
Column = lineSpan.StartLinePosition.Character,
EndLine = lineSpan.EndLinePosition.Line,
EndColumn = lineSpan.EndLinePosition.Character,
Projects = projects
Projects = projects,
ContainingSymbolName = symbol.ContainingSymbol?.Name ?? "",
GeneratedFileInfo = GetSourceGeneratedFileInfo(solution, location),
};
}

internal static SourceGeneratedFileInfo? GetSourceGeneratedFileInfo(Solution solution, Location location)
{
Debug.Assert(location.IsInSource);
var document = solution.GetDocument(location.SourceTree);
if (document is not SourceGeneratedDocument)
{
return null;
}

return new SourceGeneratedFileInfo
{
ProjectGuid = document.Project.Id.Id,
DocumentGuid = document.Id.Id
};
}
}
Expand Down
76 changes: 76 additions & 0 deletions tests/OmniSharp.Roslyn.CSharp.Tests/FindSymbolsFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
using TestUtility;
using Xunit;
using Xunit.Abstractions;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Diagnostics;
using System;
using OmniSharp.Models.v1.SourceGeneratedFile;

namespace OmniSharp.Roslyn.CSharp.Tests
{
Expand Down Expand Up @@ -343,6 +347,78 @@ public class ProbabilityManager {}";
Assert.DoesNotContain("ProbabilityManager", symbols);
}

[Fact(Skip = "https://github.com/dotnet/roslyn/issues/63375")]
public async Task SymbolsReturnedForGeneratedTypes()
{
const string Source = @"
public class Generated
{
public int Property { get; set; }
}
";

TestHelpers.AddProjectToWorkspace(SharedOmniSharpTestHost.Workspace,
"project.csproj",
new[] { "netcoreapp3.1" },
Array.Empty<TestFile>(),
analyzerRefs: ImmutableArray.Create<AnalyzerReference>(new TestGeneratorReference(
context => context.AddSource("GeneratedFile", Source))));

var requestHandler = GetRequestHandler(SharedOmniSharpTestHost);
var response = await requestHandler.Handle(new FindSymbolsRequest
{
Filter = "Property"
});

var result = (SymbolLocation)response.QuickFixes.Single();
Assert.NotNull(result);
}

[Fact]
public async Task SymbolsReturnedForGeneratedTypes_Partial()
{
const string Source = @"
public partial class Generated
{
public int Property { get; set; }
}
";
const string FileName = "real.cs";
var testFile = new TestFile(FileName, @"
partial Generated
{
}
");

TestHelpers.AddProjectToWorkspace(SharedOmniSharpTestHost.Workspace,
"project.csproj",
new[] { "netcoreapp3.1" },
new[] { testFile },
analyzerRefs: ImmutableArray.Create<AnalyzerReference>(new TestGeneratorReference(
context => context.AddSource("GeneratedFile", Source))));

var requestHandler = GetRequestHandler(SharedOmniSharpTestHost);
var response = await requestHandler.Handle(new FindSymbolsRequest
{
Filter = "Generated"
});

var result = response.QuickFixes.Cast<SymbolLocation>().Single(s => s.GeneratedFileInfo is not null);
Assert.NotNull(result);

var sourceGeneratedFileHandler = SharedOmniSharpTestHost.GetRequestHandler<SourceGeneratedFileService>(OmniSharpEndpoints.SourceGeneratedFile);
var sourceGeneratedRequest = new SourceGeneratedFileRequest
{
DocumentGuid = result.GeneratedFileInfo.DocumentGuid,
ProjectGuid = result.GeneratedFileInfo.ProjectGuid
};

var sourceGeneratedFileResponse = await sourceGeneratedFileHandler.Handle(sourceGeneratedRequest);
Assert.NotNull(sourceGeneratedFileResponse);
Assert.Equal(Source, sourceGeneratedFileResponse.Source);
Assert.Equal(@"OmniSharp.Roslyn.CSharp.Tests\OmniSharp.Roslyn.CSharp.Tests.TestSourceGenerator\GeneratedFile.cs", sourceGeneratedFileResponse.SourceName.Replace("/", @"\"));
}

private async Task<QuickFixResponse> FindSymbolsAsync(string code, string filename)
{
var testFile = new TestFile(filename, code);
Expand Down

0 comments on commit e06a8bf

Please sign in to comment.