提交 6e9f9d26 编写于 作者: C CyrusNajmabadi

Reduce the number of intermediary IEnumerables we create while building indices.

上级 83346efe
......@@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
......@@ -34,7 +35,7 @@ protected SearchScope(AbstractAddImportCodeFixProvider<TSimpleNameSyntax> provid
CancellationToken = cancellationToken;
}
protected abstract Task<IEnumerable<ISymbol>> FindDeclarationsAsync(string name, SymbolFilter filter, SearchQuery query);
protected abstract Task<ImmutableArray<ISymbol>> FindDeclarationsAsync(string name, SymbolFilter filter, SearchQuery query);
public abstract SymbolReference CreateReference<T>(SymbolResult<T> symbol) where T : INamespaceOrTypeSymbol;
public async Task<IEnumerable<SymbolResult<ISymbol>>> FindDeclarationsAsync(
......@@ -109,7 +110,7 @@ private class AllSymbolsProjectSearchScope : ProjectSearchScope
{
}
protected override Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
protected override Task<ImmutableArray<ISymbol>> FindDeclarationsAsync(
string name, SymbolFilter filter, SearchQuery searchQuery)
{
return SymbolFinder.FindDeclarationsAsync(_project, searchQuery, filter, CancellationToken);
......@@ -133,14 +134,15 @@ private class SourceSymbolsProjectSearchScope : ProjectSearchScope
_projectToAssembly = projectToAssembly;
}
protected override async Task<IEnumerable<ISymbol>> FindDeclarationsAsync(string name, SymbolFilter filter, SearchQuery searchQuery)
protected override async Task<ImmutableArray<ISymbol>> FindDeclarationsAsync(
string name, SymbolFilter filter, SearchQuery searchQuery)
{
var service = _project.Solution.Workspace.Services.GetService<ISymbolTreeInfoCacheService>();
var info = await service.TryGetSourceSymbolTreeInfoAsync(_project, CancellationToken).ConfigureAwait(false);
if (info == null)
{
// Looks like there was nothing in the cache. Return no results for now.
return SpecializedCollections.EmptyEnumerable<ISymbol>();
return ImmutableArray<ISymbol>.Empty;
}
// Don't create the assembly until it is actually needed by the SymbolTreeInfo.FindAsync
......
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
......@@ -117,7 +118,7 @@ public static partial class SymbolFinder
/// <summary>
/// Find the declared symbols from either source, referenced projects or metadata assemblies with the specified name.
/// </summary>
public static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
public static async Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, CancellationToken cancellationToken = default(CancellationToken))
{
if (name == null)
......@@ -127,16 +128,17 @@ public static partial class SymbolFinder
if (string.IsNullOrWhiteSpace(name))
{
return SpecializedTasks.EmptyEnumerable<ISymbol>();
return ImmutableArray<ISymbol>.Empty;
}
return FindDeclarationsAsync(project, SearchQuery.Create(name, ignoreCase), SymbolFilter.All, cancellationToken: cancellationToken);
return await FindDeclarationsAsync(
project, SearchQuery.Create(name, ignoreCase), SymbolFilter.All, cancellationToken: cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Find the declared symbols from either source, referenced projects or metadata assemblies with the specified name.
/// </summary>
public static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
public static async Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
if (name == null)
......@@ -146,13 +148,14 @@ public static partial class SymbolFinder
if (string.IsNullOrWhiteSpace(name))
{
return SpecializedTasks.EmptyEnumerable<ISymbol>();
return ImmutableArray<ISymbol>.Empty;
}
return FindDeclarationsAsync(project, SearchQuery.Create(name, ignoreCase), filter, cancellationToken: cancellationToken);
return await FindDeclarationsAsync(
project, SearchQuery.Create(name, ignoreCase), filter, cancellationToken: cancellationToken).ConfigureAwait(false);
}
internal static Task<IEnumerable<ISymbol>> FindDeclarationsAsync(
internal static Task<ImmutableArray<ISymbol>> FindDeclarationsAsync(
Project project, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken)
{
// All entrypoints to this function are Find functions that are only searching
......@@ -166,7 +169,7 @@ public static partial class SymbolFinder
if (query.Name != null && string.IsNullOrWhiteSpace(query.Name))
{
return SpecializedTasks.EmptyEnumerable<ISymbol>();
return SpecializedTasks.EmptyImmutableArray<ISymbol>();
}
using (Logger.LogBlock(FunctionId.SymbolFinder_FindDeclarationsAsync, cancellationToken))
......@@ -175,7 +178,7 @@ public static partial class SymbolFinder
}
}
private static async Task<IEnumerable<ISymbol>> FindDeclarationsAsyncImpl(
private static async Task<ImmutableArray<ISymbol>> FindDeclarationsAsyncImpl(
Project project, SearchQuery query, SymbolFilter criteria, CancellationToken cancellationToken)
{
// All entrypoints to this function are Find functions that are only searching
......@@ -216,20 +219,23 @@ private static string GetMetadataReferenceFilePath(MetadataReference metadataRef
/// <summary>
/// Makes certain all namespace symbols returned by API are from the compilation.
/// </summary>
private static IEnumerable<ISymbol> TranslateNamespaces(List<ISymbol> symbols, Compilation compilation)
private static ImmutableArray<ISymbol> TranslateNamespaces(List<ISymbol> symbols, Compilation compilation)
{
var result = ArrayBuilder<ISymbol>.GetInstance();
foreach (var symbol in symbols)
{
var ns = symbol as INamespaceSymbol;
if (ns != null)
{
yield return compilation.GetCompilationNamespace(ns);
result.Add(compilation.GetCompilationNamespace(ns));
}
else
{
yield return symbol;
result.Add(symbol);
}
}
return result.ToImmutableAndFree();
}
private static async Task AddDeclarationsAsync(
......@@ -479,8 +485,10 @@ internal static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Pro
}
}
internal static IEnumerable<ISymbol> FilterByCriteria(IEnumerable<ISymbol> symbols, SymbolFilter criteria)
internal static ImmutableArray<ISymbol> FilterByCriteria(
IEnumerable<ISymbol> symbols, SymbolFilter criteria)
{
var result = ArrayBuilder<ISymbol>.GetInstance();
foreach (var symbol in symbols)
{
if (symbol.IsImplicitlyDeclared || symbol.IsAccessor())
......@@ -490,9 +498,11 @@ internal static IEnumerable<ISymbol> FilterByCriteria(IEnumerable<ISymbol> symbo
if (MeetCriteria(symbol, criteria))
{
yield return symbol;
result.Add(symbol);
}
}
return result.ToImmutableAndFree();
}
private static bool MeetCriteria(ISymbol symbol, SymbolFilter filter)
......
......@@ -114,7 +114,7 @@ internal partial class SymbolTreeInfo
_spellCheckerTask = spellCheckerTask;
}
public Task<IEnumerable<ISymbol>> FindAsync(
public Task<ImmutableArray<ISymbol>> FindAsync(
SearchQuery query, IAssemblySymbol assembly, SymbolFilter filter, CancellationToken cancellationToken)
{
// All entrypoints to this function are Find functions that are only searching
......@@ -124,7 +124,7 @@ internal partial class SymbolTreeInfo
return this.FindAsync(query, new AsyncLazy<IAssemblySymbol>(assembly), filter, cancellationToken);
}
public async Task<IEnumerable<ISymbol>> FindAsync(
public async Task<ImmutableArray<ISymbol>> FindAsync(
SearchQuery query, AsyncLazy<IAssemblySymbol> lazyAssembly, SymbolFilter filter, CancellationToken cancellationToken)
{
// All entrypoints to this function are Find functions that are only searching
......@@ -136,7 +136,7 @@ internal partial class SymbolTreeInfo
filter);
}
private Task<IEnumerable<ISymbol>> FindAsyncWorker(
private Task<ImmutableArray<ISymbol>> FindAsyncWorker(
SearchQuery query, AsyncLazy<IAssemblySymbol> lazyAssembly, CancellationToken cancellationToken)
{
// All entrypoints to this function are Find functions that are only searching
......@@ -161,18 +161,18 @@ internal partial class SymbolTreeInfo
/// <summary>
/// Finds symbols in this assembly that match the provided name in a fuzzy manner.
/// </summary>
private async Task<IEnumerable<ISymbol>> FuzzyFindAsync(
private async Task<ImmutableArray<ISymbol>> FuzzyFindAsync(
AsyncLazy<IAssemblySymbol> lazyAssembly, string name, CancellationToken cancellationToken)
{
if (_spellCheckerTask.Status != TaskStatus.RanToCompletion)
{
// Spell checker isn't ready. Just return immediately.
return SpecializedCollections.EmptyEnumerable<ISymbol>();
return ImmutableArray<ISymbol>.Empty;
}
var spellChecker = _spellCheckerTask.Result;
var similarNames = spellChecker.FindSimilarWords(name, substringsAreSimilar: false);
var result = new List<ISymbol>();
var result = ArrayBuilder<ISymbol>.GetInstance();
foreach (var similarName in similarNames)
{
......@@ -180,20 +180,20 @@ internal partial class SymbolTreeInfo
result.AddRange(symbols);
}
return result;
return result.ToImmutableAndFree();
}
/// <summary>
/// Get all symbols that have a name matching the specified name.
/// </summary>
private async Task<IEnumerable<ISymbol>> FindAsync(
private async Task<ImmutableArray<ISymbol>> FindAsync(
AsyncLazy<IAssemblySymbol> lazyAssembly,
string name,
bool ignoreCase,
CancellationToken cancellationToken)
{
var comparer = GetComparer(ignoreCase);
var result = new List<ISymbol>();
var results = ArrayBuilder<ISymbol>.GetInstance();
IAssemblySymbol assemblySymbol = null;
foreach (var node in FindNodeIndices(name, comparer))
......@@ -201,10 +201,10 @@ internal partial class SymbolTreeInfo
cancellationToken.ThrowIfCancellationRequested();
assemblySymbol = assemblySymbol ?? await lazyAssembly.GetValueAsync(cancellationToken).ConfigureAwait(false);
result.AddRange(Bind(node, assemblySymbol.GlobalNamespace, cancellationToken));
Bind(node, assemblySymbol.GlobalNamespace, results, cancellationToken);
}
return result;
return results.ToImmutableAndFree(); ;
}
private static StringSliceComparer GetComparer(bool ignoreCase)
......@@ -409,26 +409,8 @@ private int BinarySearch(string name)
#region Binding
// returns all the symbols in the container corresponding to the node
private IEnumerable<ISymbol> Bind(
int index, INamespaceOrTypeSymbol rootContainer, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
using (var symbols = SharedPools.Default<List<ISymbol>>().GetPooledObject())
{
BindWorker(index, rootContainer, symbols.Object, cancellationToken);
foreach (var symbol in symbols.Object)
{
cancellationToken.ThrowIfCancellationRequested();
yield return symbol;
}
}
}
// returns all the symbols in the container corresponding to the node
private void BindWorker(
int index, INamespaceOrTypeSymbol rootContainer, List<ISymbol> results, CancellationToken cancellationToken)
private void Bind(
int index, INamespaceOrTypeSymbol rootContainer, ArrayBuilder<ISymbol> results, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -444,17 +426,26 @@ private int BinarySearch(string name)
}
else
{
using (var containerSymbols = SharedPools.Default<List<ISymbol>>().GetPooledObject())
var containerSymbols = ArrayBuilder<ISymbol>.GetInstance();
try
{
BindWorker(node.ParentIndex, rootContainer, containerSymbols.Object, cancellationToken);
Bind(node.ParentIndex, rootContainer, containerSymbols, cancellationToken);
foreach (var containerSymbol in containerSymbols.Object.OfType<INamespaceOrTypeSymbol>())
foreach (var containerSymbol in containerSymbols)
{
cancellationToken.ThrowIfCancellationRequested();
results.AddRange(containerSymbol.GetMembers(GetName(node)));
var namedType = containerSymbol as INamedTypeSymbol;
if (namedType != null)
{
results.AddRange(namedType.GetMembers(GetName(node)));
}
}
}
finally
{
containerSymbols.Free();
}
}
}
......@@ -541,16 +532,37 @@ internal void AssertEquivalentTo(SymbolTreeInfo other)
return result;
}
public IEnumerable<INamedTypeSymbol> GetDerivedMetadataTypes(
public ImmutableArray<INamedTypeSymbol> GetDerivedMetadataTypes(
string baseTypeName, Compilation compilation, CancellationToken cancellationToken)
{
var baseTypeNameIndex = BinarySearch(baseTypeName);
var derivedTypeIndices = _inheritanceMap[baseTypeNameIndex];
return from derivedTypeIndex in derivedTypeIndices
from symbol in Bind(derivedTypeIndex, compilation.GlobalNamespace, cancellationToken)
let namedType = symbol as INamedTypeSymbol
select namedType;
var builder = ArrayBuilder<INamedTypeSymbol>.GetInstance();
foreach (var derivedTypeIndex in derivedTypeIndices)
{
var tempBuilder = ArrayBuilder<ISymbol>.GetInstance();
try
{
Bind(derivedTypeIndex, compilation.GlobalNamespace, tempBuilder, cancellationToken);
foreach (var symbol in tempBuilder)
{
var namedType = symbol as INamedTypeSymbol;
if (namedType != null)
{
builder.Add(namedType);
}
}
}
finally
{
tempBuilder.Free();
}
}
return builder.ToImmutableAndFree();
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册