private static async Task <ImmutableArray <Project> > GetDependentProjectsWorkerAsync( this ISymbol symbol, Solution solution, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // Find the assembly that this symbol comes from. (Could be a metadata or source // assembly). symbol = symbol.OriginalDefinition; var containingAssembly = symbol.ContainingAssembly; if (containingAssembly == null) { // currently we don't support finding references for a symbol that doesn't have containing assembly symbol return(ImmutableArray <Project> .Empty); } // Find the projects that reference this assembly. // If this is a source symbol from a project, try to find that project. var sourceProject = solution.GetProject(containingAssembly, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); // 1) Compute all the dependent projects (submission + non-submission) and their InternalsVisibleTo semantics to the definition project. ImmutableArray <DependentProject> dependentProjects; var visibility = symbol.GetResultantVisibility(); if (visibility == SymbolVisibility.Private) { dependentProjects = await GetDependentProjectsCoreAsync(symbol, solution, sourceProject, visibility, cancellationToken).ConfigureAwait(false); } else { // We cache the dependent projects for non-private symbols, check in the cache first. var dependentProjectsMap = s_dependentProjectsCache.GetValue(solution, s_createDependentProjectsMapCallback); var key = new DefinitionProject(sourceProjectId: sourceProject?.Id, assemblyName: containingAssembly.Name.ToLower()); if (!dependentProjectsMap.TryGetValue(key, out dependentProjects)) { dependentProjects = await GetDependentProjectsCoreAsync(symbol, solution, sourceProject, visibility, cancellationToken).ConfigureAwait(false); dependentProjectsMap.TryAdd(key, dependentProjects); } } // 2) Filter the above computed dependent projects based on symbol visibility. return(FilterDependentProjectsByVisibility(solution, dependentProjects, visibility)); }
/// <summary> /// This method computes the dependent projects that need to be searched for references of the given <paramref name="symbol"/>. /// This computation depends on the given symbol's visibility: /// 1) Public: Dependent projects include the symbol definition project and all the referencing projects. /// 2) Internal: Dependent projects include the symbol definition project and all the referencing projects that have internals access to the definition project. /// 3) Private: Dependent projects include the symbol definition project and all the referencing submission projects (which are special and can reference private fields of the previous submission). /// /// We perform this computation in two stages: /// 1) Compute all the dependent projects (submission + non-submission) and their InternalsVisibleTo semantics to the definition project. /// 2) Filter the above computed dependent projects based on symbol visibility. /// Dependent projects computed in stage (1) are cached to avoid recomputation. /// </summary> private static async Task<IEnumerable<Project>> GetDependentProjectsWorkerAsync( this ISymbol symbol, Solution solution, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // Find the assembly that this symbol comes from. (Could be a metadata or source // assembly). symbol = symbol.OriginalDefinition; var containingAssembly = symbol.ContainingAssembly; if (containingAssembly == null) { // currently we don't support finding references for a symbol that doesn't have containing assembly symbol return SpecializedCollections.EmptyEnumerable<Project>(); } // Find the projects that reference this assembly. var sourceProject = solution.GetProject(containingAssembly); cancellationToken.ThrowIfCancellationRequested(); // 1) Compute all the dependent projects (submission + non-submission) and their InternalsVisibleTo semantics to the definition project. IEnumerable<DependentProject> dependentProjects; var visibility = symbol.GetResultantVisibility(); if (visibility == SymbolVisibility.Private) { dependentProjects = await GetDependentProjectsCoreAsync(symbol, solution, sourceProject, visibility, cancellationToken).ConfigureAwait(false); } else { // We cache the dependent projects for non-private symbols, check in the cache first. ConcurrentDictionary<DefinitionProject, IEnumerable<DependentProject>> dependentProjectsMap = dependentProjectsCache.GetValue(solution, createDependentProjectsMapCallback); var key = new DefinitionProject(isSourceProject: sourceProject != null, assemblyName: containingAssembly.Name.ToLower()); if (!dependentProjectsMap.TryGetValue(key, out dependentProjects)) { dependentProjects = await GetDependentProjectsCoreAsync(symbol, solution, sourceProject, visibility, cancellationToken).ConfigureAwait(false); dependentProjectsMap.TryAdd(key, dependentProjects); } } // 2) Filter the above computed dependent projects based on symbol visibility. return FilterDependentProjectsByVisibility(solution, dependentProjects, visibility); }