File: FindSymbols\FindReferences\FindReferencesSearchEngine.UnidirectionalSymbolSet.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 Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.FindSymbols
{
    internal partial class FindReferencesSearchEngine
    {
        /// <summary>
        /// Symbol set used when <see cref="FindReferencesSearchOptions.UnidirectionalHierarchyCascade"/> is <see
        /// langword="true"/>.  This symbol set will only cascade in a uniform direction once it walks either up or down
        /// from the initial set of symbols. This is the symbol set used for features like 'Find Refs', where we only
        /// want to return location results for members that could feasible actually end up calling into that member at
        /// runtime.  See the docs of <see cref="FindReferencesSearchOptions.UnidirectionalHierarchyCascade"/> for more
        /// information on this.
        /// </summary>
        private sealed class UnidirectionalSymbolSet : SymbolSet
        {
            private readonly MetadataUnifyingSymbolHashSet _initialAndDownSymbols;
 
            /// <summary>
            /// When we're doing a unidirectional find-references, the initial set of up-symbols can never change.
            /// That's because we have computed the up set entirely up front, and no down symbols can produce new
            /// up-symbols (as going down then up would not be unidirectional).
            /// </summary>
            private readonly ImmutableHashSet<ISymbol> _upSymbols;
 
            public UnidirectionalSymbolSet(
                FindReferencesSearchEngine engine,
                MetadataUnifyingSymbolHashSet initialSymbols,
                MetadataUnifyingSymbolHashSet upSymbols)
                : base(engine)
            {
                _initialAndDownSymbols = initialSymbols;
                _upSymbols = upSymbols.ToImmutableHashSet(MetadataUnifyingEquivalenceComparer.Instance);
            }
 
            public override ImmutableArray<ISymbol> GetAllSymbols()
            {
                var result = new MetadataUnifyingSymbolHashSet();
                result.AddRange(_upSymbols);
                result.AddRange(_initialAndDownSymbols);
                return result.ToImmutableArray();
            }
 
            public override async Task InheritanceCascadeAsync(Project project, CancellationToken cancellationToken)
            {
                // Start searching using the existing set of symbols found at the start (or anything found below that).
                var workQueue = new Stack<ISymbol>();
                workQueue.Push(_initialAndDownSymbols);
 
                var projects = ImmutableHashSet.Create(project);
 
                while (workQueue.Count > 0)
                {
                    var current = workQueue.Pop();
 
                    // Keep adding symbols downwards in this project as long as we keep finding new symbols.
                    await AddDownSymbolsAsync(this.Engine, current, _initialAndDownSymbols, workQueue, projects, cancellationToken).ConfigureAwait(false);
                }
            }
        }
    }
}