/// <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); }
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); } }
/// <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); } }
public override ImmutableArray <ISymbol> GetAllSymbols() { var result = new MetadataUnifyingSymbolHashSet(); result.AddRange(_upSymbols); result.AddRange(_initialAndDownSymbols); return(result.ToImmutableArray()); }
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); } }
public BidirectionalSymbolSet( FindReferencesSearchEngine engine, MetadataUnifyingSymbolHashSet initialSymbols, MetadataUnifyingSymbolHashSet upSymbols) : base(engine) { _allSymbols.AddRange(initialSymbols); _allSymbols.AddRange(upSymbols); }
public UnidirectionalSymbolSet( FindReferencesSearchEngine engine, MetadataUnifyingSymbolHashSet initialSymbols, MetadataUnifyingSymbolHashSet upSymbols) : base(engine) { _initialAndDownSymbols = initialSymbols; _upSymbols = upSymbols.ToImmutableHashSet(MetadataUnifyingEquivalenceComparer.Instance); }
/// <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); }
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();