Beispiel #1
0
        /// <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));
        }
Beispiel #2
0
        /// <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() !);
        }
Beispiel #3
0
        /// <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));
        }
Beispiel #4
0
        /// <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));
        }
Beispiel #5
0
 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));
 }