Skip to content

Commit

Permalink
Avoid Task allocations in common document extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
sharwell committed Oct 6, 2020
1 parent 6344c7a commit 4646331
Show file tree
Hide file tree
Showing 8 changed files with 25 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public SemanticModelReuseWorkspaceService(Workspace _)
{
}

public Task<SemanticModel> ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken)
public ValueTask<SemanticModel> ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken)
{
// TODO: port the GetSemanticModelForNodeAsync implementation from Workspaces layer,
// which currently relies on a bunch of internal APIs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public override string ToString()

internal AddedParameter GetAddedParameter(Document document)
{
var semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).Result;
var semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).AsTask().Result;

var type = document.Project.Language switch
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ private void FormatDocumentCreatedFromTemplate(IVsHierarchy hierarchy, uint item

// Organize using directives
addedDocument = ThreadHelper.JoinableTaskFactory.Run(() => OrganizeUsingsCreatedFromTemplateAsync(addedDocument, cancellationToken));
rootToFormat = ThreadHelper.JoinableTaskFactory.Run(() => addedDocument.GetRequiredSyntaxRootAsync(cancellationToken));
rootToFormat = ThreadHelper.JoinableTaskFactory.Run(() => addedDocument.GetRequiredSyntaxRootAsync(cancellationToken).AsTask());

// Format document
var unformattedText = addedDocument.GetTextSynchronously(cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ internal class AddParameterDialogViewModel : AbstractNotifyPropertyChanged
public AddParameterDialogViewModel(Document document, int positionForTypeBinding)
{
_notificationService = document.Project.Solution.Workspace.Services.GetService<INotificationService>();
_semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).WaitAndGetResult_CanCallOnBackground(CancellationToken.None);
_semanticModel = document.GetRequiredSemanticModelAsync(CancellationToken.None).AsTask().WaitAndGetResult_CanCallOnBackground(CancellationToken.None);

TypeIsEmptyImage = Visibility.Visible;
TypeBindsImage = Visibility.Collapsed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api
internal static class PythiaDocumentExtensions
{
public static Task<SemanticModel> GetSemanticModelForNodeAsync(this Document document, SyntaxNode? node, CancellationToken cancellationToken)
=> DocumentExtensions.ReuseExistingSpeculativeModelAsync(document, node, cancellationToken);
=> DocumentExtensions.ReuseExistingSpeculativeModelAsync(document, node, cancellationToken).AsTask();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public SemanticModelReuseWorkspaceService(Workspace workspace)
};
}

public async Task<SemanticModel> ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken)
public async ValueTask<SemanticModel> ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken)
{
var reuseService = document.GetRequiredLanguageService<ISemanticModelReuseLanguageService>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.GeneratedCodeRecognition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.SemanticModelReuse;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
Expand All @@ -30,15 +29,21 @@ internal static partial class DocumentExtensions
public static TLanguageService GetRequiredLanguageService<TLanguageService>(this Document document) where TLanguageService : class, ILanguageService
=> document.Project.GetRequiredLanguageService<TLanguageService>();

public static async Task<SemanticModel> GetRequiredSemanticModelAsync(this Document document, CancellationToken cancellationToken)
public static async ValueTask<SemanticModel> GetRequiredSemanticModelAsync(this Document document, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
if (document.TryGetSemanticModel(out var semanticModel))
return semanticModel;

semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
return semanticModel ?? throw new InvalidOperationException(string.Format(WorkspaceExtensionsResources.SyntaxTree_is_required_to_accomplish_the_task_but_is_not_supported_by_document_0, document.Name));
}

public static async Task<SyntaxTree> GetRequiredSyntaxTreeAsync(this Document document, CancellationToken cancellationToken)
public static async ValueTask<SyntaxTree> GetRequiredSyntaxTreeAsync(this Document document, CancellationToken cancellationToken)
{
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
if (document.TryGetSyntaxTree(out var syntaxTree))
return syntaxTree;

syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
return syntaxTree ?? throw new InvalidOperationException(string.Format(WorkspaceExtensionsResources.SyntaxTree_is_required_to_accomplish_the_task_but_is_not_supported_by_document_0, document.Name));
}

Expand All @@ -50,9 +55,12 @@ public static SyntaxTree GetRequiredSyntaxTreeSynchronously(this Document docume
}
#endif

public static async Task<SyntaxNode> GetRequiredSyntaxRootAsync(this Document document, CancellationToken cancellationToken)
public static async ValueTask<SyntaxNode> GetRequiredSyntaxRootAsync(this Document document, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
if (document.TryGetSyntaxRoot(out var root))
return root;

root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
return root ?? throw new InvalidOperationException(string.Format(WorkspaceExtensionsResources.SyntaxTree_is_required_to_accomplish_the_task_but_is_not_supported_by_document_0, document.Name));
}

Expand All @@ -76,7 +84,7 @@ public static bool IsOpen(this TextDocument document)
/// <para/>
/// As a speculative semantic model may be returned, location based information provided by it may be innacurate.
/// </summary>
public static Task<SemanticModel> ReuseExistingSpeculativeModelAsync(this Document document, int position, CancellationToken cancellationToken)
public static ValueTask<SemanticModel> ReuseExistingSpeculativeModelAsync(this Document document, int position, CancellationToken cancellationToken)
=> ReuseExistingSpeculativeModelAsync(document, new TextSpan(position, 0), cancellationToken);

/// <summary>
Expand All @@ -93,7 +101,7 @@ public static Task<SemanticModel> ReuseExistingSpeculativeModelAsync(this Docume
/// <para/>
/// As a speculative semantic model may be returned, location based information provided by it may be innacurate.
/// </summary>
public static async Task<SemanticModel> ReuseExistingSpeculativeModelAsync(this Document document, TextSpan span, CancellationToken cancellationToken)
public static async ValueTask<SemanticModel> ReuseExistingSpeculativeModelAsync(this Document document, TextSpan span, CancellationToken cancellationToken)
{
Contract.ThrowIfFalse(document.SupportsSemanticModel);

Expand All @@ -118,7 +126,7 @@ public static async Task<SemanticModel> ReuseExistingSpeculativeModelAsync(this
/// <para/>
/// As a speculative semantic model may be returned, location based information provided by it may be innacurate.
/// </summary>
public static Task<SemanticModel> ReuseExistingSpeculativeModelAsync(this Document document, SyntaxNode? node, CancellationToken cancellationToken)
public static ValueTask<SemanticModel> ReuseExistingSpeculativeModelAsync(this Document document, SyntaxNode? node, CancellationToken cancellationToken)
{
if (node == null)
return document.GetRequiredSemanticModelAsync(cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ internal interface ISemanticModelReuseWorkspaceService : IWorkspaceService
/// <summary>
/// Don't call this directly. use <see cref="DocumentExtensions.ReuseExistingSpeculativeModelAsync(Document, SyntaxNode, CancellationToken)"/> (or an overload).
/// </summary>
Task<SemanticModel> ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken);
ValueTask<SemanticModel> ReuseExistingSpeculativeModelAsync(Document document, SyntaxNode node, CancellationToken cancellationToken);
}
}

0 comments on commit 4646331

Please sign in to comment.