From f06a12446836eae00e7ba950dae1b613d0f852c7 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 11 Aug 2022 22:47:21 -0700 Subject: [PATCH 1/2] 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. --- .../Models/v1/SymbolLocation.cs | 8 ++++-- .../OmniSharpWorkspaceSymbolsHandler.cs | 1 + .../Navigation/GoToDefinitionHelpers.cs | 18 ------------- .../Navigation/GotoDefinitionService.cs | 2 +- .../Navigation/GotoDefinitionServiceV2.cs | 2 +- .../Navigation/GotoTypeDefinitionService.cs | 2 +- .../Extensions/SolutionExtensions.cs | 26 +++++++++++++++++-- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/OmniSharp.Abstractions/Models/v1/SymbolLocation.cs b/src/OmniSharp.Abstractions/Models/v1/SymbolLocation.cs index 71918216c5..3e4c7f8b7f 100644 --- a/src/OmniSharp.Abstractions/Models/v1/SymbolLocation.cs +++ b/src/OmniSharp.Abstractions/Models/v1/SymbolLocation.cs @@ -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; } } -} \ No newline at end of file +} diff --git a/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpWorkspaceSymbolsHandler.cs b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpWorkspaceSymbolsHandler.cs index be99034cce..4086fc68fe 100644 --- a/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpWorkspaceSymbolsHandler.cs +++ b/src/OmniSharp.LanguageServerProtocol/Handlers/OmniSharpWorkspaceSymbolsHandler.cs @@ -60,6 +60,7 @@ public override async Task> Handle( { Name = x.Text, Kind = Helpers.ToSymbolKind(x.Kind), + ContainerName = x.ContainingSymbolName, Location = new OmniSharp.Extensions.LanguageServer.Protocol.Models.Location { Uri = Helpers.ToUri(x.FileName), diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GoToDefinitionHelpers.cs b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GoToDefinitionHelpers.cs index 1f350d68a8..f8c005fd0c 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GoToDefinitionHelpers.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GoToDefinitionHelpers.cs @@ -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; @@ -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 - }; - } } } diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionService.cs index 436dfc580d..2080648689 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionService.cs @@ -51,7 +51,7 @@ public async Task 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) diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionServiceV2.cs b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionServiceV2.cs index f947fc5c88..b685eaded4 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionServiceV2.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoDefinitionServiceV2.cs @@ -65,7 +65,7 @@ public async Task Handle(GotoDefinitionRequest request) } else { - sourceGeneratedFileInfo = GoToDefinitionHelpers.GetSourceGeneratedFileInfo(_workspace, location); + sourceGeneratedFileInfo = SolutionExtensions.GetSourceGeneratedFileInfo(document.Project.Solution, location); } return new Definition diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoTypeDefinitionService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoTypeDefinitionService.cs index 64a4de2db2..b6c61042ab 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoTypeDefinitionService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Navigation/GotoTypeDefinitionService.cs @@ -53,7 +53,7 @@ public async Task Handle(GotoTypeDefinitionRequest r .Select(location => new TypeDefinition { Location = location.GetMappedLineSpan().GetLocationFromFileLinePositionSpan(), - SourceGeneratedFileInfo = GoToDefinitionHelpers.GetSourceGeneratedFileInfo(_workspace, location) + SourceGeneratedFileInfo = SolutionExtensions.GetSourceGeneratedFileInfo(document.Project.Solution, location) }) .ToList() }; diff --git a/src/OmniSharp.Roslyn/Extensions/SolutionExtensions.cs b/src/OmniSharp.Roslyn/Extensions/SolutionExtensions.cs index 80f7fbfc71..31c32b9714 100644 --- a/src/OmniSharp.Roslyn/Extensions/SolutionExtensions.cs +++ b/src/OmniSharp.Roslyn/Extensions/SolutionExtensions.cs @@ -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 { @@ -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; @@ -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 }; } } From feea1dc41575dba32f1b2e6462f8bf9621740167 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 12 Aug 2022 22:44:22 -0700 Subject: [PATCH 2/2] Add tests, filed https://github.com/dotnet/roslyn/issues/63375 on roslyn. --- .../FindSymbolsFacts.cs | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/FindSymbolsFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/FindSymbolsFacts.cs index 43a3484cba..6c9dab8d32 100644 --- a/tests/OmniSharp.Roslyn.CSharp.Tests/FindSymbolsFacts.cs +++ b/tests/OmniSharp.Roslyn.CSharp.Tests/FindSymbolsFacts.cs @@ -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 { @@ -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(), + analyzerRefs: ImmutableArray.Create(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(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().Single(s => s.GeneratedFileInfo is not null); + Assert.NotNull(result); + + var sourceGeneratedFileHandler = SharedOmniSharpTestHost.GetRequestHandler(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 FindSymbolsAsync(string code, string filename) { var testFile = new TestFile(filename, code);