Beispiel #1
1
        internal async Task RemoveAllRenameAnnotationsAsync(IEnumerable<DocumentId> documentWithRenameAnnotations, AnnotationTable<RenameAnnotation> annotationSet, CancellationToken cancellationToken)
        {
            foreach (var documentId in documentWithRenameAnnotations)
            {
                if (_renamedSpansTracker.IsDocumentChanged(documentId))
                {
                    var document = _newSolution.GetDocument(documentId);
                    var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    // For the computeReplacementToken and computeReplacementNode functions, use 
                    // the "updated" node to maintain any annotation removals from descendants.
                    var newRoot = root.ReplaceSyntax(
                        nodes: annotationSet.GetAnnotatedNodes(root),
                        computeReplacementNode: (original, updated) => annotationSet.WithoutAnnotations(updated, annotationSet.GetAnnotations(updated).ToArray()),
                        tokens: annotationSet.GetAnnotatedTokens(root),
                        computeReplacementToken: (original, updated) => annotationSet.WithoutAnnotations(updated, annotationSet.GetAnnotations(updated).ToArray()),
                        trivia: SpecializedCollections.EmptyEnumerable<SyntaxTrivia>(),
                        computeReplacementTrivia: null);

                    _intermediateSolutionContainingOnlyModifiedDocuments = _intermediateSolutionContainingOnlyModifiedDocuments.WithDocumentSyntaxRoot(documentId, newRoot, PreservationMode.PreserveIdentity);
                }
            }

            _newSolution = _intermediateSolutionContainingOnlyModifiedDocuments;
        }
Beispiel #2
0
        internal async Task RemoveAllRenameAnnotationsAsync(IEnumerable <DocumentId> documentWithRenameAnnotations, AnnotationTable <RenameAnnotation> annotationSet, CancellationToken cancellationToken)
        {
            foreach (var documentId in documentWithRenameAnnotations)
            {
                if (_renamedSpansTracker.IsDocumentChanged(documentId))
                {
                    var document = _newSolution.GetDocument(documentId);
                    var root     = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    // For the computeReplacementToken and computeReplacementNode functions, use
                    // the "updated" node to maintain any annotation removals from descendants.
                    var newRoot = root.ReplaceSyntax(
                        nodes: annotationSet.GetAnnotatedNodes(root),
                        computeReplacementNode: (original, updated) => annotationSet.WithoutAnnotations(updated, annotationSet.GetAnnotations(updated).ToArray()),
                        tokens: annotationSet.GetAnnotatedTokens(root),
                        computeReplacementToken: (original, updated) => annotationSet.WithoutAnnotations(updated, annotationSet.GetAnnotations(updated).ToArray()),
                        trivia: SpecializedCollections.EmptyEnumerable <SyntaxTrivia>(),
                        computeReplacementTrivia: null);

                    _intermediateSolutionContainingOnlyModifiedDocuments = _intermediateSolutionContainingOnlyModifiedDocuments.WithDocumentSyntaxRoot(documentId, newRoot, PreservationMode.PreserveIdentity);
                }
            }

            _newSolution = _intermediateSolutionContainingOnlyModifiedDocuments;
        }
Beispiel #3
0
        internal void RemoveAllRenameAnnotations(IEnumerable <DocumentId> documentWithRenameAnnotations, AnnotationTable <RenameAnnotation> annotationSet, CancellationToken cancellationToken)
        {
            foreach (var documentId in documentWithRenameAnnotations)
            {
                if (this.renamedSpansTracker.IsDocumentChanged(documentId))
                {
                    var document = newSolution.GetDocument(documentId);
                    var root     = document.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                    var newRoot  = root.ReplaceSyntax(
                        annotationSet.GetAnnotatedNodes(root),
                        (original, dummy) => annotationSet.WithoutAnnotations(original, annotationSet.GetAnnotations(original).ToArray()),
                        annotationSet.GetAnnotatedTokens(root),
                        (original, dummy) => annotationSet.WithoutAnnotations(original, annotationSet.GetAnnotations(original).ToArray()),
                        SpecializedCollections.EmptyEnumerable <SyntaxTrivia>(),
                        computeReplacementTrivia: null);

                    this.intermediateSolutionContainingOnlyModifiedDocuments = this.intermediateSolutionContainingOnlyModifiedDocuments.WithDocumentSyntaxRoot(documentId, newRoot, PreservationMode.PreserveIdentity);
                }
            }

            this.newSolution = this.intermediateSolutionContainingOnlyModifiedDocuments;
        }
