private async Task <ProjectMap> CreateProjectMapAsync(ConcurrentSet <SymbolGroup> symbolGroups, CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.FindReference_CreateProjectMapAsync, cancellationToken)) { var projectMap = new ProjectMap(); var scope = _documents?.Select(d => d.Project).ToImmutableHashSet(); foreach (var symbolGroup in symbolGroups) { foreach (var symbol in symbolGroup.Symbols) { cancellationToken.ThrowIfCancellationRequested(); var projects = await DependentProjectsFinder.GetDependentProjectsAsync( _solution, symbol, scope, cancellationToken).ConfigureAwait(false); foreach (var project in projects.Distinct().WhereNotNull()) { if (scope == null || scope.Contains(project)) { projectMap.MultiAdd(project, symbol); } } } } Contract.ThrowIfTrue(projectMap.Any(kvp => kvp.Value.Count != kvp.Value.ToSet().Count)); return(projectMap); } }
private static async Task <ISet <ProjectId> > GetProjectsThatCouldReferenceTypeAsync( INamedTypeSymbol type, Solution solution, bool searchInMetadata, CancellationToken cancellationToken ) { var dependencyGraph = solution.GetProjectDependencyGraph(); if (searchInMetadata) { // For a metadata type, find all projects that refer to the metadata assembly that // the type is defined in. Note: we pass 'null' for projects intentionally. We // Need to find all the possible projects that contain this metadata. var projectsThatReferenceMetadataAssembly = await DependentProjectsFinder .GetDependentProjectsAsync( solution, type, projects : null, cancellationToken : cancellationToken ) .ConfigureAwait(false); // Now collect all the dependent projects as well. var projectsThatCouldReferenceType = projectsThatReferenceMetadataAssembly .SelectMany(p => GetProjectsThatCouldReferenceType(dependencyGraph, p)) .ToSet(); return(projectsThatCouldReferenceType); } else { // For a source project, find the project that that type was defined in. var sourceProject = solution.GetProject(type.ContainingAssembly, cancellationToken); if (sourceProject == null) { return(SpecializedCollections.EmptySet <ProjectId>()); } // Now find all the dependent of those projects. var projectsThatCouldReferenceType = GetProjectsThatCouldReferenceType( dependencyGraph, sourceProject ) .ToSet(); return(projectsThatCouldReferenceType); } }
private static async Task <IEnumerable <INamedTypeSymbol> > GetDependentTypesAsync( INamedTypeSymbol type, Solution solution, IImmutableSet <Project> projects, Func <INamedTypeSymbol, INamedTypeSymbol, bool> predicate, ConditionalWeakTable <Compilation, ConcurrentDictionary <SymbolKey, List <SymbolKey> > > cache, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var dependentProjects = await DependentProjectsFinder.GetDependentProjectsAsync(type, solution, projects, cancellationToken).ConfigureAwait(false); // If it's a type from source, then only other types from source could derive from // it. If it's a type from metadata then unfortunately anything could derive from // it. bool locationsInMetadata = type.Locations.Any(loc => loc.IsInMetadata); ConcurrentSet <ISymbol> results = new ConcurrentSet <ISymbol>(SymbolEquivalenceComparer.Instance); cancellationToken.ThrowIfCancellationRequested(); var projectTasks = new List <Task>(); foreach (var project in dependentProjects) { projectTasks.Add(Task.Run( async() => await GetDependentTypesInProjectAsync(type, project, solution, predicate, cache, locationsInMetadata, results, cancellationToken).ConfigureAwait(false), cancellationToken)); } await Task.WhenAll(projectTasks).ConfigureAwait(false); if (results.Any()) { return(results.OfType <INamedTypeSymbol>()); } else { return(SpecializedCollections.EmptyEnumerable <INamedTypeSymbol>()); } }