File: FindSymbols\FindReferences\Finders\NamespaceSymbolReferenceFinder.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.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.FindSymbols.Finders
{
    internal class NamespaceSymbolReferenceFinder : AbstractReferenceFinder<INamespaceSymbol>
    {
        protected override bool CanFind(INamespaceSymbol symbol)
            => true;
 
        protected override Task<ImmutableArray<string>> DetermineGlobalAliasesAsync(INamespaceSymbol symbol, Project project, CancellationToken cancellationToken)
        {
            return GetAllMatchingGlobalAliasNamesAsync(project, symbol.Name, arity: 0, cancellationToken);
        }
 
        protected override async Task<ImmutableArray<Document>> DetermineDocumentsToSearchAsync(
            INamespaceSymbol symbol,
            HashSet<string>? globalAliases,
            Project project,
            IImmutableSet<Document>? documents,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            using var _ = ArrayBuilder<Document>.GetInstance(out var result);
 
            result.AddRange(!symbol.IsGlobalNamespace
                ? await FindDocumentsAsync(project, documents, cancellationToken, symbol.Name).ConfigureAwait(false)
                : await FindDocumentsWithPredicateAsync(project, documents, static index => index.ContainsGlobalKeyword, cancellationToken).ConfigureAwait(false));
 
            if (globalAliases != null)
            {
                foreach (var globalAlias in globalAliases)
                {
                    result.AddRange(await FindDocumentsAsync(
                        project, documents, cancellationToken, globalAlias).ConfigureAwait(false));
                }
            }
 
            var documentsWithGlobalAttributes = await FindDocumentsWithGlobalSuppressMessageAttributeAsync(project, documents, cancellationToken).ConfigureAwait(false);
            result.AddRange(documentsWithGlobalAttributes);
 
            return result.ToImmutable();
        }
 
        protected override async ValueTask<ImmutableArray<FinderLocation>> FindReferencesInDocumentAsync(
            INamespaceSymbol symbol,
            FindReferencesDocumentState state,
            FindReferencesSearchOptions options,
            CancellationToken cancellationToken)
        {
            using var _ = ArrayBuilder<FinderLocation>.GetInstance(out var initialReferences);
 
            if (symbol.IsGlobalNamespace)
            {
                await AddGlobalNamespaceReferencesAsync(
                    symbol, state, initialReferences, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                var namespaceName = symbol.Name;
                await AddNamedReferencesAsync(
                    symbol, namespaceName, state, initialReferences, cancellationToken).ConfigureAwait(false);
 
                foreach (var globalAlias in state.GlobalAliases)
                {
                    // ignore the cases where the global alias might match the namespace name (i.e.
                    // global alias Collections = System.Collections).  We'll already find those references
                    // above.
                    if (state.SyntaxFacts.StringComparer.Equals(namespaceName, globalAlias))
                        continue;
 
                    await AddNamedReferencesAsync(
                        symbol, globalAlias, state, initialReferences, cancellationToken).ConfigureAwait(false);
                }
 
                initialReferences.AddRange(await FindLocalAliasReferencesAsync(
                    initialReferences, symbol, state, cancellationToken).ConfigureAwait(false));
 
                initialReferences.AddRange(await FindReferencesInDocumentInsideGlobalSuppressionsAsync(
                    symbol, state, cancellationToken).ConfigureAwait(false));
            }
 
            return initialReferences.ToImmutable();
        }
 
        /// <summary>
        /// Finds references to <paramref name="symbol"/> in this <paramref name="state"/>, but only if it referenced
        /// though <paramref name="name"/> (which might be the actual name of the type, or a global alias to it).
        /// </summary>
        private static async Task AddNamedReferencesAsync(
            INamespaceSymbol symbol,
            string name,
            FindReferencesDocumentState state,
            ArrayBuilder<FinderLocation> initialReferences,
            CancellationToken cancellationToken)
        {
            var tokens = await FindMatchingIdentifierTokensAsync(
                state, name, cancellationToken).ConfigureAwait(false);
 
            initialReferences.AddRange(await FindReferencesInTokensAsync(
                symbol, state, tokens, cancellationToken).ConfigureAwait(false));
        }
 
        private static async Task AddGlobalNamespaceReferencesAsync(
            INamespaceSymbol symbol,
            FindReferencesDocumentState state,
            ArrayBuilder<FinderLocation> initialReferences,
            CancellationToken cancellationToken)
        {
            var tokens = state.Root
                .DescendantTokens()
                .WhereAsArray(
                    static (token, state) => state.SyntaxFacts.IsGlobalNamespaceKeyword(token),
                    state);
 
            initialReferences.AddRange(await FindReferencesInTokensAsync(
                symbol, state, tokens, cancellationToken).ConfigureAwait(false));
        }
    }
}