未验证 提交 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 @@ ...@@ -5,7 +5,6 @@
#nullable enable #nullable enable
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
...@@ -13,29 +12,17 @@ ...@@ -13,29 +12,17 @@
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols.DependentProjects;
using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities; using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols namespace Microsoft.CodeAnalysis.FindSymbols
{ {
using DependentProjectMap = ConcurrentDictionary<DefinitionProject, AsyncLazy<ImmutableArray<DependentProject>>>;
/// <summary> /// <summary>
/// Provides helper methods for finding dependent projects across a solution that a given symbol can be referenced within. /// Provides helper methods for finding dependent projects across a solution that a given symbol can be referenced within.
/// </summary> /// </summary>
internal static partial class DependentProjectsFinder 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( public static async Task<ImmutableArray<Project>> GetDependentProjectsAsync(
Solution solution, ISymbol symbol, IImmutableSet<Project>? projects, CancellationToken cancellationToken) Solution solution, ISymbol symbol, IImmutableSet<Project>? projects, CancellationToken cancellationToken)
{ {
...@@ -79,32 +66,17 @@ internal static partial class DependentProjectsFinder ...@@ -79,32 +66,17 @@ internal static partial class DependentProjectsFinder
return ImmutableArray<Project>.Empty; return ImmutableArray<Project>.Empty;
// 1) Compute all the dependent projects (submission + non-submission) and their InternalsVisibleTo semantics to the definition project. // 1) Compute all the dependent projects (submission + non-submission) and their InternalsVisibleTo semantics to the definition project.
var symbolVisibility = symbol.GetResultantVisibility();
var visibility = symbol.GetResultantVisibility(); var dependentProjects = await ComputeDependentProjectsAsync(
if (visibility == SymbolVisibility.Private) solution, symbolOrigination, symbolVisibility, cancellationToken).ConfigureAwait(false);
{
// 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);
// 2) Filter the above computed dependent projects based on symbol visibility. // 2) Filter the above computed dependent projects based on symbol visibility.
return GetProjects(solution, visibility == SymbolVisibility.Internal var filteredProjects = symbolVisibility == SymbolVisibility.Internal
? dependentProjects.WhereAsArray(dp => dp.HasInternalsAccess) ? dependentProjects.WhereAsArray(dp => dp.hasInternalsAccess)
: dependentProjects); : dependentProjects;
}
private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableArray<DependentProject> dependentProjects) return filteredProjects.SelectAsArray(t => t.project);
=> dependentProjects.SelectAsArray(dp => solution.GetRequiredProject(dp.ProjectId)); }
/// <summary> /// <summary>
/// Returns a pair of data bout where <paramref name="symbol"/> originates from. It's <see /// 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 ...@@ -118,7 +90,7 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
return assembly == null ? default : (assembly, solution.GetProject(assembly, cancellationToken)); 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, Solution solution,
(IAssemblySymbol assembly, Project? sourceProject) symbolOrigination, (IAssemblySymbol assembly, Project? sourceProject) symbolOrigination,
SymbolVisibility visibility, SymbolVisibility visibility,
...@@ -126,12 +98,12 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA ...@@ -126,12 +98,12 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
{ {
cancellationToken.ThrowIfCancellationRequested(); 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 // If a symbol was defined in source, then it is always visible to the project it
// was defined in. // was defined in.
if (symbolOrigination.sourceProject != null) 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 it's not private, then we need to find possible references.
if (visibility != SymbolVisibility.Private) if (visibility != SymbolVisibility.Private)
...@@ -145,7 +117,7 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA ...@@ -145,7 +117,7 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
} }
private static async Task AddSubmissionDependentProjectsAsync( 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) if (sourceProject?.IsSubmission != true)
return; return;
...@@ -187,7 +159,7 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA ...@@ -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 // 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 // our current set of projects and find the transitive closure over backwards
// submission previous references. // 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) while (projectIdsToProcess.Count > 0)
{ {
...@@ -197,9 +169,9 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA ...@@ -197,9 +169,9 @@ private static ImmutableArray<Project> GetProjects(Solution solution, ImmutableA
{ {
foreach (var pId in submissionIds) 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); projectIdsToProcess.Push(pId);
} }
} }
...@@ -220,7 +192,7 @@ private static bool IsInternalsVisibleToAttribute(AttributeData attr) ...@@ -220,7 +192,7 @@ private static bool IsInternalsVisibleToAttribute(AttributeData attr)
private static void AddNonSubmissionDependentProjects( private static void AddNonSubmissionDependentProjects(
Solution solution, Solution solution,
(IAssemblySymbol assembly, Project? sourceProject) symbolOrigination, (IAssemblySymbol assembly, Project? sourceProject) symbolOrigination,
HashSet<DependentProject> dependentProjects, HashSet<(Project project, bool hasInternalsAccess)> dependentProjects,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (symbolOrigination.sourceProject?.IsSubmission == true) if (symbolOrigination.sourceProject?.IsSubmission == true)
...@@ -239,8 +211,8 @@ private static bool IsInternalsVisibleToAttribute(AttributeData attr) ...@@ -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 // 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. // if it can see internals or not as well.
internalsVisibleToSet ??= GetInternalsVisibleToSet(symbolOrigination.assembly); internalsVisibleToSet ??= GetInternalsVisibleToSet(symbolOrigination.assembly);
var internalsVisibleTo = internalsVisibleToSet.Contains(project.AssemblyName); var hasInternalsAccess = internalsVisibleToSet.Contains(project.AssemblyName);
dependentProjects.Add(new DependentProject(project.Id, internalsVisibleTo)); dependentProjects.Add((project, hasInternalsAccess));
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册