File: FindSymbols\FindReferences\Finders\MethodTypeParameterSymbolReferenceFinder.cs
Web Access
Project: ..\..\..\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.FindSymbols.Finders
{
    internal sealed class MethodTypeParameterSymbolReferenceFinder : AbstractTypeParameterSymbolReferenceFinder
    {
        protected override bool CanFind(ITypeParameterSymbol symbol)
            => symbol.TypeParameterKind == TypeParameterKind.Method;
 
        protected override ValueTask<ImmutableArray<ISymbol>> DetermineCascadedSymbolsAsync(
            ITypeParameterSymbol symbol,
            Solution solution,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            var method = (IMethodSymbol)symbol.ContainingSymbol;
            var ordinal = method.TypeParameters.IndexOf(symbol);
 
            if (ordinal >= 0)
            {
                if (method.PartialDefinitionPart != null && ordinal < method.PartialDefinitionPart.TypeParameters.Length)
                    return new(ImmutableArray.Create<ISymbol>(method.PartialDefinitionPart.TypeParameters[ordinal]));
 
                if (method.PartialImplementationPart != null && ordinal < method.PartialImplementationPart.TypeParameters.Length)
                    return new(ImmutableArray.Create<ISymbol>(method.PartialImplementationPart.TypeParameters[ordinal]));
            }
 
            return new(ImmutableArray<ISymbol>.Empty);
        }
 
        protected sealed override Task<ImmutableArray<Document>> DetermineDocumentsToSearchAsync(
            ITypeParameterSymbol symbol,
            HashSet<string>? globalAliases,
            Project project,
            IImmutableSet<Document>? documents,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            // Type parameters are only found in documents that have both their name, and the name
            // of its owning method.  NOTE(cyrusn): We have to check in multiple files because of
            // partial types.  A type parameter can be referenced across all the parts. NOTE(cyrusn):
            // We look for type parameters by name.  This means if the same type parameter has a
            // different name in different parts that we won't find it. However, this only happens
            // in error situations.  It is not legal in C# to use a different name for a type
            // parameter in different parts.
            //
            // Also, we only look for files that have the name of the owning type.  This helps filter
            // down the set considerably.
            Contract.ThrowIfNull(symbol.DeclaringMethod);
            return FindDocumentsAsync(project, documents, cancellationToken, symbol.Name,
                GetMemberNameWithoutInterfaceName(symbol.DeclaringMethod.Name),
                symbol.DeclaringMethod.ContainingType.Name);
        }
 
        private static string GetMemberNameWithoutInterfaceName(string fullName)
        {
            var index = fullName.LastIndexOf('.');
            return index > 0 ? fullName[(index + 1)..] : fullName;
        }
    }
}