未验证 提交 8c3d23d3 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #45116 from CyrusNajmabadi/removeCaching2

Remove unnecessary caching
// 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.
#nullable enable
using System;
using System.Collections.Generic;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols.DependentProjects
{
/// <summary>
/// The name of the assembly, and optionally also the project, that a symbol came from. Used in the <see
/// cref="DependentProjectsFinder"/> to quickly find which set of projects in a solution should searched when
/// looking at symbols from that same location.
/// </summary>
internal readonly struct DefinitionProject : IEquatable<DefinitionProject>
{
private readonly ProjectId? _sourceProjectId;
private readonly string _assemblyName;
public DefinitionProject(ProjectId? sourceProjectId, string assemblyName)
{
_sourceProjectId = sourceProjectId;
_assemblyName = assemblyName;
}
public override bool Equals(object? obj)
=> obj is DefinitionProject project && Equals(project);
public bool Equals(DefinitionProject other)
=> EqualityComparer<ProjectId?>.Default.Equals(_sourceProjectId, other._sourceProjectId) &&
_assemblyName == other._assemblyName;
public override int GetHashCode()
=> Hash.Combine(_sourceProjectId, _assemblyName.GetHashCode());
}
}
// 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.
#nullable enable
using System;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols.DependentProjects
{
/// <summary>
/// Represents a project that depends on some assembly, and if that project can see the internal symbols of that
/// assembly or not.
/// </summary>
internal readonly struct DependentProject : IEquatable<DependentProject>
{
public readonly ProjectId ProjectId;
public readonly bool HasInternalsAccess;
public DependentProject(ProjectId dependentProjectId, bool hasInternalsAccess)
{
this.ProjectId = dependentProjectId;
this.HasInternalsAccess = hasInternalsAccess;
}
public override bool Equals(object? obj)
=> obj is DependentProject project && this.Equals(project);
public override int GetHashCode()
=> Hash.Combine(HasInternalsAccess, ProjectId.GetHashCode());
public bool Equals(DependentProject other)
=> HasInternalsAccess == other.HasInternalsAccess && ProjectId.Equals(other.ProjectId);
}
}
......@@ -5,7 +5,6 @@
#nullable enable
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
......@@ -13,29 +12,17 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols.DependentProjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
using DependentProjectMap = ConcurrentDictionary<DefinitionProject, AsyncLazy<ImmutableArray<DependentProject>>>;
/// <summary>
/// Provides helper methods for finding dependent projects across a solution that a given symbol can be referenced within.
/// </summary>
internal static partial class DependentProjectsFinder
{
/// <summary>
/// Dependent projects cache.
/// For a given solution, maps from an assembly (source-project or metadata-assembly) to the set of projects referencing it.
/// Key: DefinitionProject, which contains the project-id for a source-project-assembly, or assembly-name for a metadata-assembly.
/// Value: List of DependentProjects, where each DependentProject contains a dependent project ID and a flag indicating whether the dependent project has internals access to definition project.
/// </summary>
private static readonly ConditionalWeakTable<Solution, DependentProjectMap> s_dependentProjectsCache =
new ConditionalWeakTable<Solution, DependentProjectMap>();
public static async Task<ImmutableArray<Project>> GetDependentProjectsAsync(
Solution solution, ISymbol symbol, IImmutableSet<Project>? projects, CancellationToken cancellationToken)
{
......@@ -79,32 +66,17 @@ internal static partial class DependentProjectsFinder
return ImmutableArray<Project>.Empty;
// 1) Compute all the dependent projects (submission + non-submission) and their InternalsVisibleTo semantics to the definition project.
var visibility = symbol.GetResultantVisibility();
if (visibility == SymbolVisibility.Private)
{
// For private symbols, we only need the current project (and related submissions). No need to cache
// that, just simply compute and return the result.
return GetProjects(solution, await ComputeDependentProjectsAsync(solution, symbolOrigination, visibility, cancellationToken).ConfigureAwait(false));
}
// Otherwise, for non-private symbols, we cache the dependent projects for non-private symbols to speed up
// future calls.
var dependentProjectsMap = s_dependentProjectsCache.GetValue(solution, _ => new DependentProjectMap());
var asyncLazy = dependentProjectsMap.GetOrAdd(
new DefinitionProject(symbolOrigination.sourceProject?.Id, symbolOrigination.assembly.Name.ToLower()),
_ => AsyncLazy.Create(c => ComputeDependentProjectsAsync(solution, symbolOrigination, visibility, c), cacheResult: true));
var dependentProjects = await asyncLazy.GetValueAsync(cancellationToken).ConfigureAwait(false);
var symbolVisibility = symbol.GetResultantVisibility();
var dependentProjects = await ComputeDependentProjectsAsync(
solution, symbolOrigination, symbolVisibility, cancellationToken).ConfigureAwait(false);
// 2) Filter the above computed dependent projects based on symbol visibility.
return GetProjects(solution, visibility == SymbolVisibility.Internal
? dependentProjects.WhereAsArray(dp => dp.HasInternalsAccess)
: dependentProjects);
}
var filteredProjects = symbolVisibility == SymbolVisibility.Internal
? dependentProjects.WhereAsArray(dp => dp.hasInternalsAccess)
: dependentProjects;
private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableArray<DependentProject> dependentProjects)
=> dependentProjects.SelectAsArray(dp => solution.GetRequiredProject(dp.ProjectId));
return filteredProjects.SelectAsArray(t => t.project);
}
/// <summary>
/// Returns a pair of data bout where <paramref name="symbol"/> originates from. It's <see
......@@ -118,7 +90,7 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
return assembly == null ? default : (assembly, solution.GetProject(assembly, cancellationToken));
}
private static async Task<ImmutableArray<DependentProject>> ComputeDependentProjectsAsync(
private static async Task<ImmutableArray<(Project project, bool hasInternalsAccess)>> ComputeDependentProjectsAsync(
Solution solution,
(IAssemblySymbol assembly, Project? sourceProject) symbolOrigination,
SymbolVisibility visibility,
......@@ -126,12 +98,12 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
{
cancellationToken.ThrowIfCancellationRequested();
var dependentProjects = new HashSet<DependentProject>();
var dependentProjects = new HashSet<(Project, bool hasInternalsAccess)>();
// If a symbol was defined in source, then it is always visible to the project it
// was defined in.
if (symbolOrigination.sourceProject != null)
dependentProjects.Add(new DependentProject(symbolOrigination.sourceProject.Id, hasInternalsAccess: true));
dependentProjects.Add((symbolOrigination.sourceProject, hasInternalsAccess: true));
// If it's not private, then we need to find possible references.
if (visibility != SymbolVisibility.Private)
......@@ -145,7 +117,7 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
}
private static async Task AddSubmissionDependentProjectsAsync(
Solution solution, Project? sourceProject, HashSet<DependentProject> dependentProjects, CancellationToken cancellationToken)
Solution solution, Project? sourceProject, HashSet<(Project project, bool hasInternalsAccess)> dependentProjects, CancellationToken cancellationToken)
{
if (sourceProject?.IsSubmission != true)
return;
......@@ -187,7 +159,7 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
// and 2, even though 2 doesn't have a direct reference to 1. Hence we need to take
// our current set of projects and find the transitive closure over backwards
// submission previous references.
var projectIdsToProcess = new Stack<ProjectId>(dependentProjects.Select(dp => dp.ProjectId));
var projectIdsToProcess = new Stack<ProjectId>(dependentProjects.Select(dp => dp.project.Id));
while (projectIdsToProcess.Count > 0)
{
......@@ -197,9 +169,9 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
{
foreach (var pId in submissionIds)
{
if (!dependentProjects.Any(dp => dp.ProjectId == pId))
if (!dependentProjects.Any(dp => dp.project.Id == pId))
{
dependentProjects.Add(new DependentProject(pId, hasInternalsAccess: true));
dependentProjects.Add((solution.GetRequiredProject(pId), hasInternalsAccess: true));
projectIdsToProcess.Push(pId);
}
}
......@@ -220,7 +192,7 @@ private static bool IsInternalsVisibleToAttribute(AttributeData attr)
private static void AddNonSubmissionDependentProjects(
Solution solution,
(IAssemblySymbol assembly, Project? sourceProject) symbolOrigination,
HashSet<DependentProject> dependentProjects,
HashSet<(Project project, bool hasInternalsAccess)> dependentProjects,
CancellationToken cancellationToken)
{
if (symbolOrigination.sourceProject?.IsSubmission == true)
......@@ -239,8 +211,8 @@ private static bool IsInternalsVisibleToAttribute(AttributeData attr)
// Ok, we have some project that at least references this assembly. Add it to the result, keeping track
// if it can see internals or not as well.
internalsVisibleToSet ??= GetInternalsVisibleToSet(symbolOrigination.assembly);
var internalsVisibleTo = internalsVisibleToSet.Contains(project.AssemblyName);
dependentProjects.Add(new DependentProject(project.Id, internalsVisibleTo));
var hasInternalsAccess = internalsVisibleToSet.Contains(project.AssemblyName);
dependentProjects.Add((project, hasInternalsAccess));
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册