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

Simplify lsif generation concepts #65858

Merged
merged 17 commits into from
Dec 10, 2022
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.LanguageServer
{
Expand All @@ -31,12 +29,15 @@ public EditorLspHoverResultCreationService(IGlobalOptionService optionService)
}

public async Task<Hover> CreateHoverAsync(
SourceText text, string language, QuickInfoItem info, Document? document, ClientCapabilities? clientCapabilities, CancellationToken cancellationToken)
Document document, QuickInfoItem info, ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var supportsVSExtensions = clientCapabilities.HasVisualStudioLspCapability();

if (!supportsVSExtensions)
return DefaultLspHoverResultCreationService.CreateDefaultHover(text, language, info, clientCapabilities);
return await DefaultLspHoverResultCreationService.CreateDefaultHoverAsync(document, info, clientCapabilities, cancellationToken).ConfigureAwait(false);

var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var language = document.Project.Language;

var classificationOptions = _optionService.GetClassificationOptions(language);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,6 @@ public override async Task<BlockStructure> GetBlockStructureAsync(
return GetBlockStructure(context, _providers);
}

public BlockStructure GetBlockStructure(
SyntaxTree syntaxTree,
in BlockStructureOptions options,
CancellationToken cancellationToken)
{
var context = CreateContext(syntaxTree, options, cancellationToken);
return GetBlockStructure(context, _providers);
}

private static BlockStructureContext CreateContext(
SyntaxTree syntaxTree,
in BlockStructureOptions options,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Structure;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;
Expand Down Expand Up @@ -40,37 +41,24 @@ public FoldingRangesHandler(IGlobalOptionService globalOptions)
if (document is null)
return null;

var blockStructureService = document.Project.Services.GetService<BlockStructureService>();
if (blockStructureService == null)
{
return Array.Empty<FoldingRange>();
}

var options = _globalOptions.GetBlockStructureOptions(document.Project);
var blockStructure = await blockStructureService.GetBlockStructureAsync(document, options, cancellationToken).ConfigureAwait(false);
if (blockStructure == null)
{
return Array.Empty<FoldingRange>();
}

var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return GetFoldingRanges(blockStructure, text);
return await GetFoldingRangesAsync(document, options, cancellationToken).ConfigureAwait(false);
}

