diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
index 041f4dd5bc581d8c896bb2ccf2b4c82e515b4c76..6c13e8c969222462c5843cff58fab234009c4464 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.DefinitionTrackingContext.cs
@@ -14,7 +14,7 @@ internal abstract partial class AbstractFindUsagesService
/// Forwards notifications to an underlying
/// while also keeping track of the definitions reported.
///
- /// These can then be used by to report the
+ /// These can then be used by to report the
/// definitions found to third parties in case they want to add any additional definitions
/// to the results we present.
///
diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
index 8e637b66271c70a4660124cc407964c734fcb3ca..de39707792ae8c1a6a1d2a45a441ec11d8711713 100644
--- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
+++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs
@@ -1,13 +1,14 @@
// 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.Immutable;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
-using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
@@ -50,18 +51,27 @@ internal abstract partial class AbstractFindUsagesService : IFindUsagesService
{
var definitionTrackingContext = new DefinitionTrackingContext(context);
- // NOTE: All ConFigureAwaits in this method need to pass 'true' so that
- // we return to the caller's context. that's so the call to
- // CallThirdPartyExtensionsAsync will happen on the UI thread. We need
- // this to maintain the threading guarantee we had around that method
- // from pre-Roslyn days.
+ // Need ConfigureAwait(true) here so we get back to the UI thread before calling
+ // GetThirdPartyDefinitions. We need to call that on the UI thread to match behavior
+ // of how the language service always worked in the past.
+ //
+ // Any async calls before GetThirdPartyDefinitions must be ConfigureAwait(true).
await FindLiteralOrSymbolReferencesAsync(
document, position, definitionTrackingContext).ConfigureAwait(true);
// After the FAR engine is done call into any third party extensions to see
// if they want to add results.
- await CallThirdPartyExtensionsAsync(
- document.Project.Solution, definitionTrackingContext, context).ConfigureAwait(true);
+ var thirdPartyDefinitions = GetThirdPartyDefinitions(
+ document.Project.Solution, definitionTrackingContext.GetDefinitions(), context.CancellationToken);
+
+ // From this point on we can do ConfigureAwait(false) as we're not calling back
+ // into third parties anymore.
+
+ foreach (var definition in thirdPartyDefinitions)
+ {
+ // Don't need ConfigureAwait(true) here
+ await context.OnDefinitionFoundAsync(definition).ConfigureAwait(false);
+ }
}
private async Task FindLiteralOrSymbolReferencesAsync(
@@ -81,24 +91,15 @@ internal abstract partial class AbstractFindUsagesService : IFindUsagesService
document, position, context).ConfigureAwait(false);
}
- private async Task CallThirdPartyExtensionsAsync(
+ private ImmutableArray GetThirdPartyDefinitions(
Solution solution,
- DefinitionTrackingContext definitionTrackingContext,
- IFindUsagesContext underlyingContext)
+ ImmutableArray definitions,
+ CancellationToken cancellationToken)
{
- var cancellationToken = definitionTrackingContext.CancellationToken;
var factory = solution.Workspace.Services.GetService();
-
- foreach (var definition in definitionTrackingContext.GetDefinitions())
- {
- var item = factory.GetThirdPartyDefinitionItem(solution, definition, cancellationToken);
- if (item != null)
- {
- // ConfigureAwait(true) because we want to come back on the
- // same thread after calling into extensions.
- await underlyingContext.OnDefinitionFoundAsync(item).ConfigureAwait(true);
- }
- }
+ return definitions.Select(d => factory.GetThirdPartyDefinitionItem(solution, d, cancellationToken))
+ .WhereNotNull()
+ .ToImmutableArray();
}
private async Task FindSymbolReferencesAsync(