diff --git a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/AbstractDocumentHighlightsService.cs b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/AbstractDocumentHighlightsService.cs index 4721c5f76ec37b95ead4b5b7d0d7deb44d919155..6cde3de2b7789ea8b549861e002de71141dab9eb 100644 --- a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/AbstractDocumentHighlightsService.cs +++ b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/AbstractDocumentHighlightsService.cs @@ -18,26 +18,31 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.ReferenceHighlighting { internal abstract class AbstractDocumentHighlightsService : IDocumentHighlightsService { - public async Task> GetDocumentHighlightsAsync(Document document, int position, IEnumerable documentsToSearch, CancellationToken cancellationToken) + public async Task> GetDocumentHighlightsAsync( + Document document, int position, IImmutableSet documentsToSearch, CancellationToken cancellationToken) { // use speculative semantic model to see whether we are on a symbol we can do HR var span = new TextSpan(position, 0); var solution = document.Project.Solution; + var semanticModel = await document.GetSemanticModelForSpanAsync(span, cancellationToken).ConfigureAwait(false); - var symbol = await SymbolFinder.FindSymbolAtPositionAsync(semanticModel, position, solution.Workspace, cancellationToken).ConfigureAwait(false); + var symbol = await SymbolFinder.FindSymbolAtPositionAsync( + semanticModel, position, solution.Workspace, cancellationToken).ConfigureAwait(false); if (symbol == null) { - return SpecializedCollections.EmptyEnumerable(); + return ImmutableArray.Empty; } symbol = await GetSymbolToSearchAsync(document, position, semanticModel, symbol, cancellationToken).ConfigureAwait(false); if (symbol == null) { - return SpecializedCollections.EmptyEnumerable(); + return ImmutableArray.Empty; } // Get unique tags for referenced symbols - return await GetTagsForReferencedSymbolAsync(symbol, ImmutableHashSet.CreateRange(documentsToSearch), solution, cancellationToken).ConfigureAwait(false); + return await GetTagsForReferencedSymbolAsync( + new SymbolAndProjectId(symbol, document.Project.Id), documentsToSearch, + solution, cancellationToken).ConfigureAwait(false); } private async Task GetSymbolToSearchAsync(Document document, int position, SemanticModel semanticModel, ISymbol symbol, CancellationToken cancellationToken) @@ -53,22 +58,28 @@ private async Task GetSymbolToSearchAsync(Document document, int positi return await SymbolFinder.FindSymbolAtPositionAsync(currentSemanticModel, position, document.Project.Solution.Workspace, cancellationToken).ConfigureAwait(false); } - private async Task> GetTagsForReferencedSymbolAsync( - ISymbol symbol, + private async Task> GetTagsForReferencedSymbolAsync( + SymbolAndProjectId symbolAndProjectId, IImmutableSet documentsToSearch, Solution solution, CancellationToken cancellationToken) { + var symbol = symbolAndProjectId.Symbol; Contract.ThrowIfNull(symbol); if (ShouldConsiderSymbol(symbol)) { - var references = await SymbolFinder.FindReferencesAsync( - symbol, solution, progress: null, documents: documentsToSearch, cancellationToken: cancellationToken).ConfigureAwait(false); - - return await FilterAndCreateSpansAsync(references, solution, documentsToSearch, symbol, cancellationToken).ConfigureAwait(false); + var progress = new StreamingProgressCollector( + StreamingFindReferencesProgress.Instance); + await SymbolFinder.FindReferencesAsync( + symbolAndProjectId, solution, progress, + documentsToSearch, cancellationToken).ConfigureAwait(false); + + return await FilterAndCreateSpansAsync( + progress.GetReferencedSymbols(), solution, documentsToSearch, + symbol, cancellationToken).ConfigureAwait(false); } - return SpecializedCollections.EmptyEnumerable(); + return ImmutableArray.Empty; } private bool ShouldConsiderSymbol(ISymbol symbol) @@ -95,8 +106,10 @@ private bool ShouldConsiderSymbol(ISymbol symbol) } } - private async Task> FilterAndCreateSpansAsync( - IEnumerable references, Solution solution, IImmutableSet documentsToSearch, ISymbol symbol, CancellationToken cancellationToken) + private async Task> FilterAndCreateSpansAsync( + IEnumerable references, Solution solution, + IImmutableSet documentsToSearch, ISymbol symbol, + CancellationToken cancellationToken) { references = references.FilterToItemsToShow(); references = references.FilterNonMatchingMethodNames(solution, symbol); @@ -114,7 +127,9 @@ private bool ShouldConsiderSymbol(ISymbol symbol) additionalReferences.AddRange(await GetAdditionalReferencesAsync(document, symbol, cancellationToken).ConfigureAwait(false)); } - return await CreateSpansAsync(solution, symbol, references, additionalReferences, documentsToSearch, cancellationToken).ConfigureAwait(false); + return await CreateSpansAsync( + solution, symbol, references, additionalReferences, + documentsToSearch, cancellationToken).ConfigureAwait(false); } private Task> GetAdditionalReferencesAsync( @@ -129,7 +144,7 @@ private bool ShouldConsiderSymbol(ISymbol symbol) return Task.FromResult(SpecializedCollections.EmptyEnumerable()); } - private async Task> CreateSpansAsync( + private async Task> CreateSpansAsync( Solution solution, ISymbol symbol, IEnumerable references, @@ -196,19 +211,19 @@ private bool ShouldConsiderSymbol(ISymbol symbol) await AddLocationSpan(location, solution, spanSet, tagMap, HighlightSpanKind.Reference, cancellationToken).ConfigureAwait(false); } - var list = new List(tagMap.Count); + var list = ArrayBuilder.GetInstance(tagMap.Count); foreach (var kvp in tagMap) { - var spans = new List(kvp.Value.Count); + var spans = ArrayBuilder.GetInstance(kvp.Value.Count); foreach (var span in kvp.Value) { spans.Add(span); } - list.Add(new DocumentHighlights(kvp.Key, spans)); + list.Add(new DocumentHighlights(kvp.Key, spans.ToImmutableAndFree())); } - return list; + return list.ToImmutableAndFree(); } private static bool ShouldIncludeDefinition(ISymbol symbol) @@ -247,7 +262,8 @@ private async Task AddLocationSpan(Location location, Solution solution, HashSet } } - private async Task?> GetLocationSpanAsync(Solution solution, Location location, CancellationToken cancellationToken) + private async Task?> GetLocationSpanAsync( + Solution solution, Location location, CancellationToken cancellationToken) { try { @@ -284,4 +300,4 @@ private async Task AddLocationSpan(Location location, Solution solution, HashSet return null; } } -} +} \ No newline at end of file diff --git a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/IDocumentHighlightsService.cs b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/IDocumentHighlightsService.cs index 218cbd594e56b6fa7a9f0cbe615e4ffb818c8c84..f86be931963c1cff0e11159a4a5eac49ebd0efe2 100644 --- a/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/IDocumentHighlightsService.cs +++ b/src/EditorFeatures/Core/Implementation/ReferenceHighlighting/IDocumentHighlightsService.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; @@ -31,9 +32,9 @@ public HighlightSpan(TextSpan textSpan, HighlightSpanKind kind) : this() internal struct DocumentHighlights { public Document Document { get; } - public IList HighlightSpans { get; } + public ImmutableArray HighlightSpans { get; } - public DocumentHighlights(Document document, IList highlightSpans) : this() + public DocumentHighlights(Document document, ImmutableArray highlightSpans) { this.Document = document; this.HighlightSpans = highlightSpans; @@ -42,6 +43,7 @@ public DocumentHighlights(Document document, IList highlightSpans internal interface IDocumentHighlightsService : ILanguageService { - Task> GetDocumentHighlightsAsync(Document document, int position, IEnumerable documentsToSearch, CancellationToken cancellationToken); + Task> GetDocumentHighlightsAsync( + Document document, int position, IImmutableSet documentsToSearch, CancellationToken cancellationToken); } }