Beispiel #4
0
        internal void RemoveAllRenameAnnotations(IEnumerable<DocumentId> documentWithRenameAnnotations, AnnotationTable<RenameAnnotation> annotationSet, CancellationToken cancellationToken)
        {
            foreach (var documentId in documentWithRenameAnnotations)
            {
                if (this.renamedSpansTracker.IsDocumentChanged(documentId))
                {
                    var document = newSolution.GetDocument(documentId);
                    var root = document.GetSyntaxRootAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                    var newRoot = root.ReplaceSyntax(
                        annotationSet.GetAnnotatedNodes(root),
                        (original, dummy) => annotationSet.WithoutAnnotations(original, annotationSet.GetAnnotations(original).ToArray()),
                        annotationSet.GetAnnotatedTokens(root),
                        (original, dummy) => annotationSet.WithoutAnnotations(original, annotationSet.GetAnnotations(original).ToArray()),
                        SpecializedCollections.EmptyEnumerable<SyntaxTrivia>(),
                        computeReplacementTrivia: null);

                    this.intermediateSolutionContainingOnlyModifiedDocuments = this.intermediateSolutionContainingOnlyModifiedDocuments.WithDocumentSyntaxRoot(documentId, newRoot);
                }
            }

            this.newSolution = this.intermediateSolutionContainingOnlyModifiedDocuments;
        }
