Esempio n. 1
0
            /// <summary>
            /// Finds all the symbols 'up' the inheritance hierarchy of <paramref name="symbol"/> in the solution.  The
            /// symbols found are added to <paramref name="seenSymbols"/>.  If <paramref name="seenSymbols"/> did not contain that symbol,
            /// then it is also added to <paramref name="workQueue"/> to allow fixed point algorithms to continue.
            /// </summary>
            protected static async Task AddUpSymbolsAsync(
                FindReferencesSearchEngine engine, ISymbol symbol,
                MetadataUnifyingSymbolHashSet seenSymbols, Stack <ISymbol> workQueue,
                ImmutableHashSet <Project> projects, CancellationToken cancellationToken)
            {
                if (!InvolvesInheritance(symbol))
                {
                    return;
                }

                var solution           = engine._solution;
                var originatingProject = solution.GetOriginatingProject(symbol);

                if (originatingProject != null)
                {
                    // We have a normal method.  Find any interface methods up the inheritance hierarchy that it implicitly
                    // or explicitly implements and cascade to those.
                    foreach (var match in await SymbolFinder.FindImplementedInterfaceMembersArrayAsync(symbol, solution, projects, cancellationToken).ConfigureAwait(false))
                    {
                        await AddCascadedAndLinkedSymbolsToAsync(engine, match, seenSymbols, workQueue, cancellationToken).ConfigureAwait(false);
                    }
                }

                // If we're overriding a member, then add it to the up-set
                if (symbol.GetOverriddenMember() is ISymbol overriddenMember)
                {
                    await AddCascadedAndLinkedSymbolsToAsync(engine, overriddenMember, seenSymbols, workQueue, cancellationToken).ConfigureAwait(false);
                }

                // An explicit interface method will cascade to all the methods that it implements in the up direction.
                await AddCascadedAndLinkedSymbolsToAsync(engine, symbol.ExplicitInterfaceImplementations(), seenSymbols, workQueue, cancellationToken).ConfigureAwait(false);
            }
Esempio n. 2
0
            protected static async Task AddCascadedAndLinkedSymbolsToAsync(
                FindReferencesSearchEngine engine, ISymbol symbol, MetadataUnifyingSymbolHashSet seenSymbols, Stack <ISymbol> workQueue, CancellationToken cancellationToken)
            {
                var solution = engine._solution;

                symbol = await MapAndAddLinkedSymbolsAsync(symbol).ConfigureAwait(false);

                foreach (var finder in engine._finders)
                {
                    var cascaded = await finder.DetermineCascadedSymbolsAsync(symbol, solution, engine._options, cancellationToken).ConfigureAwait(false);

                    foreach (var cascade in cascaded)
                    {
                        await MapAndAddLinkedSymbolsAsync(cascade).ConfigureAwait(false);
                    }
                }

                return;

                async Task <ISymbol> MapAndAddLinkedSymbolsAsync(ISymbol symbol)
                {
                    symbol = await MapToAppropriateSymbolAsync(solution, symbol, cancellationToken).ConfigureAwait(false);

                    foreach (var linked in await SymbolFinder.FindLinkedSymbolsAsync(symbol, solution, cancellationToken).ConfigureAwait(false))
                    {
                        if (seenSymbols.Add(linked))
                        {
                            workQueue.Push(linked);
                        }
                    }

                    return(symbol);
                }
            }