public static FoldingRange[] GetFoldingRanges(
SyntaxTree syntaxTree,
LanguageServices languageServices,
in BlockStructureOptions options,
/// <summary>
/// Used here and by lsif generator.
/// </summary>
public static async Task<FoldingRange[]> GetFoldingRangesAsync(
Document document,
BlockStructureOptions options,
CancellationToken cancellationToken)
{
var blockStructureService = (BlockStructureServiceWithProviders)languageServices.GetRequiredService<BlockStructureService>();
var blockStructure = blockStructureService.GetBlockStructure(syntaxTree, options, cancellationToken);
var blockStructureService = document.GetRequiredLanguageService<BlockStructureService>();
var blockStructure = await blockStructureService.GetBlockStructureAsync(document, options, cancellationToken).ConfigureAwait(false);
if (blockStructure == null)
{
return Array.Empty<FoldingRange>();
}

var text = syntaxTree.GetText(cancellationToken);
var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return GetFoldingRanges(blockStructure, text);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@

using System;
using System.Composition;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Microsoft.CodeAnalysis.LanguageServer.Handler
Expand Down Expand Up @@ -46,52 +45,26 @@ public HoverHandler(IGlobalOptionService globalOptions)
var clientCapabilities = context.GetRequiredClientCapabilities();

var position = await document.GetPositionFromLinePositionAsync(ProtocolConversions.PositionToLinePosition(request.Position), cancellationToken).ConfigureAwait(false);
var quickInfoService = document.Project.Services.GetRequiredService<QuickInfoService>();
var options = _globalOptions.GetSymbolDescriptionOptions(document.Project.Language);
var info = await quickInfoService.GetQuickInfoAsync(document, position, options, cancellationToken).ConfigureAwait(false);
if (info == null)
return null;

var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
return await GetHoverAsync(
document.Project.Solution.Services, info, text, document.Project.Language,
document, clientCapabilities, cancellationToken).ConfigureAwait(false);
return await GetHoverAsync(document, position, options, clientCapabilities, cancellationToken).ConfigureAwait(false);
}

internal static async Task<Hover?> GetHoverAsync(
SemanticModel semanticModel,
Document document,
int position,
SymbolDescriptionOptions options,
LanguageServices languageServices,
ClientCapabilities clientCapabilities,
CancellationToken cancellationToken)
{
Debug.Assert(semanticModel.Language is LanguageNames.CSharp or LanguageNames.VisualBasic);

// Get the quick info service to compute quick info.
// This code path is only invoked for C# and VB, so we can directly cast to QuickInfoServiceWithProviders.
var quickInfoService = (QuickInfoServiceWithProviders)languageServices.GetRequiredService<QuickInfoService>();
var info = await quickInfoService.GetQuickInfoAsync(semanticModel, position, options, cancellationToken).ConfigureAwait(false);
var quickInfoService = document.GetRequiredLanguageService<QuickInfoService>();
var info = await quickInfoService.GetQuickInfoAsync(document, position, options, cancellationToken).ConfigureAwait(false);
if (info == null)
return null;

var text = await semanticModel.SyntaxTree.GetTextAsync(cancellationToken).ConfigureAwait(false);
return await GetHoverAsync(
languageServices.SolutionServices, info, text, semanticModel.Language, document: null, clientCapabilities, cancellationToken).ConfigureAwait(false);
}

private static async Task<Hover> GetHoverAsync(
SolutionServices solutionServices,
QuickInfoItem info,
SourceText text,
string language,
Document? document,
ClientCapabilities? clientCapabilities,
CancellationToken cancellationToken)
{
var hoverService = solutionServices.GetRequiredService<ILspHoverResultCreationService>();
return await hoverService.CreateHoverAsync(
text, language, info, document, clientCapabilities, cancellationToken).ConfigureAwait(false);
var hoverService = document.Project.Solution.Services.GetRequiredService<ILspHoverResultCreationService>();
return await hoverService.CreateHoverAsync(document, info, clientCapabilities, cancellationToken).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.QuickInfo;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServer.Protocol;

namespace Microsoft.CodeAnalysis.LanguageServer.Handler
{
internal interface ILspHoverResultCreationService : IWorkspaceService
{
Task<Hover> CreateHoverAsync(
SourceText text, string language, QuickInfoItem info, Document? document, ClientCapabilities? clientCapabilities, CancellationToken cancellationToken);
Document document, QuickInfoItem info, ClientCapabilities clientCapabilities, CancellationToken cancellationToken);
}

[ExportWorkspaceService(typeof(ILspHoverResultCreationService)), Shared]
Expand All @@ -31,10 +30,10 @@ public DefaultLspHoverResultCreationService()
{
}

public Task<Hover> CreateHoverAsync(SourceText text, string language, QuickInfoItem info, Document? document, ClientCapabilities? clientCapabilities, CancellationToken cancellationToken)
=> Task.FromResult(CreateDefaultHover(text, language, info, clientCapabilities));
public Task<Hover> CreateHoverAsync(Document document, QuickInfoItem info, ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
=> CreateDefaultHoverAsync(document, info, clientCapabilities, cancellationToken);

public static Hover CreateDefaultHover(SourceText text, string language, QuickInfoItem info, ClientCapabilities? clientCapabilities)
public static async Task<Hover> CreateDefaultHoverAsync(Document document, QuickInfoItem info, ClientCapabilities clientCapabilities, CancellationToken cancellationToken)
{
var clientSupportsMarkdown = clientCapabilities?.TextDocument?.Hover?.ContentFormat.Contains(MarkupKind.Markdown) == true;

Expand All @@ -43,6 +42,9 @@ public static Hover CreateDefaultHover(SourceText text, string language, QuickIn
.SelectMany(section => section.TaggedParts.Add(new TaggedText(TextTags.LineBreak, Environment.NewLine)))
.ToImmutableArray();

var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
var language = document.Project.Language;

return new Hover
{
Range = ProtocolConversions.TextSpanToRange(info.Span, text),
Expand Down
24 changes: 4 additions & 20 deletions src/Features/Lsif/Generator/CompilerInvocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,16 @@

namespace Microsoft.CodeAnalysis.LanguageServerIndexFormat.Generator
{
internal class CompilerInvocation
internal static class CompilerInvocation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this can/should be renamed to something else but it's fine.

{
public Compilation Compilation { get; }
public LanguageServices LanguageServices { get; }
public string ProjectFilePath { get; }
public GeneratorOptions Options { get; }

public CompilerInvocation(Compilation compilation, LanguageServices languageServices, string projectFilePath, GeneratorOptions options)
{
Compilation = compilation;
LanguageServices = languageServices;
ProjectFilePath = projectFilePath;
Options = options;
}

public static async Task<CompilerInvocation> CreateFromJsonAsync(string jsonContents)
public static async Task<Project> CreateFromJsonAsync(string jsonContents)
{
var invocationInfo = JsonConvert.DeserializeObject<CompilerInvocationInfo>(jsonContents);
Assumes.Present(invocationInfo);
return await CreateFromInvocationInfoAsync(invocationInfo);
}

public static async Task<CompilerInvocation> CreateFromInvocationInfoAsync(CompilerInvocationInfo invocationInfo)
public static async Task<Project> CreateFromInvocationInfoAsync(CompilerInvocationInfo invocationInfo)
jasonmalinowski marked this conversation as resolved.
Show resolved Hide resolved
{
// We will use a Workspace to simplify the creation of the compilation, but will be careful not to return the Workspace instance from this class.
// We will still provide the language services which are used by the generator itself, but we don't tie it to a Workspace object so we can
Expand Down Expand Up @@ -113,10 +100,7 @@ public static async Task<CompilerInvocation> CreateFromInvocationInfoAsync(Compi
hostObjectType: null);

var solution = workspace.CurrentSolution.AddProject(projectInfo);
var compilation = await solution.GetRequiredProject(projectId).GetRequiredCompilationAsync(CancellationToken.None);
var options = GeneratorOptions.Default;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that we always used GeneratorOptions.Default here. so the callers of this method just pas that along instead.


return new CompilerInvocation(compilation, languageServices, invocationInfo.ProjectFilePath, options);
return solution.GetRequiredProject(projectId);

// Local methods:
DocumentInfo CreateDocumentInfo(string unmappedPath)
Expand Down
Loading