|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Collections;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.QuickInfo;
internal abstract class CommonQuickInfoProvider : QuickInfoProvider
{
protected abstract Task<QuickInfoItem?> BuildQuickInfoAsync(QuickInfoContext context, SyntaxToken token);
protected abstract Task<QuickInfoItem?> BuildQuickInfoAsync(CommonQuickInfoContext context, SyntaxToken token);
public override async Task<QuickInfoItem?> GetQuickInfoAsync(QuickInfoContext context)
{
var cancellationToken = context.CancellationToken;
var tree = await context.Document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var tokens = await GetTokensAsync(tree, context.Position, context.CancellationToken).ConfigureAwait(false);
foreach (var token in tokens)
{
var info = await GetQuickInfoAsync(context, token).ConfigureAwait(false);
if (info != null)
return info;
}
return null;
}
public async Task<QuickInfoItem?> GetQuickInfoAsync(CommonQuickInfoContext context)
{
var tokens = await GetTokensAsync(context.SemanticModel.SyntaxTree, context.Position, context.CancellationToken).ConfigureAwait(false);
foreach (var token in tokens)
{
var info = await GetQuickInfoAsync(context, token).ConfigureAwait(false);
if (info != null)
return info;
}
return null;
}
protected async Task<ImmutableArray<SyntaxToken>> GetTokensAsync(SyntaxTree tree, int position, System.Threading.CancellationToken cancellationToken)
{
using var result = TemporaryArray<SyntaxToken>.Empty;
var token = await tree.GetTouchingTokenAsync(position, cancellationToken, findInsideTrivia: true).ConfigureAwait(false);
if (token != default)
{
result.Add(token);
if (ShouldCheckPreviousToken(token))
{
token = token.GetPreviousToken();
if (token != default && token.Span.IntersectsWith(position))
result.Add(token);
}
}
return result.ToImmutableAndClear();
}
protected virtual bool ShouldCheckPreviousToken(SyntaxToken token)
=> true;
private async Task<QuickInfoItem?> GetQuickInfoAsync(
QuickInfoContext context,
SyntaxToken token)
{
if (token != default &&
token.Span.IntersectsWith(context.Position))
{
return await BuildQuickInfoAsync(context, token).ConfigureAwait(false);
}
return null;
}
private async Task<QuickInfoItem?> GetQuickInfoAsync(
CommonQuickInfoContext context,
SyntaxToken token)
{
if (token != default &&
token.Span.IntersectsWith(context.Position))
{
return await BuildQuickInfoAsync(context, token).ConfigureAwait(false);
}
return null;
}
}
|