/// <summary> /// Gets the <see cref="SyntaxTree" /> for this document asynchronously. /// </summary> public Task <SyntaxTree> GetSyntaxTreeAsync(CancellationToken cancellationToken = default(CancellationToken)) { // If the language doesn't support getting syntax trees for a document, then bail out immediately. if (!this.SupportsSyntaxTree) { return(SpecializedTasks.Default <SyntaxTree>()); } // if we have a cached result task use it if (_syntaxTreeResultTask != null) { return(_syntaxTreeResultTask); } // check to see if we already have the tree before actually going async if (TryGetSyntaxTree(out var tree)) { // stash a completed result task for this value for the next request (to reduce extraneous allocations of tasks) // don't use the actual async task because it depends on a specific cancellation token // its okay to cache the task and hold onto the SyntaxTree, because the DocumentState already keeps the SyntaxTree alive. Interlocked.CompareExchange(ref _syntaxTreeResultTask, Task.FromResult(tree), null); return(_syntaxTreeResultTask); } // do it async for real. return(DocumentState.GetSyntaxTreeAsync(cancellationToken)); }
/// <summary> /// Gets the <see cref="SyntaxTree" /> for this document asynchronously. /// </summary> /// <returns> /// The returned syntax tree can be <see langword="null"/> if the <see cref="SupportsSyntaxTree"/> returns <see /// langword="false"/>. This function may cause computation to occur the first time it is called, but will return /// a cached result every subsequent time. <see cref="SyntaxTree"/>'s can hold onto their roots lazily. So calls /// to <see cref="SyntaxTree.GetRoot"/> or <see cref="SyntaxTree.GetRootAsync"/> may end up causing computation /// to occur at that point. /// </returns> public Task <SyntaxTree?> GetSyntaxTreeAsync(CancellationToken cancellationToken = default) { // If the language doesn't support getting syntax trees for a document, then bail out immediately. if (!this.SupportsSyntaxTree) { return(SpecializedTasks.Null <SyntaxTree>()); } // if we have a cached result task use it if (_syntaxTreeResultTask != null) { // _syntaxTreeResultTask is a Task<SyntaxTree> so the ! operator here isn't suppressing a possible null ref, but rather allowing the // conversion from Task<SyntaxTree> to Task<SyntaxTree?> since Task itself isn't properly variant. return(_syntaxTreeResultTask !); } // check to see if we already have the tree before actually going async if (TryGetSyntaxTree(out var tree)) { // stash a completed result task for this value for the next request (to reduce extraneous allocations of tasks) // don't use the actual async task because it depends on a specific cancellation token // its okay to cache the task and hold onto the SyntaxTree, because the DocumentState already keeps the SyntaxTree alive. Interlocked.CompareExchange(ref _syntaxTreeResultTask, Task.FromResult(tree), null); // _syntaxTreeResultTask is a Task<SyntaxTree> so the ! operator here isn't suppressing a possible null ref, but rather allowing the // conversion from Task<SyntaxTree> to Task<SyntaxTree?> since Task itself isn't properly variant. return(_syntaxTreeResultTask !); } // do it async for real. // GetSyntaxTreeAsync returns a Task<SyntaxTree> so the ! operator here isn't suppressing a possible null ref, but rather allowing the // conversion from Task<SyntaxTree> to Task<SyntaxTree?> since Task itself isn't properly variant. return(DocumentState.GetSyntaxTreeAsync(cancellationToken).AsTask() !); }
/// <summary> /// Gets the <see cref="SyntaxTree" /> for this document asynchronously. /// </summary> public Task <SyntaxTree> GetSyntaxTreeAsync(CancellationToken cancellationToken = default(CancellationToken)) { // If the language doesn't support getting syntax trees for a document, then bail out // immediately. if (!this.SupportsSyntaxTree) { return(SpecializedTasks.Default <SyntaxTree>()); } if (_syntaxTreeResultTask != null) { return(_syntaxTreeResultTask); } // First see if we already have a semantic model computed. If so, we can just return // that syntax tree. SemanticModel semanticModel; if (TryGetSemanticModel(out semanticModel)) { // PERF: This is a hot code path, so cache the result to reduce allocations var result = Task.FromResult(semanticModel.SyntaxTree); Interlocked.CompareExchange(ref _syntaxTreeResultTask, result, null); return(_syntaxTreeResultTask); } // second, see whether we already computed the tree, if we already did, return the cache SyntaxTree tree; if (TryGetSyntaxTree(out tree)) { if (_syntaxTreeResultTask == null) { var result = Task.FromResult(tree); Interlocked.CompareExchange(ref _syntaxTreeResultTask, result, null); } return(_syntaxTreeResultTask); } // we can't cache this result, since internally it uses AsyncLazy which // care about cancellation token return(_state.GetSyntaxTreeAsync(cancellationToken)); }
/// <summary> /// Gets the <see cref="SyntaxTree" /> for this document asynchronously. /// </summary> public Task <SyntaxTree> GetSyntaxTreeAsync(CancellationToken cancellationToken = default(CancellationToken)) { // If the language doesn't support getting syntax trees for a document, then bail out // immediately. if (!this.SupportsSyntaxTree) { return(SpecializedTasks.Default <SyntaxTree>()); } var syntaxTreeTask = GetExistingSyntaxTreeTask(); if (syntaxTreeTask != null) { return(syntaxTreeTask); } // we can't cache this result, since internally it uses AsyncLazy which // care about cancellation token return(DocumentState.GetSyntaxTreeAsync(cancellationToken)); }
private static async Task<Compilation> UpdateDocumentInCompilationAsync( Compilation compilation, DocumentState oldDocument, DocumentState newDocument, CancellationToken cancellationToken) { return compilation.ReplaceSyntaxTree( await oldDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false), await newDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); }