diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs
index 2563ced0e5054f803960a3760f005b00243a2635..0ccbc0881c0aa9fbfc193e27d65e88f5f536902f 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs
@@ -6,7 +6,6 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
-using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Navigation;
@@ -49,7 +48,7 @@ public async Task OnReferenceFoundAsync(Document document, TextSpan span)
///
/// Forwards IFindReferencesProgress calls to an IFindUsagesContext instance.
///
- private class FindReferencesProgressAdapter : ForegroundThreadAffinitizedObject, IStreamingFindReferencesProgress
+ private class FindReferencesProgressAdapter : IStreamingFindReferencesProgress
{
private readonly Solution _solution;
private readonly IFindUsagesContext _context;
@@ -74,9 +73,7 @@ public IStreamingProgressTracker ProgressTracker
=> _context.ProgressTracker;
public FindReferencesProgressAdapter(
- IThreadingContext threadingContext, Solution solution,
- IFindUsagesContext context, FindReferencesSearchOptions options)
- : base(threadingContext)
+ Solution solution, IFindUsagesContext context, FindReferencesSearchOptions options)
{
_solution = solution;
_context = context;
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.SymbolMoniker.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.SymbolMoniker.cs
index e8406acfc7af7e5debbde6d072e0ce54f759b6f5..a3f037c32bae642dcda23cb049a7ec788d214891 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.SymbolMoniker.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.SymbolMoniker.cs
@@ -21,8 +21,7 @@ internal abstract partial class AbstractFindUsagesService
private static async Task FindSymbolMonikerReferencesAsync(
IFindSymbolMonikerUsagesService monikerUsagesService,
ISymbol definition,
- IFindUsagesContext context,
- CancellationToken cancellationToken)
+ IFindUsagesContext context)
{
var moniker = SymbolMoniker.TryCreate(definition);
if (moniker == null)
@@ -42,7 +41,7 @@ internal abstract partial class AbstractFindUsagesService
var monikers = ImmutableArray.Create(moniker);
var first = true;
- await foreach (var referenceItem in monikerUsagesService.FindReferencesByMoniker(definitionItem, monikers, cancellationToken))
+ await foreach (var referenceItem in monikerUsagesService.FindReferencesByMoniker(definitionItem, monikers, context.CancellationToken))
{
if (first)
{
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
index 6848cdbbb149189d49003615c8f7c98873c947a3..bfc4e9c3a4e08dc86450d28abad05fabdfd85a5e 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
@@ -13,6 +13,7 @@
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServices;
+using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
@@ -121,17 +122,15 @@ protected AbstractFindUsagesService(IThreadingContext threadingContext)
cancellationToken.ThrowIfCancellationRequested();
// Find the symbol we want to search and the solution we want to search in.
- var symbolAndSolutionOpt = await FindUsagesHelpers.GetRelevantSymbolAndSolutionAtPositionAsync(
+ var symbolAndProjectOpt = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
document, position, cancellationToken).ConfigureAwait(false);
- if (symbolAndSolutionOpt == null)
+ if (symbolAndProjectOpt == null)
return;
- var (symbol, solution) = symbolAndSolutionOpt.Value;
+ var (symbol, project) = symbolAndProjectOpt.Value;
await FindSymbolReferencesAsync(
- _threadingContext, context,
- symbol, solution,
- cancellationToken).ConfigureAwait(false);
+ context, symbol, project).ConfigureAwait(false);
}
///
@@ -139,9 +138,9 @@ protected AbstractFindUsagesService(IThreadingContext threadingContext)
/// and want to push all the references to it into the Streaming-Find-References window.
///
public static async Task FindSymbolReferencesAsync(
- IThreadingContext threadingContext, IFindUsagesContext context,
- ISymbol symbol, Solution solution, CancellationToken cancellationToken)
+ IFindUsagesContext context, ISymbol symbol, Project project)
{
+ var solution = project.Solution;
var monikerUsagesService = solution.Workspace.Services.GetRequiredService();
await context.SetSearchTitleAsync(string.Format(EditorFeaturesResources._0_references,
@@ -153,17 +152,64 @@ protected AbstractFindUsagesService(IThreadingContext threadingContext)
// engine will push results into the 'progress' instance passed into it.
// We'll take those results, massage them, and forward them along to the
// FindReferencesContext instance we were given.
- var progress = new FindReferencesProgressAdapter(threadingContext, solution, context, options);
- var normalFindReferencesTask = SymbolFinder.FindReferencesAsync(
- symbol, solution, progress, documents: null, options, cancellationToken);
+ var normalFindReferencesTask = FindReferencesAsync(
+ context, symbol, project, options);
// Kick off work to search the online code index system in parallel
var codeIndexReferencesTask = FindSymbolMonikerReferencesAsync(
- monikerUsagesService, symbol, context, cancellationToken);
+ monikerUsagesService, symbol, context);
await Task.WhenAll(normalFindReferencesTask, codeIndexReferencesTask).ConfigureAwait(false);
}
+ public static async Task FindReferencesAsync(
+ IFindUsagesContext context,
+ ISymbol symbol,
+ Project project,
+ FindReferencesSearchOptions options)
+ {
+ var cancellationToken = context.CancellationToken;
+ var solution = project.Solution;
+ var client = await RemoteHostClient.TryGetClientAsync(solution.Workspace, cancellationToken).ConfigureAwait(false);
+ if (client != null)
+ {
+ // Create a callback that we can pass to the server process to hear about the
+ // results as it finds them. When we hear about results we'll forward them to
+ // the 'progress' parameter which will then update the UI.
+ var serverCallback = new FindReferencesServerCallback(solution, context);
+
+ var success = await client.TryRunRemoteAsync(
+ WellKnownServiceHubServices.CodeAnalysisService,
+ nameof(IRemoteFindUsagesService.FindReferencesAsync),
+ solution,
+ new object[]
+ {
+ SerializableSymbolAndProjectId.Create(symbol, project, cancellationToken),
+ SerializableFindReferencesSearchOptions.Dehydrate(options),
+ },
+ serverCallback,
+ cancellationToken).ConfigureAwait(false);
+
+ if (success)
+ return;
+ }
+
+ // Couldn't effectively search in OOP. Perform the search in-proc.
+ await FindReferencesInCurrentProcessAsync(
+ context, symbol, project, options).ConfigureAwait(false);
+ }
+
+ private static Task FindReferencesInCurrentProcessAsync(
+ IFindUsagesContext context,
+ ISymbol symbol,
+ Project project,
+ FindReferencesSearchOptions options)
+ {
+ var progress = new FindReferencesProgressAdapter(project.Solution, context, options);
+ return SymbolFinder.FindReferencesAsync(
+ symbol, project.Solution, progress, documents: null, options, context.CancellationToken);
+ }
+
private async Task TryFindLiteralReferencesAsync(
Document document, int position, IFindUsagesContext context)
{
diff --git a/src/EditorFeatures/Core/FindUsages/FindUsagesHelpers.cs b/src/EditorFeatures/Core/FindUsages/FindUsagesHelpers.cs
index b80755df56ecee9812d19c3ef6e1930aa4846173..2ee5022088bcb4849390e5f2376ee77c6d01ddbb 100644
--- a/src/EditorFeatures/Core/FindUsages/FindUsagesHelpers.cs
+++ b/src/EditorFeatures/Core/FindUsages/FindUsagesHelpers.cs
@@ -31,7 +31,7 @@ public static string GetDisplayName(ISymbol symbol)
/// there may be symbol mapping involved (for example in Metadata-As-Source
/// scenarios).
///
- public static async Task<(ISymbol symbol, Solution solution)?> GetRelevantSymbolAndSolutionAtPositionAsync(
+ public static async Task<(ISymbol symbol, Project project)?> GetRelevantSymbolAndProjectAtPositionAsync(
Document document, int position, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -49,19 +49,19 @@ public static string GetDisplayName(ISymbol symbol)
if (mapping == null)
return null;
- return (mapping.Symbol, mapping.Project.Solution);
+ return (mapping.Symbol, mapping.Project);
}
public static async Task<(Solution solution, ISymbol symbol, ImmutableArray implementations, string message)?> FindSourceImplementationsAsync(Document document, int position, CancellationToken cancellationToken)
{
- var symbolAndSolutionOpt = await GetRelevantSymbolAndSolutionAtPositionAsync(
+ var symbolAndProjectOpt = await GetRelevantSymbolAndProjectAtPositionAsync(
document, position, cancellationToken).ConfigureAwait(false);
- if (symbolAndSolutionOpt == null)
+ if (symbolAndProjectOpt == null)
return null;
- var (symbol, solution) = symbolAndSolutionOpt.Value;
+ var (symbol, project) = symbolAndProjectOpt.Value;
return await FindSourceImplementationsAsync(
- solution, symbol, cancellationToken).ConfigureAwait(false);
+ project.Solution, symbol, cancellationToken).ConfigureAwait(false);
}
private static async Task<(Solution solution, ISymbol symbol, ImmutableArray implementations, string message)?> FindSourceImplementationsAsync(
diff --git a/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs b/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7f3970a2979fb63452a56d352aac89ac628216aa
--- /dev/null
+++ b/src/EditorFeatures/Core/FindUsages/IRemoteFindUsagesService.cs
@@ -0,0 +1,185 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.FindUsages;
+using Microsoft.CodeAnalysis.Remote;
+using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Editor.FindUsages
+{
+ internal interface IRemoteFindUsagesService
+ {
+ Task FindReferencesAsync(
+ PinnedSolutionInfo solutionInfo,
+ SerializableSymbolAndProjectId symbolAndProjectIdArg,
+ SerializableFindReferencesSearchOptions options,
+ CancellationToken cancellationToken);
+ }
+
+ internal class FindReferencesServerCallback
+ {
+ private readonly Solution _solution;
+ private readonly IFindUsagesContext _context;
+ private readonly Dictionary _idToDefinition = new Dictionary();
+
+ public FindReferencesServerCallback(Solution solution, IFindUsagesContext context)
+ {
+ _solution = solution;
+ _context = context;
+ }
+
+ public Task AddItemsAsync(int count)
+ => _context.ProgressTracker.AddItemsAsync(count);
+
+ public Task ItemCompletedAsync()
+ => _context.ProgressTracker.ItemCompletedAsync();
+
+ public Task ReportMessageAsync(string message)
+ => _context.ReportMessageAsync(message);
+
+ [Obsolete]
+ public Task ReportProgressAsync(int current, int maximum)
+ => _context.ReportProgressAsync(current, maximum);
+
+ public Task SetSearchTitleAsync(string title)
+ => _context.SetSearchTitleAsync(title);
+
+ public Task OnDefinitionFoundAsync(SerializableDefinitionItem definition)
+ {
+ var id = definition.Id;
+ var rehydrated = definition.Rehydrate(_solution);
+
+ lock (_idToDefinition)
+ {
+ _idToDefinition.Add(id, rehydrated);
+ }
+
+ return _context.OnDefinitionFoundAsync(rehydrated);
+ }
+
+ public Task OnReferenceFoundAsync(SerializableSourceReferenceItem reference)
+ => _context.OnReferenceFoundAsync(reference.Rehydrate(_solution, GetDefinition(reference.DefinitionId)));
+
+ private DefinitionItem GetDefinition(int definitionId)
+ {
+ lock (_idToDefinition)
+ {
+ Contract.ThrowIfFalse(_idToDefinition.ContainsKey(definitionId));
+ return _idToDefinition[definitionId];
+ }
+ }
+ }
+
+ internal class SerializableDocumentSpan
+ {
+ public DocumentId DocumentId;
+ public TextSpan SourceSpan;
+
+ public static SerializableDocumentSpan Dehydrate(DocumentSpan documentSpan)
+ => new SerializableDocumentSpan
+ {
+ DocumentId = documentSpan.Document.Id,
+ SourceSpan = documentSpan.SourceSpan,
+ };
+
+ public DocumentSpan Rehydrate(Solution solution)
+ => new DocumentSpan(solution.GetDocument(DocumentId), SourceSpan);
+ }
+
+ internal class SerializableTaggedText
+ {
+ public string Tag;
+ public string Text;
+ public TaggedTextStyle Style;
+ public string NavigationTarget;
+ public string NavigationHint;
+
+ public static SerializableTaggedText Dehydrate(TaggedText text)
+ => new SerializableTaggedText
+ {
+ Tag = text.Tag,
+ Text = text.Text,
+ Style = text.Style,
+ NavigationTarget = text.NavigationTarget,
+ NavigationHint = text.NavigationHint,
+ };
+
+ public TaggedText Rehydrate()
+ => new TaggedText(Tag, Text, Style, NavigationTarget, NavigationHint);
+ }
+
+ internal class SerializableDefinitionItem
+ {
+ public int Id;
+ public string[] Tags;
+ public SerializableTaggedText[] DisplayParts;
+ public SerializableTaggedText[] NameDisplayParts;
+ public SerializableTaggedText[] OriginationParts;
+ public SerializableDocumentSpan[] SourceSpans;
+ public (string key, string value)[] Properties;
+ public (string key, string value)[] DisplayableProperties;
+ public bool DisplayIfNoReferences;
+
+ public static SerializableDefinitionItem Dehydrate(int id, DefinitionItem item)
+ => new SerializableDefinitionItem
+ {
+ Id = id,
+ Tags = item.Tags.ToArray(),
+ DisplayParts = item.DisplayParts.Select(p => SerializableTaggedText.Dehydrate(p)).ToArray(),
+ NameDisplayParts = item.NameDisplayParts.Select(p => SerializableTaggedText.Dehydrate(p)).ToArray(),
+ OriginationParts = item.OriginationParts.Select(p => SerializableTaggedText.Dehydrate(p)).ToArray(),
+ SourceSpans = item.SourceSpans.Select(ss => SerializableDocumentSpan.Dehydrate(ss)).ToArray(),
+ Properties = item.Properties.Select(kvp => (kvp.Key, kvp.Value)).ToArray(),
+ DisplayableProperties = item.DisplayableProperties.Select(kvp => (kvp.Key, kvp.Value)).ToArray(),
+ DisplayIfNoReferences = item.DisplayIfNoReferences,
+ };
+
+ public DefinitionItem Rehydrate(Solution solution)
+ => new DefinitionItem.DefaultDefinitionItem(
+ Tags.ToImmutableArray(),
+ DisplayParts.SelectAsArray(dp => dp.Rehydrate()),
+ NameDisplayParts.SelectAsArray(dp => dp.Rehydrate()),
+ OriginationParts.SelectAsArray(dp => dp.Rehydrate()),
+ SourceSpans.SelectAsArray(ss => ss.Rehydrate(solution)),
+ Properties.ToImmutableDictionary(t => t.key, t => t.value),
+ DisplayableProperties.ToImmutableDictionary(t => t.key, t => t.value),
+ DisplayIfNoReferences);
+ }
+
+ internal class SerializableSourceReferenceItem
+ {
+ public int DefinitionId;
+ public SerializableDocumentSpan SourceSpan;
+ public SymbolUsageInfo SymbolUsageInfo;
+ public (string Key, string Value)[] AdditionalProperties;
+
+ public static SerializableSourceReferenceItem Dehydrate(
+ int definitionId, SourceReferenceItem item)
+ {
+ return new SerializableSourceReferenceItem
+ {
+ DefinitionId = definitionId,
+ SourceSpan = SerializableDocumentSpan.Dehydrate(item.SourceSpan),
+ SymbolUsageInfo = item.SymbolUsageInfo,
+ AdditionalProperties = item.AdditionalProperties.Select(kvp => (kvp.Key, kvp.Value)).ToArray(),
+ };
+ }
+
+ public SourceReferenceItem Rehydrate(Solution solution, DefinitionItem definition)
+ {
+ return new SourceReferenceItem(
+ definition,
+ SourceSpan.Rehydrate(solution),
+ SymbolUsageInfo,
+ AdditionalProperties.ToImmutableDictionary(t => t.Key, t => t.Value));
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core/GoToBase/AbstractGoToBaseService.cs b/src/EditorFeatures/Core/GoToBase/AbstractGoToBaseService.cs
index 892940287382d7e4138aa70c57b563dc7706139c..9113774907e9d2b37079b5c22c596ec9f9984cc2 100644
--- a/src/EditorFeatures/Core/GoToBase/AbstractGoToBaseService.cs
+++ b/src/EditorFeatures/Core/GoToBase/AbstractGoToBaseService.cs
@@ -16,20 +16,20 @@ internal abstract partial class AbstractGoToBaseService : IGoToBaseService
public async Task FindBasesAsync(Document document, int position, IFindUsagesContext context)
{
var cancellationToken = context.CancellationToken;
- var symbolAndSolutionOpt = await FindUsagesHelpers.GetRelevantSymbolAndSolutionAtPositionAsync(
+ var symbolAndProjectOpt = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(
document, position, cancellationToken).ConfigureAwait(false);
- if (symbolAndSolutionOpt == null)
+ if (symbolAndProjectOpt == null)
{
await context.ReportMessageAsync(
EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret).ConfigureAwait(false);
return;
}
- var (symbol, solution) = symbolAndSolutionOpt.Value;
+ var (symbol, project) = symbolAndProjectOpt.Value;
- var bases = FindBaseHelpers.FindBases(
- symbol, solution, cancellationToken);
+ var solution = project.Solution;
+ var bases = FindBaseHelpers.FindBases(symbol, solution, cancellationToken);
await context.SetSearchTitleAsync(
string.Format(EditorFeaturesResources._0_bases,
diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs
index 5c6f39552c20dadb28ec45fdaf2490df3d5e38b5..1ef090d8ca60e2ad85b620821372215a0f552a0c 100644
--- a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs
+++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs
@@ -152,6 +152,7 @@ internal abstract partial class DefinitionItem
Contract.ThrowIfFalse(Properties.ContainsKey(MetadataSymbolOriginatingProjectIdDebugName));
}
}
+
public abstract bool CanNavigateTo(Workspace workspace);
public abstract bool TryNavigateTo(Workspace workspace, NavigationBehavior navigationBehavior);
diff --git a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs
index c178ab77d6d7bb4f40dfb44d2fecb97ee67c863e..e2207266b4825500b09cc35acba94f61d49f320a 100644
--- a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs
+++ b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs
@@ -528,7 +528,7 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
// thread.
await Task.Run(async () =>
{
- await FindReferencesAsync(_threadingContext, symbolListItem, project, context, cancellationToken).ConfigureAwait(false);
+ await FindReferencesAsync(_threadingContext, symbolListItem, project, context).ConfigureAwait(false);
}, cancellationToken).ConfigureAwait(false);
// Note: we don't need to put this in a finally. The only time we might not hit
@@ -546,15 +546,12 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
}
}
- private static async Task FindReferencesAsync(IThreadingContext threadingContext, SymbolListItem symbolListItem, Project project, CodeAnalysis.FindUsages.FindUsagesContext context, CancellationToken cancellationToken)
+ private static async Task FindReferencesAsync(IThreadingContext threadingContext, SymbolListItem symbolListItem, Project project, CodeAnalysis.FindUsages.FindUsagesContext context)
{
- var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
+ var compilation = await project.GetCompilationAsync(context.CancellationToken).ConfigureAwait(false);
var symbol = symbolListItem.ResolveSymbol(compilation);
if (symbol != null)
- {
- await AbstractFindUsagesService.FindSymbolReferencesAsync(
- threadingContext, context, symbol, project.Solution, cancellationToken).ConfigureAwait(false);
- }
+ await AbstractFindUsagesService.FindSymbolReferencesAsync(context, symbol, project).ConfigureAwait(false);
}
}
}
diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_FindUsages.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_FindUsages.cs
new file mode 100644
index 0000000000000000000000000000000000000000..faf7057c2581718b6874219fe0d71899d3b51fa2
--- /dev/null
+++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_FindUsages.cs
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Editor.FindUsages;
+using Microsoft.CodeAnalysis.FindUsages;
+using Microsoft.CodeAnalysis.Shared.Utilities;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Remote
+{
+ // root level service for all Roslyn services
+ internal partial class CodeAnalysisService : IRemoteFindUsagesService
+ {
+ public Task FindReferencesAsync(PinnedSolutionInfo solutionInfo,
+ SerializableSymbolAndProjectId symbolAndProjectIdArg,
+ SerializableFindReferencesSearchOptions options,
+ CancellationToken cancellationToken)
+ {
+ return RunServiceAsync(async () =>
+ {
+ using (UserOperationBooster.Boost())
+ {
+ var solution = await GetSolutionAsync(solutionInfo, cancellationToken).ConfigureAwait(false);
+
+ var symbol = await symbolAndProjectIdArg.TryRehydrateAsync(
+ solution, cancellationToken).ConfigureAwait(false);
+ var project = solution.GetProject(symbolAndProjectIdArg.ProjectId);
+
+ var context = new RemoteFindUsageContext(solution, EndPoint, cancellationToken);
+
+ if (symbol == null)
+ return;
+
+ await AbstractFindUsagesService.FindReferencesAsync(
+ context, symbol, project, options.Rehydrate()).ConfigureAwait(false);
+ }
+ }, cancellationToken);
+ }
+
+ private class RemoteFindUsageContext : IFindUsagesContext, IStreamingProgressTracker
+ {
+ private readonly Solution _solution;
+ private readonly RemoteEndPoint _endPoint;
+ private readonly Dictionary _definitionItemToId = new Dictionary();
+
+ public CancellationToken CancellationToken { get; }
+
+ public RemoteFindUsageContext(Solution solution, RemoteEndPoint endPoint, CancellationToken cancellationToken)
+ {
+ _solution = solution;
+ _endPoint = endPoint;
+ CancellationToken = cancellationToken;
+ }
+
+ #region IStreamingProgressTracker
+
+ public Task AddItemsAsync(int count)
+ => _endPoint.InvokeAsync(nameof(AddItemsAsync), new object[] { count }, CancellationToken);
+
+ public Task ItemCompletedAsync()
+ => _endPoint.InvokeAsync(nameof(ItemCompletedAsync), Array.Empty