diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SearchScope.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SearchScope.cs index 928b8c6a0f055a502f469ee5a29078518c11662c..567eb98153fd99fbb0f168362abdc4ddd85484f3 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SearchScope.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SearchScope.cs @@ -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 provid CancellationToken = cancellationToken; } - protected abstract Task> FindDeclarationsAsync(string name, SymbolFilter filter, SearchQuery query); + protected abstract Task> FindDeclarationsAsync(string name, SymbolFilter filter, SearchQuery query); public abstract SymbolReference CreateReference(SymbolResult symbol) where T : INamespaceOrTypeSymbol; public async Task>> FindDeclarationsAsync( @@ -109,7 +110,7 @@ private class AllSymbolsProjectSearchScope : ProjectSearchScope { } - protected override Task> FindDeclarationsAsync( + protected override Task> 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> FindDeclarationsAsync(string name, SymbolFilter filter, SearchQuery searchQuery) + protected override async Task> FindDeclarationsAsync( + string name, SymbolFilter filter, SearchQuery searchQuery) { var service = _project.Solution.Workspace.Services.GetService(); 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(); + return ImmutableArray.Empty; } // Don't create the assembly until it is actually needed by the SymbolTreeInfo.FindAsync @@ -190,14 +192,14 @@ public override SymbolReference CreateReference(SymbolResult searchResult) _metadataReference); } - protected override async Task> FindDeclarationsAsync( + protected override async Task> FindDeclarationsAsync( string name, SymbolFilter filter, SearchQuery searchQuery) { var service = _solution.Workspace.Services.GetService(); var info = await service.TryGetMetadataSymbolTreeInfoAsync(_solution, _metadataReference, CancellationToken).ConfigureAwait(false); if (info == null) { - return SpecializedCollections.EmptyEnumerable(); + return ImmutableArray.Empty; } return await info.FindAsync(searchQuery, _assembly, filter, CancellationToken).ConfigureAwait(false); diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs index e65ae5ed1173023e6938e364da5c046df569643f..e5a0a6ee8529377c125f9e7a722e9599f1ff82f1 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Declarations.cs @@ -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 /// /// Find the declared symbols from either source, referenced projects or metadata assemblies with the specified name. /// - public static Task> FindDeclarationsAsync( + public static async Task> 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(); + return ImmutableArray.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); } /// /// Find the declared symbols from either source, referenced projects or metadata assemblies with the specified name. /// - public static Task> FindDeclarationsAsync( + public static async Task> 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(); + return ImmutableArray.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> FindDeclarationsAsync( + internal static Task> 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(); + return SpecializedTasks.EmptyImmutableArray(); } using (Logger.LogBlock(FunctionId.SymbolFinder_FindDeclarationsAsync, cancellationToken)) @@ -175,7 +178,7 @@ public static partial class SymbolFinder } } - private static async Task> FindDeclarationsAsyncImpl( + private static async Task> 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 /// /// Makes certain all namespace symbols returned by API are from the compilation. /// - private static IEnumerable TranslateNamespaces(List symbols, Compilation compilation) + private static ImmutableArray TranslateNamespaces(List symbols, Compilation compilation) { + var result = ArrayBuilder.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> FindSourceDeclarationsAsync(Pro } } - internal static IEnumerable FilterByCriteria(IEnumerable symbols, SymbolFilter criteria) + internal static ImmutableArray FilterByCriteria( + IEnumerable symbols, SymbolFilter criteria) { + var result = ArrayBuilder.GetInstance(); foreach (var symbol in symbols) { if (symbol.IsImplicitlyDeclared || symbol.IsAccessor()) @@ -490,9 +498,11 @@ internal static IEnumerable FilterByCriteria(IEnumerable symbo if (MeetCriteria(symbol, criteria)) { - yield return symbol; + result.Add(symbol); } } + + return result.ToImmutableAndFree(); } private static bool MeetCriteria(ISymbol symbol, SymbolFilter filter) diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs index 0174ef1adaca736895b317ab7fc2513d409acaf0..4d1933b228ea673d28cd5a66147d144ca70bd70b 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo.cs @@ -114,7 +114,7 @@ internal partial class SymbolTreeInfo _spellCheckerTask = spellCheckerTask; } - public Task> FindAsync( + public Task> 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(assembly), filter, cancellationToken); } - public async Task> FindAsync( + public async Task> FindAsync( SearchQuery query, AsyncLazy 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> FindAsyncWorker( + private Task> FindAsyncWorker( SearchQuery query, AsyncLazy lazyAssembly, CancellationToken cancellationToken) { // All entrypoints to this function are Find functions that are only searching @@ -161,18 +161,18 @@ internal partial class SymbolTreeInfo /// /// Finds symbols in this assembly that match the provided name in a fuzzy manner. /// - private async Task> FuzzyFindAsync( + private async Task> FuzzyFindAsync( AsyncLazy lazyAssembly, string name, CancellationToken cancellationToken) { if (_spellCheckerTask.Status != TaskStatus.RanToCompletion) { // Spell checker isn't ready. Just return immediately. - return SpecializedCollections.EmptyEnumerable(); + return ImmutableArray.Empty; } var spellChecker = _spellCheckerTask.Result; var similarNames = spellChecker.FindSimilarWords(name, substringsAreSimilar: false); - var result = new List(); + var result = ArrayBuilder.GetInstance(); foreach (var similarName in similarNames) { @@ -180,20 +180,20 @@ internal partial class SymbolTreeInfo result.AddRange(symbols); } - return result; + return result.ToImmutableAndFree(); } /// /// Get all symbols that have a name matching the specified name. /// - private async Task> FindAsync( + private async Task> FindAsync( AsyncLazy lazyAssembly, string name, bool ignoreCase, CancellationToken cancellationToken) { var comparer = GetComparer(ignoreCase); - var result = new List(); + var results = ArrayBuilder.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 Bind( - int index, INamespaceOrTypeSymbol rootContainer, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - - using (var symbols = SharedPools.Default>().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 results, CancellationToken cancellationToken) + private void Bind( + int index, INamespaceOrTypeSymbol rootContainer, ArrayBuilder results, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -444,17 +426,26 @@ private int BinarySearch(string name) } else { - using (var containerSymbols = SharedPools.Default>().GetPooledObject()) + var containerSymbols = ArrayBuilder.GetInstance(); + try { - BindWorker(node.ParentIndex, rootContainer, containerSymbols.Object, cancellationToken); + Bind(node.ParentIndex, rootContainer, containerSymbols, cancellationToken); - foreach (var containerSymbol in containerSymbols.Object.OfType()) + foreach (var containerSymbol in containerSymbols) { cancellationToken.ThrowIfCancellationRequested(); - results.AddRange(containerSymbol.GetMembers(GetName(node))); + var nsOrType = containerSymbol as INamespaceOrTypeSymbol; + if (nsOrType != null) + { + results.AddRange(nsOrType.GetMembers(GetName(node))); + } } } + finally + { + containerSymbols.Free(); + } } } @@ -541,16 +532,37 @@ internal void AssertEquivalentTo(SymbolTreeInfo other) return result; } - public IEnumerable GetDerivedMetadataTypes( + public ImmutableArray 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.GetInstance(); + + foreach (var derivedTypeIndex in derivedTypeIndices) + { + var tempBuilder = ArrayBuilder.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