Skip to content

Commit 14bfc40

Browse files
Clean up blocking code in snippets
1 parent 37d00bf commit 14bfc40

File tree

1 file changed

+22
-19
lines changed

1 file changed

+22
-19
lines changed

src/VisualStudio/Core/Def/Snippets/SnippetExpansionClient.cs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,13 @@ private static XDocument CreateMethodCallSnippet(string methodName, bool include
705705
private void OnModelUpdated(object sender, ModelUpdatedEventsArgs e)
706706
{
707707
_threadingContext.ThrowIfNotOnUIThread();
708+
_threadingContext.JoinableTaskFactory.Run(() => OnModelUpdatedAsync(e.NewModel, CancellationToken.None));
709+
}
708710

709-
if (e.NewModel is null)
711+
private async Task OnModelUpdatedAsync(
712+
Model? newModel, CancellationToken cancellationToken)
713+
{
714+
if (newModel is null)
710715
{
711716
// Signature Help was dismissed, but it's possible for a user to bring it back with Ctrl+Shift+Space.
712717
// Leave the snippet session (if any) in its current state to allow it to process either a subsequent
@@ -721,7 +726,7 @@ private void OnModelUpdated(object sender, ModelUpdatedEventsArgs e)
721726
return;
722727
}
723728

724-
if (!e.NewModel.UserSelected && _state._method is not null)
729+
if (!newModel.UserSelected && _state._method is not null)
725730
{
726731
// This was an implicit signature change which was not triggered by user pressing up/down, and we are
727732
// already showing an initialized argument completion snippet session, so avoid switching sessions.
@@ -739,13 +744,17 @@ private void OnModelUpdated(object sender, ModelUpdatedEventsArgs e)
739744
// TODO: The following blocks the UI thread without cancellation, but it only occurs when an argument value
740745
// completion session is active, which is behind an experimental feature flag.
741746
// https://github.com/dotnet/roslyn/issues/50634
742-
var compilation = _threadingContext.JoinableTaskFactory.Run(() => document.Project.GetRequiredCompilationAsync(CancellationToken.None));
743-
var newSymbolKey = (e.NewModel.SelectedItem as AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem)?.SymbolKey ?? default;
744-
var newSymbol = newSymbolKey.Resolve(compilation, cancellationToken: CancellationToken.None).GetAnySymbol();
747+
var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(true);
748+
var newSymbolKey = (newModel.SelectedItem as AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem)?.SymbolKey ?? default;
749+
var newSymbol = newSymbolKey.Resolve(compilation, cancellationToken: cancellationToken).GetAnySymbol();
745750
if (newSymbol is not IMethodSymbol method)
746751
return;
747752

748-
MoveToSpecificMethod(method, CancellationToken.None);
753+
await MoveToSpecificMethodAsync(
754+
document, method, cancellationToken).ConfigureAwait(true);
755+
756+
// Don't let the compilation drop as MoveToSpecificMethodAsync wants to get the semantic model for the document.
757+
GC.KeepAlive(compilation);
749758
}
750759

751760
private static async Task<ImmutableArray<ISymbol>> GetReferencedSymbolsToLeftOfCaretAsync(
@@ -771,10 +780,12 @@ private static async Task<ImmutableArray<ISymbol>> GetReferencedSymbolsToLeftOfC
771780
/// </summary>
772781
/// <param name="method">The currently-selected method in Signature Help.</param>
773782
/// <param name="cancellationToken">A cancellation token the operation may observe.</param>
774-
public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancellationToken)
783+
public async Task MoveToSpecificMethodAsync(
784+
Document document,
785+
IMethodSymbol method,
786+
CancellationToken cancellationToken)
775787
{
776-
_threadingContext.ThrowIfNotOnUIThread();
777-
788+
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
778789
if (ExpansionSession is null)
779790
{
780791
return;
@@ -804,14 +815,6 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell
804815
return;
805816
}
806817

807-
var document = SubjectBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
808-
if (document is null)
809-
{
810-
// Couldn't identify the current document
811-
ExpansionSession.EndCurrentExpansion(fLeaveCaret: 1);
812-
return;
813-
}
814-
815818
var textViewModel = TextView.TextViewModel;
816819
if (textViewModel == null)
817820
{
@@ -893,7 +896,7 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell
893896
}
894897

895898
// Now compute the new arguments for the new call
896-
var semanticModel = document.GetRequiredSemanticModelAsync(cancellationToken).AsTask().WaitAndGetResult(cancellationToken);
899+
var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(true);
897900
var position = SubjectBuffer.CurrentSnapshot.GetPosition(adjustedTextSpan.iStartLine, adjustedTextSpan.iStartIndex);
898901

899902
foreach (var parameter in method.Parameters)
@@ -903,7 +906,7 @@ public void MoveToSpecificMethod(IMethodSymbol method, CancellationToken cancell
903906
foreach (var provider in GetArgumentProviders(document.Project.Solution.Workspace))
904907
{
905908
var context = new ArgumentContext(provider, semanticModel, position, parameter, value, cancellationToken);
906-
_threadingContext.JoinableTaskFactory.Run(() => provider.ProvideArgumentAsync(context));
909+
await provider.ProvideArgumentAsync(context).ConfigureAwait(true);
907910

908911
if (context.DefaultValue is not null)
909912
{

0 commit comments

Comments
 (0)