提交 5b5ccba3 编写于 作者: C CyrusNajmabadi

Reduce more allocations for common paths.

上级 165583ab
......@@ -187,7 +187,7 @@ public static partial class SymbolFinder
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var list = new List<ISymbol>();
var list = ArrayBuilder<ISymbol>.GetInstance();
// get declarations from the compilation's assembly
await AddDeclarationsAsync(project, query, criteria, list, cancellationToken).ConfigureAwait(false);
......@@ -208,7 +208,7 @@ public static partial class SymbolFinder
}
}
return TranslateNamespaces(list, compilation);
return TranslateNamespaces(list.ToImmutableAndFree(), compilation);
}
private static string GetMetadataReferenceFilePath(MetadataReference metadataReference)
......@@ -219,70 +219,92 @@ private static string GetMetadataReferenceFilePath(MetadataReference metadataRef
/// <summary>
/// Makes certain all namespace symbols returned by API are from the compilation.
/// </summary>
private static ImmutableArray<ISymbol> TranslateNamespaces(List<ISymbol> symbols, Compilation compilation)
private static ImmutableArray<ISymbol> TranslateNamespaces(
ImmutableArray<ISymbol> symbols, Compilation compilation)
{
var result = ArrayBuilder<ISymbol>.GetInstance();
var builder = ArrayBuilder<ISymbol>.GetInstance();
foreach (var symbol in symbols)
{
var ns = symbol as INamespaceSymbol;
if (ns != null)
{
result.Add(compilation.GetCompilationNamespace(ns));
builder.Add(compilation.GetCompilationNamespace(ns));
}
else
{
result.Add(symbol);
builder.Add(symbol);
}
}
return result.ToImmutableAndFree();
var result = builder.Count == symbols.Length
? symbols
: builder.ToImmutable();
builder.Free();
return result;
}
private static async Task AddDeclarationsAsync(
Project project, SearchQuery query, SymbolFilter filter, List<ISymbol> list, CancellationToken cancellationToken)
private static Task AddDeclarationsAsync(
Project project, SearchQuery query, SymbolFilter filter,
ArrayBuilder<ISymbol> list, CancellationToken cancellationToken)
{
await AddDeclarationsAsync(
return AddDeclarationsAsync(
project, query, filter, list,
startingCompilation: null,
startingAssembly: null,
cancellationToken: cancellationToken).ConfigureAwait(false);
cancellationToken: cancellationToken);
}
private static async Task AddDeclarationsAsync(
Project project,
SearchQuery query,
SymbolFilter filter,
List<ISymbol> list,
ArrayBuilder<ISymbol> list,
Compilation startingCompilation,
IAssemblySymbol startingAssembly,
CancellationToken cancellationToken)
{
using (Logger.LogBlock(FunctionId.SymbolFinder_Project_AddDeclarationsAsync, cancellationToken))
using (var set = SharedPools.Default<HashSet<ISymbol>>().GetPooledObject())
{
if (!await project.ContainsSymbolsWithNameAsync(query.GetPredicate(), filter, cancellationToken).ConfigureAwait(false))
{
return;
}
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (startingCompilation != null && startingAssembly != null && compilation.Assembly != startingAssembly)
{
// Return symbols from skeleton assembly in this case so that symbols have the same language as startingCompilation.
list.AddRange(
FilterByCriteria(compilation.GetSymbolsWithName(query.GetPredicate(), filter, cancellationToken), filter)
.Select(s => s.GetSymbolKey().Resolve(startingCompilation, cancellationToken: cancellationToken).Symbol).WhereNotNull());
}
else
{
list.AddRange(FilterByCriteria(compilation.GetSymbolsWithName(query.GetPredicate(), filter, cancellationToken), filter));
}
var unfilteredSymbols = await GetUnfilteredSymbolsAsync(
project, query, filter, startingCompilation, startingAssembly, cancellationToken).ConfigureAwait(false);
list.AddRange(FilterByCriteria(unfilteredSymbols, filter));
}
}
private static async Task<ImmutableArray<ISymbol>> GetUnfilteredSymbolsAsync(
Project project,
SearchQuery query,
SymbolFilter filter,
Compilation startingCompilation,
IAssemblySymbol startingAssembly,
CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (startingCompilation != null && startingAssembly != null && compilation.Assembly != startingAssembly)
{
// Return symbols from skeleton assembly in this case so that symbols have the same language as startingCompilation.
return compilation.GetSymbolsWithName(query.GetPredicate(), filter, cancellationToken)
.Select(s => s.GetSymbolKey().Resolve(startingCompilation, cancellationToken: cancellationToken).Symbol)
.WhereNotNull()
.ToImmutableArray();
}
else
{
return compilation.GetSymbolsWithName(query.GetPredicate(), filter, cancellationToken)
.ToImmutableArray();
}
}
private static async Task AddDeclarationsAsync(
Solution solution, IAssemblySymbol assembly, PortableExecutableReference referenceOpt,
SearchQuery query, SymbolFilter filter, List<ISymbol> list, CancellationToken cancellationToken)
SearchQuery query, SymbolFilter filter, ArrayBuilder<ISymbol> list, CancellationToken cancellationToken)
{
// All entrypoints to this function are Find functions that are only searching
// for specific strings (i.e. they never do a custom search).
......@@ -367,7 +389,8 @@ public static Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Project pro
/// <summary>
/// Find the symbols for declarations made in source with the specified name.
/// </summary>
public static Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
public static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(
Project project, string name, bool ignoreCase, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
if (project == null)
{
......@@ -381,21 +404,22 @@ public static Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Project pro
if (string.IsNullOrWhiteSpace(name))
{
return SpecializedTasks.EmptyEnumerable<ISymbol>();
return ImmutableArray<ISymbol>.Empty;
}
using (Logger.LogBlock(FunctionId.SymbolFinder_Project_Name_FindSourceDeclarationsAsync, cancellationToken))
{
return FindSourceDeclarationsAsyncImpl(project, SearchQuery.Create(name, ignoreCase), filter, cancellationToken);
return await FindSourceDeclarationsAsyncImpl(
project, SearchQuery.Create(name, ignoreCase), filter, cancellationToken).ConfigureAwait(false);
}
}
private static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsyncImpl(
private static async Task<ImmutableArray<ISymbol>> FindSourceDeclarationsAsyncImpl(
Project project, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken)
{
var list = new List<ISymbol>();
var list = ArrayBuilder<ISymbol>.GetInstance();
await AddDeclarationsAsync(project, query, filter, list, cancellationToken).ConfigureAwait(false);
return list;
return list.ToImmutableAndFree();
}
/// <summary>
......@@ -452,13 +476,15 @@ public static Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Project pro
/// <summary>
/// Find the symbols for declarations made in source with a matching name.
/// </summary>
public static Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(
public static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(
Project project, Func<string, bool> predicate, SymbolFilter filter, CancellationToken cancellationToken = default(CancellationToken))
{
return FindSourceDeclarationsAsync(project, SearchQuery.CreateCustom(predicate), filter, cancellationToken);
return await FindSourceDeclarationsAsync(
project, SearchQuery.CreateCustom(predicate), filter, cancellationToken).ConfigureAwait(false);
}
internal static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Project project, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken)
internal static async Task<ImmutableArray<ISymbol>> FindSourceDeclarationsAsync(
Project project, SearchQuery query, SymbolFilter filter, CancellationToken cancellationToken)
{
if (project == null)
{
......@@ -467,28 +493,27 @@ internal static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Pro
if (query.Name != null && string.IsNullOrWhiteSpace(query.Name))
{
return SpecializedCollections.EmptyEnumerable<ISymbol>();
return ImmutableArray<ISymbol>.Empty;
}
using (Logger.LogBlock(FunctionId.SymbolFinder_Project_Predicate_FindSourceDeclarationsAsync, cancellationToken))
{
var result = new List<ISymbol>();
if (!await project.ContainsSymbolsWithNameAsync(query.GetPredicate(), filter, cancellationToken).ConfigureAwait(false))
{
return result;
return ImmutableArray<ISymbol>.Empty;
}
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
result.AddRange(FilterByCriteria(compilation.GetSymbolsWithName(query.GetPredicate(), filter, cancellationToken), filter));
return result;
var unfiltered = compilation.GetSymbolsWithName(query.GetPredicate(), filter, cancellationToken).ToImmutableArray();
return FilterByCriteria(unfiltered, filter);
}
}
internal static ImmutableArray<ISymbol> FilterByCriteria(
IEnumerable<ISymbol> symbols, SymbolFilter criteria)
ImmutableArray<ISymbol> symbols, SymbolFilter criteria)
{
var result = ArrayBuilder<ISymbol>.GetInstance();
var builder = ArrayBuilder<ISymbol>.GetInstance();
foreach (var symbol in symbols)
{
if (symbol.IsImplicitlyDeclared || symbol.IsAccessor())
......@@ -498,11 +523,16 @@ internal static async Task<IEnumerable<ISymbol>> FindSourceDeclarationsAsync(Pro
if (MeetCriteria(symbol, criteria))
{
result.Add(symbol);
builder.Add(symbol);
}
}
return result.ToImmutableAndFree();
var result = builder.Count == symbols.Length
? symbols
: builder.ToImmutable();
builder.Free();
return result;
}
private static bool MeetCriteria(ISymbol symbol, SymbolFilter filter)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册