using System; using System.Collections.Concurrent; using Microsoft.CodeAnalysis.Editor.Navigation; using Microsoft.CodeAnalysis.FindReferences; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.Editor.Implementation.FindReferences { internal abstract partial class AbstractFindReferencesService { /// /// Forwards IFindReferencesProgress calls to a FindRefrencesContext instance. /// private class ProgressAdapter : IFindReferencesProgress { private readonly Solution _solution; private readonly FindReferencesContext _context; /// /// We will hear about definition symbols many times while performing FAR. We'll /// here about it first when the FAR engine discovers the symbol, and then for every /// reference it finds to the symbol. However, we only want to create and pass along /// a single instance of for that definition no matter /// how many times we see it. /// /// This dictionary allows us to make that mapping once and then keep it around for /// all future callbacks. /// private readonly ConcurrentDictionary _definitionToNavigableItem = new ConcurrentDictionary(MetadataUnifyingEquivalenceComparer.Instance); private readonly Func _definitionFactory; public ProgressAdapter(Solution solution, FindReferencesContext context) { _solution = solution; _context = context; _definitionFactory = s => s.ToDefinitionItem(solution); } // Do nothing functions. The streaming far service doesn't care about // any of these. public void OnStarted() { } public void OnCompleted() { } public void OnFindInDocumentStarted(Document document) { } public void OnFindInDocumentCompleted(Document document) { } // Simple context forwarding functions. public void ReportProgress(int current, int maximum) => _context.ReportProgress(current, maximum); // More complicated forwarding functions. These need to map from the symbols // used by the FAR engine to the INavigableItems used by the streaming FAR // feature. private DefinitionItem GetDefinitionItem(ISymbol definition) { return _definitionToNavigableItem.GetOrAdd(definition, _definitionFactory); } public void OnDefinitionFound(ISymbol definition) { _context.OnDefinitionFound(GetDefinitionItem(definition)); } public void OnReferenceFound(ISymbol definition, ReferenceLocation location) { var referenceItem = location.TryCreateSourceReferenceItem( GetDefinitionItem(definition)); if (referenceItem != null) { _context.OnReferenceFound(referenceItem); } } } } }