提交 889966ca 编写于 作者: C Cyrus Najmabadi

Keep track of associated project when finding symbols for faster lookup.

上级 ace6dbc2
...@@ -53,7 +53,8 @@ internal static partial class DependentTypeFinder ...@@ -53,7 +53,8 @@ internal static partial class DependentTypeFinder
private static readonly Func<INamedTypeSymbol, bool> s_isNonSealedClass = t => t?.TypeKind == TypeKind.Class && !t.IsSealed; private static readonly Func<INamedTypeSymbol, bool> s_isNonSealedClass = t => t?.TypeKind == TypeKind.Class && !t.IsSealed;
private static readonly Func<INamedTypeSymbol, bool> s_isInterfaceOrNonSealedClass = t => s_isInterface(t) || s_isNonSealedClass(t); private static readonly Func<INamedTypeSymbol, bool> s_isInterfaceOrNonSealedClass = t => s_isInterface(t) || s_isNonSealedClass(t);
private static readonly ObjectPool<PooledHashSet<INamedTypeSymbol>> s_setPool1 = PooledHashSet<INamedTypeSymbol>.CreatePool(SymbolEquivalenceComparer.Instance); private static readonly ObjectPool<PooledHashSet<INamedTypeSymbol>> s_symbolSetPool = PooledHashSet<INamedTypeSymbol>.CreatePool(SymbolEquivalenceComparer.Instance);
private static readonly ObjectPool<PooledDictionary<INamedTypeSymbol, Project>> s_symbolToProjectPool = PooledDictionary<INamedTypeSymbol, Project>.CreatePool(SymbolEquivalenceComparer.Instance);
// Caches from a types to their related types (in the context of a specific solution). // Caches from a types to their related types (in the context of a specific solution).
// Kept as a cache so that clients who make many calls into us won't end up computing // Kept as a cache so that clients who make many calls into us won't end up computing
...@@ -84,7 +85,7 @@ internal static partial class DependentTypeFinder ...@@ -84,7 +85,7 @@ internal static partial class DependentTypeFinder
Solution solution, Solution solution,
IImmutableSet<Project> projects, IImmutableSet<Project> projects,
RelatedTypeCache cache, RelatedTypeCache cache,
Func<CancellationToken, Task<ImmutableArray<INamedTypeSymbol>>> findAsync, Func<CancellationToken, Task<ImmutableArray<(INamedTypeSymbol, Project)>>> findAsync,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var dictionary = cache.GetValue(solution, s_createTypeMap); var dictionary = cache.GetValue(solution, s_createTypeMap);
...@@ -96,7 +97,7 @@ internal static partial class DependentTypeFinder ...@@ -96,7 +97,7 @@ internal static partial class DependentTypeFinder
{ {
lazy = dictionary.GetOrAdd(key, lazy = dictionary.GetOrAdd(key,
new AsyncLazy<ImmutableArray<(SymbolKey, ProjectId)>>( new AsyncLazy<ImmutableArray<(SymbolKey, ProjectId)>>(
c => GetSymbolKeysAndProjectIdsAsync(solution, findAsync, c), c => GetSymbolKeysAndProjectIdsAsync(findAsync, c),
cacheResult: true)); cacheResult: true));
} }
...@@ -138,8 +139,7 @@ internal static partial class DependentTypeFinder ...@@ -138,8 +139,7 @@ internal static partial class DependentTypeFinder
} }
private static async Task<ImmutableArray<(SymbolKey, ProjectId)>> GetSymbolKeysAndProjectIdsAsync( private static async Task<ImmutableArray<(SymbolKey, ProjectId)>> GetSymbolKeysAndProjectIdsAsync(
Solution solution, Func<CancellationToken, Task<ImmutableArray<(INamedTypeSymbol, Project)>>> findAsync,
Func<CancellationToken, Task<ImmutableArray<INamedTypeSymbol>>> findAsync,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
// If we're the code that is actually computing the symbols, then just // If we're the code that is actually computing the symbols, then just
...@@ -147,7 +147,7 @@ internal static partial class DependentTypeFinder ...@@ -147,7 +147,7 @@ internal static partial class DependentTypeFinder
// doesn't need to incur the cost of deserializing the symbol keys that // doesn't need to incur the cost of deserializing the symbol keys that
// we're create right below this. // we're create right below this.
var result = await findAsync(cancellationToken).ConfigureAwait(false); var result = await findAsync(cancellationToken).ConfigureAwait(false);
return result.SelectAsArray(t => (t.GetSymbolKey(), solution.GetOriginatingProjectId(t))); return result.SelectAsArray(t => (t.Item1.GetSymbolKey(), t.Item2.Id));
} }
/// <summary> /// <summary>
...@@ -159,7 +159,7 @@ internal static partial class DependentTypeFinder ...@@ -159,7 +159,7 @@ internal static partial class DependentTypeFinder
/// inherit from it that would match this search.</param> /// inherit from it that would match this search.</param>
/// <param name="transitive">If this search after finding the direct inherited types that match the provided /// <param name="transitive">If this search after finding the direct inherited types that match the provided
/// predicate, or if the search should continue recursively using those types as the starting point.</param> /// predicate, or if the search should continue recursively using those types as the starting point.</param>
private static async Task<ImmutableArray<INamedTypeSymbol>> DescendInheritanceTreeAsync( private static async Task<ImmutableArray<(INamedTypeSymbol, Project)>> DescendInheritanceTreeAsync(
INamedTypeSymbol type, INamedTypeSymbol type,
Solution solution, Solution solution,
IImmutableSet<Project> projects, IImmutableSet<Project> projects,
...@@ -200,9 +200,8 @@ internal static partial class DependentTypeFinder ...@@ -200,9 +200,8 @@ internal static partial class DependentTypeFinder
var orderedProjectsToExamine = GetOrderedProjectsToExamine( var orderedProjectsToExamine = GetOrderedProjectsToExamine(
solution, projects, projectsThatCouldReferenceType); solution, projects, projectsThatCouldReferenceType);
// The final set of results we'll be returning. // The final set of results we'll be returning.
using var _1 = GetSymbolSet(out var result); using var _1 = GetSymbolToProjectMap(out var result);
// The current total set of matching metadata types in the descendant tree (including the initial type if it // The current total set of matching metadata types in the descendant tree (including the initial type if it
// is from metadata). Will be used when examining new types to see if they inherit from any of these. // is from metadata). Will be used when examining new types to see if they inherit from any of these.
...@@ -236,12 +235,12 @@ internal static partial class DependentTypeFinder ...@@ -236,12 +235,12 @@ internal static partial class DependentTypeFinder
transitive, cancellationToken).ConfigureAwait(false); transitive, cancellationToken).ConfigureAwait(false);
} }
return result.ToImmutableArray(); return result.SelectAsArray(kvp => (kvp.Key, kvp.Value));
} }
private static async Task DescendInheritanceTreeInProjectAsync( private static async Task DescendInheritanceTreeInProjectAsync(
bool searchInMetadata, bool searchInMetadata,
SymbolSet result, Dictionary<INamedTypeSymbol, Project> result,
SymbolSet currentMetadataTypes, SymbolSet currentMetadataTypes,
SymbolSet currentSourceAndMetadataTypes, SymbolSet currentSourceAndMetadataTypes,
Project project, Project project,
...@@ -272,7 +271,7 @@ internal static partial class DependentTypeFinder ...@@ -272,7 +271,7 @@ internal static partial class DependentTypeFinder
// Add all the matches we found to the result set. // Add all the matches we found to the result set.
AssertContents(tempBuffer, assert: s_isInMetadata, "Found type was not from metadata"); AssertContents(tempBuffer, assert: s_isInMetadata, "Found type was not from metadata");
AddRange(tempBuffer, result); AddRange(tempBuffer, project, result);
// Now, if we're doing a transitive search, add these found types to the 'current' sets we're // Now, if we're doing a transitive search, add these found types to the 'current' sets we're
// searching for more results for. These will then be used when searching for more types in the next // searching for more results for. These will then be used when searching for more types in the next
...@@ -299,7 +298,7 @@ internal static partial class DependentTypeFinder ...@@ -299,7 +298,7 @@ internal static partial class DependentTypeFinder
// Add all the matches we found to the result set. // Add all the matches we found to the result set.
AssertContents(tempBuffer, assert: s_isInSource, "Found type was not from source"); AssertContents(tempBuffer, assert: s_isInSource, "Found type was not from source");
AddRange(tempBuffer, result); AddRange(tempBuffer, project, result);
// Now, if we're doing a transitive search, add these types to the currentSourceAndMetadataTypes // Now, if we're doing a transitive search, add these types to the currentSourceAndMetadataTypes
// set. These will then be used when searching for more types in the next project (which our caller // set. These will then be used when searching for more types in the next project (which our caller
...@@ -318,11 +317,11 @@ internal static partial class DependentTypeFinder ...@@ -318,11 +317,11 @@ internal static partial class DependentTypeFinder
Debug.Assert(type.Locations.All(assert), message); Debug.Assert(type.Locations.All(assert), message);
} }
private static void AddRange(SymbolSet foundTypes, SymbolSet result) private static void AddRange(SymbolSet foundTypes, Project project, Dictionary<INamedTypeSymbol, Project> result)
{ {
// Directly enumerate to avoid IEnumerator allocations. // Directly enumerate to avoid IEnumerator allocations.
foreach (var type in foundTypes) foreach (var type in foundTypes)
result.Add(type); result[type] = project;
} }
private static void AddRange(SymbolSet foundTypes, SymbolSet currentTypes, Func<INamedTypeSymbol, bool> shouldContinueSearching) private static void AddRange(SymbolSet foundTypes, SymbolSet currentTypes, Func<INamedTypeSymbol, bool> shouldContinueSearching)
...@@ -722,10 +721,18 @@ private static bool TypeHasInterfaceInSet(INamedTypeSymbol type, SymbolSet set) ...@@ -722,10 +721,18 @@ private static bool TypeHasInterfaceInSet(INamedTypeSymbol type, SymbolSet set)
public static PooledDisposer<PooledHashSet<INamedTypeSymbol>> GetSymbolSet(out SymbolSet instance) public static PooledDisposer<PooledHashSet<INamedTypeSymbol>> GetSymbolSet(out SymbolSet instance)
{ {
var pooledInstance = s_setPool1.Allocate(); var pooledInstance = s_symbolSetPool.Allocate();
Debug.Assert(pooledInstance.Count == 0); Debug.Assert(pooledInstance.Count == 0);
instance = pooledInstance; instance = pooledInstance;
return new PooledDisposer<PooledHashSet<INamedTypeSymbol>>(pooledInstance); return new PooledDisposer<PooledHashSet<INamedTypeSymbol>>(pooledInstance);
} }
public static PooledDisposer<PooledDictionary<INamedTypeSymbol, Project>> GetSymbolToProjectMap(out Dictionary<INamedTypeSymbol, Project> instance)
{
var pooledInstance = s_symbolToProjectPool.Allocate();
Debug.Assert(pooledInstance.Count == 0);
instance = pooledInstance;
return new PooledDisposer<PooledDictionary<INamedTypeSymbol, Project>>(pooledInstance);
}
} }
} }
...@@ -49,7 +49,7 @@ internal static partial class DependentTypeFinder ...@@ -49,7 +49,7 @@ internal static partial class DependentTypeFinder
cancellationToken); cancellationToken);
} }
private static Task<ImmutableArray<INamedTypeSymbol>> FindWithoutCachingDerivedClassesAsync( private static Task<ImmutableArray<(INamedTypeSymbol, Project)>> FindWithoutCachingDerivedClassesAsync(
INamedTypeSymbol type, INamedTypeSymbol type,
Solution solution, Solution solution,
IImmutableSet<Project> projects, IImmutableSet<Project> projects,
...@@ -68,7 +68,7 @@ static bool TypeMatches(INamedTypeSymbol type, SymbolSet set) ...@@ -68,7 +68,7 @@ static bool TypeMatches(INamedTypeSymbol type, SymbolSet set)
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
} }
return SpecializedTasks.EmptyImmutableArray<INamedTypeSymbol>(); return SpecializedTasks.EmptyImmutableArray<(INamedTypeSymbol, Project)>();
} }
} }
} }
...@@ -49,7 +49,7 @@ internal static partial class DependentTypeFinder ...@@ -49,7 +49,7 @@ internal static partial class DependentTypeFinder
cancellationToken); cancellationToken);
} }
private static Task<ImmutableArray<INamedTypeSymbol>> FindWithoutCachingDerivedInterfacesAsync( private static Task<ImmutableArray<(INamedTypeSymbol, Project)>> FindWithoutCachingDerivedInterfacesAsync(
INamedTypeSymbol type, INamedTypeSymbol type,
Solution solution, Solution solution,
IImmutableSet<Project> projects, IImmutableSet<Project> projects,
...@@ -69,7 +69,7 @@ static bool TypeMatches(INamedTypeSymbol type, SymbolSet set) ...@@ -69,7 +69,7 @@ static bool TypeMatches(INamedTypeSymbol type, SymbolSet set)
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
} }
return SpecializedTasks.EmptyImmutableArray<INamedTypeSymbol>(); return SpecializedTasks.EmptyImmutableArray<(INamedTypeSymbol, Project)>();
} }
} }
} }
...@@ -48,7 +48,7 @@ internal static partial class DependentTypeFinder ...@@ -48,7 +48,7 @@ internal static partial class DependentTypeFinder
cancellationToken); cancellationToken);
} }
private static async Task<ImmutableArray<INamedTypeSymbol>> FindWithoutCachingImplementingTypesAsync( private static async Task<ImmutableArray<(INamedTypeSymbol, Project)>> FindWithoutCachingImplementingTypesAsync(
INamedTypeSymbol type, INamedTypeSymbol type,
Solution solution, Solution solution,
IImmutableSet<Project> projects, IImmutableSet<Project> projects,
...@@ -88,13 +88,13 @@ static bool TypeMatches(INamedTypeSymbol type, SymbolSet set) ...@@ -88,13 +88,13 @@ static bool TypeMatches(INamedTypeSymbol type, SymbolSet set)
// FindDerivedInterfacesAsync. Delegates/Enums only happen in a few corner cases. For example, enums // FindDerivedInterfacesAsync. Delegates/Enums only happen in a few corner cases. For example, enums
// implement IComparable, and delegates implement ICloneable. // implement IComparable, and delegates implement ICloneable.
return allTypes.WhereAsArray( return allTypes.WhereAsArray(
t => t.TypeKind == TypeKind.Class || t => t.Item1.TypeKind == TypeKind.Class ||
t.TypeKind == TypeKind.Struct || t.Item1.TypeKind == TypeKind.Struct ||
t.TypeKind == TypeKind.Delegate || t.Item1.TypeKind == TypeKind.Delegate ||
t.TypeKind == TypeKind.Enum); t.Item1.TypeKind == TypeKind.Enum);
} }
return ImmutableArray<INamedTypeSymbol>.Empty; return ImmutableArray<(INamedTypeSymbol, Project)>.Empty;
} }
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册