Beispiel #5
0
        public static async Task <TRoot> ReplaceSyntaxAsync <TRoot>(
            this TRoot root,
            IEnumerable <SyntaxNode> nodes,
            Func <SyntaxNode, SyntaxNode, CancellationToken, Task <SyntaxNode> > computeReplacementNodeAsync,
            IEnumerable <SyntaxToken> tokens,
            Func <SyntaxToken, SyntaxToken, CancellationToken, Task <SyntaxToken> > computeReplacementTokenAsync,
            IEnumerable <SyntaxTrivia> trivia,
            Func <SyntaxTrivia, SyntaxTrivia, CancellationToken, Task <SyntaxTrivia> > computeReplacementTriviaAsync,
            CancellationToken cancellationToken)
            where TRoot : SyntaxNode
        {
            // index all nodes, tokens and trivia by the full spans they cover
            var nodesToReplace = nodes != null?nodes.ToDictionary(n => n.FullSpan) : new Dictionary <TextSpan, SyntaxNode>();

            var tokensToReplace = tokens != null?tokens.ToDictionary(t => t.FullSpan) : new Dictionary <TextSpan, SyntaxToken>();

            var triviaToReplace = trivia != null?trivia.ToDictionary(t => t.FullSpan) : new Dictionary <TextSpan, SyntaxTrivia>();

            var nodeReplacements   = new Dictionary <SyntaxNode, SyntaxNode>();
            var tokenReplacements  = new Dictionary <SyntaxToken, SyntaxToken>();
            var triviaReplacements = new Dictionary <SyntaxTrivia, SyntaxTrivia>();

            var retryAnnotations = new AnnotationTable <object>("RetryReplace");

            var spans = new List <TextSpan>(nodesToReplace.Count + tokensToReplace.Count + triviaToReplace.Count);

            spans.AddRange(nodesToReplace.Keys);
            spans.AddRange(tokensToReplace.Keys);
            spans.AddRange(triviaToReplace.Keys);

            while (spans.Count > 0)
            {
                // sort the spans of the items to be replaced so we can tell if any overlap
                spans.Sort((x, y) =>
                {
                    // order by end offset, and then by length
                    var d = x.End - y.End;

                    if (d == 0)
                    {
                        d = x.Length - y.Length;
                    }

                    return(d);
                });

                // compute replacements for all nodes that will go in the same batch
                // only spans that do not overlap go in the same batch.
                TextSpan previous = default(TextSpan);
                foreach (var span in spans)
                {
                    // only add to replacement map if we don't intersect with the previous node. This taken with the sort order
                    // should ensure that parent nodes are not processed in the same batch as child nodes.
                    if (previous == default(TextSpan) || !previous.IntersectsWith(span))
                    {
                        if (nodesToReplace.TryGetValue(span, out var currentNode))
                        {
                            var original = (SyntaxNode)retryAnnotations.GetAnnotations(currentNode).SingleOrDefault() ?? currentNode;
                            var newNode  = await computeReplacementNodeAsync(original, currentNode, cancellationToken).ConfigureAwait(false);

                            nodeReplacements[currentNode] = newNode;
                        }
                        else if (tokensToReplace.TryGetValue(span, out var currentToken))
                        {
                            var original = (SyntaxToken)retryAnnotations.GetAnnotations(currentToken).SingleOrDefault();
                            if (original == default(SyntaxToken))
                            {
                                original = currentToken;
                            }

                            var newToken = await computeReplacementTokenAsync(original, currentToken, cancellationToken).ConfigureAwait(false);

                            tokenReplacements[currentToken] = newToken;
                        }
                        else if (triviaToReplace.TryGetValue(span, out var currentTrivia))
                        {
                            var original = (SyntaxTrivia)retryAnnotations.GetAnnotations(currentTrivia).SingleOrDefault();
                            if (original == default(SyntaxTrivia))
                            {
                                original = currentTrivia;
                            }

                            var newTrivia = await computeReplacementTriviaAsync(original, currentTrivia, cancellationToken).ConfigureAwait(false);

                            triviaReplacements[currentTrivia] = newTrivia;
                        }
                    }

                    previous = span;
                }

                bool retryNodes  = false;
                bool retryTokens = false;
                bool retryTrivia = false;

                // replace nodes in batch
                // submit all nodes so we can annotate the ones we don't replace
                root = root.ReplaceSyntax(
                    nodes: nodesToReplace.Values,
                    computeReplacementNode: (original, rewritten) =>
                {
                    if (rewritten != original || !nodeReplacements.TryGetValue(original, out var replaced))
                    {
                        // the subtree did change, or we didn't have a replacement for it in this batch
                        // so we need to add an annotation so we can find this node again for the next batch.
                        replaced   = retryAnnotations.WithAdditionalAnnotations(rewritten, original);
                        retryNodes = true;
                    }

                    return(replaced);
                },
                    tokens: tokensToReplace.Values,
                    computeReplacementToken: (original, rewritten) =>
                {
                    if (rewritten != original || !tokenReplacements.TryGetValue(original, out var replaced))
                    {
                        // the subtree did change, or we didn't have a replacement for it in this batch
                        // so we need to add an annotation so we can find this node again for the next batch.
                        replaced    = retryAnnotations.WithAdditionalAnnotations(rewritten, original);
                        retryTokens = true;
                    }

                    return(replaced);
                },
                    trivia: triviaToReplace.Values,
                    computeReplacementTrivia: (original, rewritten) =>
                {
                    if (!triviaReplacements.TryGetValue(original, out var replaced))
                    {
                        // the subtree did change, or we didn't have a replacement for it in this batch
                        // so we need to add an annotation so we can find this node again for the next batch.
                        replaced    = retryAnnotations.WithAdditionalAnnotations(rewritten, original);
                        retryTrivia = true;
                    }

                    return(replaced);
                });

                nodesToReplace.Clear();
                tokensToReplace.Clear();
                triviaToReplace.Clear();
                spans.Clear();

                // prepare next batch out of all remaining annotated nodes
                if (retryNodes)
                {
                    nodesToReplace = retryAnnotations.GetAnnotatedNodes(root).ToDictionary(n => n.FullSpan);
                    spans.AddRange(nodesToReplace.Keys);
                }

                if (retryTokens)
                {
                    tokensToReplace = retryAnnotations.GetAnnotatedTokens(root).ToDictionary(t => t.FullSpan);
                    spans.AddRange(tokensToReplace.Keys);
                }

                if (retryTrivia)
                {
                    triviaToReplace = retryAnnotations.GetAnnotatedTrivia(root).ToDictionary(t => t.FullSpan);
                    spans.AddRange(triviaToReplace.Keys);
                }
            }

            return(root);
        }