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

Support 'view call hierarchy' on primary consstructor #77328

Merged
merged 9 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions src/Features/Core/Portable/FindUsages/FindUsagesHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.SymbolMapping;

Expand All @@ -18,25 +19,40 @@ internal static class FindUsagesHelpers
public static string GetDisplayName(ISymbol symbol)
=> symbol.IsConstructor() ? symbol.ContainingType.Name : symbol.Name;

public static Task<(ISymbol symbol, Project project)?> GetRelevantSymbolAndProjectAtPositionAsync(
Document document, int position, CancellationToken cancellationToken)
=> GetRelevantSymbolAndProjectAtPositionAsync(document, position, preferPrimaryConstructor: false, cancellationToken);

/// <summary>
/// Common helper for both the synchronous and streaming versions of FAR.
/// It returns the symbol we want to search for and the solution we should
/// be searching.
///
/// Note that the <see cref="Solution"/> returned may absolutely *not* be
/// the same as <c>document.Project.Solution</c>. This is because
/// there may be symbol mapping involved (for example in Metadata-As-Source
/// scenarios).
/// Common helper for both the synchronous and streaming versions of FAR. It returns the symbol we want to search
/// for and the solution we should be searching.
/// <para/> Note that the <see cref="Solution"/> returned may absolutely *not* be the same as
/// <c>document.Project.Solution</c>. This is because there may be symbol mapping involved (for example in
/// Metadata-As-Source scenarios).
/// </summary>
/// <param name="preferPrimaryConstructor">Whether the named type or primary constructor should be preferred if the
/// position is on a type-header fof a type declaration that has primary constructor parameters.</param>
public static async Task<(ISymbol symbol, Project project)?> GetRelevantSymbolAndProjectAtPositionAsync(
Document document, int position, CancellationToken cancellationToken)
Document document, int position, bool preferPrimaryConstructor, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken: cancellationToken).ConfigureAwait(false);
var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken).ConfigureAwait(false);
if (symbol == null)
return null;

if (preferPrimaryConstructor && symbol is INamedTypeSymbol namedType)
{
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var headerFacts = document.GetRequiredLanguageService<IHeaderFactsService>();
var semanticFacts = document.GetRequiredLanguageService<ISemanticFactsService>();
if (headerFacts.IsOnTypeHeader(root, position, out _) &&
semanticFacts.TryGetPrimaryConstructor(namedType, out var primaryConstructor))
{
symbol = primaryConstructor;
}
}

// If this document is not in the primary workspace, we may want to search for results
// in a solution different from the one we started in. Use the starting workspace's
// ISymbolMappingService to get a context for searching in the proper solution.
Expand Down
Loading
Loading