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; }
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; }
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; }
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; }
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); }