Esempio n. 3
0
            /// <summary>
            /// Finds all the symbols 'down' the inheritance hierarchy of <paramref name="symbol"/> in the given
            /// project.  The symbols found are added to <paramref name="seenSymbols"/>.  If <paramref name="seenSymbols"/> did not
            /// contain that symbol, then it is also added to <paramref name="workQueue"/> to allow fixed point
            /// algorithms to continue.
            /// </summary>
            /// <remarks><paramref name="projects"/> will always be a single project.  We just pass this in as a set to
            /// avoid allocating a fresh set every time this calls into FindMemberImplementationsArrayAsync.
            /// </remarks>
            protected static async Task AddDownSymbolsAsync(
                FindReferencesSearchEngine engine, ISymbol symbol,
                MetadataUnifyingSymbolHashSet seenSymbols, Stack <ISymbol> workQueue,
                ImmutableHashSet <Project> projects, CancellationToken cancellationToken)
            {
                Contract.ThrowIfFalse(projects.Count == 1, "Only a single project should be passed in");

                // Don't bother on symbols that aren't even involved in inheritance computations.
                if (!InvolvesInheritance(symbol))
                {
                    return;
                }

                var solution = engine._solution;

                if (symbol.IsImplementableMember())
                {
                    var implementations = await SymbolFinder.FindMemberImplementationsArrayAsync(
                        symbol, solution, projects, cancellationToken).ConfigureAwait(false);

                    await AddCascadedAndLinkedSymbolsToAsync(engine, implementations, seenSymbols, workQueue, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    var overrrides = await SymbolFinder.FindOverridesArrayAsync(
                        symbol, solution, projects, cancellationToken).ConfigureAwait(false);

                    await AddCascadedAndLinkedSymbolsToAsync(engine, overrrides, seenSymbols, workQueue, cancellationToken).ConfigureAwait(false);
                }
            }
Esempio n. 4
0
            public override ImmutableArray <ISymbol> GetAllSymbols()
            {
                var result = new MetadataUnifyingSymbolHashSet();

                result.AddRange(_upSymbols);
                result.AddRange(_initialAndDownSymbols);
                return(result.ToImmutableArray());
            }
Esempio n. 5
0
 protected static async Task AddCascadedAndLinkedSymbolsToAsync(
     FindReferencesSearchEngine engine, ImmutableArray <ISymbol> symbols, MetadataUnifyingSymbolHashSet seenSymbols, Stack <ISymbol> workQueue, CancellationToken cancellationToken)
 {
     foreach (var symbol in symbols)
     {
         await AddCascadedAndLinkedSymbolsToAsync(engine, symbol, seenSymbols, workQueue, cancellationToken).ConfigureAwait(false);
     }
 }
Esempio n. 6
0
 public BidirectionalSymbolSet(
     FindReferencesSearchEngine engine,
     MetadataUnifyingSymbolHashSet initialSymbols,
     MetadataUnifyingSymbolHashSet upSymbols)
     : base(engine)
 {
     _allSymbols.AddRange(initialSymbols);
     _allSymbols.AddRange(upSymbols);
 }
Esempio n. 7
0
 public UnidirectionalSymbolSet(
     FindReferencesSearchEngine engine,
     MetadataUnifyingSymbolHashSet initialSymbols,
     MetadataUnifyingSymbolHashSet upSymbols)
     : base(engine)
 {
     _initialAndDownSymbols = initialSymbols;
     _upSymbols             = upSymbols.ToImmutableHashSet(MetadataUnifyingEquivalenceComparer.Instance);
 }
Esempio n. 8
0
            /// <summary>
            /// Determines the initial set of symbols that we should actually be finding references for given a request
            /// to find refs to <paramref name="symbol"/>.  This will include any symbols that a specific <see
            /// cref="IReferenceFinder"/> cascades to, as well as all the linked symbols to those across any
            /// multi-targetting/shared-project documents.  This will not include symbols up or down the inheritance
            /// hierarchy.
            /// </summary>
            private static async Task <MetadataUnifyingSymbolHashSet> DetermineInitialSearchSymbolsAsync(
                FindReferencesSearchEngine engine, ISymbol symbol, CancellationToken cancellationToken)
            {
                var result    = new MetadataUnifyingSymbolHashSet();
                var workQueue = new Stack <ISymbol>();

                // Start with the initial symbol we're searching for.
                workQueue.Push(symbol);

                // As long as there's work in the queue, keep going.
                while (workQueue.Count > 0)
                {
                    var currentSymbol = workQueue.Pop();
                    await AddCascadedAndLinkedSymbolsToAsync(engine, currentSymbol, result, workQueue, cancellationToken).ConfigureAwait(false);
                }

                return(result);
            }
Esempio n. 9
0
            private static async Task <HashSet <ISymbol> > DetermineInitialUpSymbolsAsync(
                FindReferencesSearchEngine engine, HashSet <ISymbol> initialSymbols, CancellationToken cancellationToken)
            {
                var upSymbols = new MetadataUnifyingSymbolHashSet();
                var workQueue = new Stack <ISymbol>();

                workQueue.Push(initialSymbols);

                var solution    = engine._solution;
                var allProjects = solution.Projects.ToImmutableHashSet();

                while (workQueue.Count > 0)
                {
                    var currentSymbol = workQueue.Pop();
                    await AddUpSymbolsAsync(engine, currentSymbol, upSymbols, workQueue, allProjects, cancellationToken).ConfigureAwait(false);
                }

                return(upSymbols);
            }
 public UnidirectionalSymbolSet(FindReferencesSearchEngine engine, MetadataUnifyingSymbolHashSet initialSymbols, HashSet <ISymbol> upSymbols)
     : base(engine)
 {
     _initialAndDownSymbols = initialSymbols;
     _upSymbols             = upSymbols.ToImmutableHashSet();
 }
 public NonCascadingSymbolSet(FindReferencesSearchEngine engine, MetadataUnifyingSymbolHashSet searchSymbols) : base(engine)
     => _symbols = searchSymbols.ToImmutableArray();