private SyntaxNode ReplaceTokens( SyntaxNode root, IEnumerable<SyntaxToken> oldTokens, Func<SyntaxToken, SyntaxToken, SyntaxToken> computeReplacementToken) { return root.ReplaceTokens(oldTokens, (o, n) => computeReplacementToken(o, n)); }
public SyntaxNode RestoreTrivia( SyntaxNode root, AnnotationResolver annotationResolver = null, TriviaResolver triviaResolver = null) { var tokens = RecoverTokensAtEdges(root, annotationResolver); var map = CreateOldToNewTokensMap(tokens, triviaResolver); return root.ReplaceTokens(map.Keys, (o, n) => map[o]); }
private SyntaxNode ReplaceTokens( SyntaxNode root, IEnumerable<SyntaxToken> oldTokens, Func<SyntaxToken, SyntaxToken, SyntaxToken> computeReplacementToken) { Contract.ThrowIfNull(root); Contract.ThrowIfNull(oldTokens); Contract.ThrowIfNull(computeReplacementToken); return root.ReplaceTokens(oldTokens, (o, n) => computeReplacementToken(o, n)); }
/// <summary> /// Fix the new lines around open brace tokens. An open brace should be followed by content, not a blank /// line. Remove those here. /// </summary> private static SyntaxNode FixOpenBraces(SyntaxNode syntaxNode) { // Look for the open brace tokens that are followed by empty blank lines. The new lines will // be attached to the next nodes, not the open brace token. var tokensToReplace = syntaxNode.DescendantTokens().Where((token) => { var nextToken = token.GetNextToken(); if (token.Kind() != SyntaxKind.OpenBraceToken || !nextToken.HasLeadingTrivia) { return false; } return IsSimpleNewLine(nextToken.LeadingTrivia, 0); }).Select(x => x.GetNextToken()); return syntaxNode.ReplaceTokens(tokensToReplace, (_, y) => FixOpenBraceNextToken(y)); }
SyntaxNode ISyntaxRule.Process(SyntaxNode root) { var braceTokenNeighbors = root.DescendantTokens() .Where(t => t.IsKind(SyntaxKind.OpenBraceToken) || (t.IsKind(SyntaxKind.CloseBraceToken) && t.GetPreviousToken().IsKind(SyntaxKind.OpenBraceToken)) ) .ToDictionary( t => t.IsKind(SyntaxKind.OpenBraceToken) ? t.GetNextToken() : t.GetPreviousToken(), t => t.Kind() ); var processed = root.ReplaceTokens( braceTokenNeighbors.Keys, (orig, t) => braceTokenNeighbors[orig] == SyntaxKind.OpenBraceToken ? ProcessTokenAfterOpenBrace(t) : ProcessTokenBeforeCloseBrace(t) ); return processed; }
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, SyntaxToken token) { Dictionary<SyntaxToken, SyntaxToken> replacements = new Dictionary<SyntaxToken, SyntaxToken>(); // check for a following space bool missingFollowingSpace = true; if (token.HasTrailingTrivia) { if (token.TrailingTrivia.First().IsKind(SyntaxKind.WhitespaceTrivia)) { missingFollowingSpace = false; } else if (token.TrailingTrivia.First().IsKind(SyntaxKind.EndOfLineTrivia)) { missingFollowingSpace = false; } } else { SyntaxToken nextToken = token.GetNextToken(); if (nextToken.IsKind(SyntaxKind.CommaToken) || nextToken.IsKind(SyntaxKind.GreaterThanToken) || nextToken.IsKind(SyntaxKind.CloseBracketToken)) { // make an exception for things like typeof(Func<,>), typeof(Func<,,>), and int[,] missingFollowingSpace = false; } } if (!token.IsFirstInLine()) { SyntaxToken precedingToken = token.GetPreviousToken(); if (precedingToken.TrailingTrivia.Any(SyntaxKind.WhitespaceTrivia)) { SyntaxToken corrected = precedingToken.WithoutTrailingWhitespace().WithoutFormatting(); replacements[precedingToken] = corrected; } } if (missingFollowingSpace) { SyntaxToken intermediate = token.WithoutTrailingWhitespace(); SyntaxToken corrected = intermediate .WithTrailingTrivia(intermediate.TrailingTrivia.Insert(0, SyntaxFactory.Space)); replacements[token] = corrected; } var transformed = root.ReplaceTokens(replacements.Keys, (original, maybeRewritten) => replacements[original]); return Task.FromResult(document.WithSyntaxRoot(transformed)); }
private static SyntaxNode StripMultipleBlankLines(SyntaxNode syntaxRoot) { var replaceMap = new Dictionary<SyntaxToken, SyntaxToken>(); var usingDirectives = syntaxRoot.GetAnnotatedNodes(UsingCodeFixAnnotation).Cast<UsingDirectiveSyntax>(); foreach (var usingDirective in usingDirectives) { var nextToken = usingDirective.SemicolonToken.GetNextToken(true); // start at -1 to compensate for the always present end-of-line. var count = -1; // count the blanks lines at the end of the using statement. foreach (var trivia in usingDirective.SemicolonToken.TrailingTrivia.Reverse()) { if (!trivia.IsKind(SyntaxKind.EndOfLineTrivia)) { break; } count++; } // count the blank lines at the start of the next token foreach (var trivia in nextToken.LeadingTrivia) { if (!trivia.IsKind(SyntaxKind.EndOfLineTrivia)) { break; } count++; } if (count > 1) { replaceMap[nextToken] = nextToken.WithLeadingTrivia(nextToken.LeadingTrivia.Skip(count - 1)); } } var newSyntaxRoot = syntaxRoot.ReplaceTokens(replaceMap.Keys, (original, rewritten) => replaceMap[original]); return newSyntaxRoot; }
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, SyntaxToken token) { bool precededBySpace; bool followsSpecialCharacter; Dictionary<SyntaxToken, SyntaxToken> replacements = new Dictionary<SyntaxToken, SyntaxToken>(); if (!token.IsFirstInLine()) { SyntaxToken precedingToken = token.GetPreviousToken(); precededBySpace = precedingToken.TrailingTrivia.Any(SyntaxKind.WhitespaceTrivia); followsSpecialCharacter = precedingToken.IsKind(SyntaxKind.OpenBracketToken) || precedingToken.IsKind(SyntaxKind.OpenParenToken) || precedingToken.IsKind(SyntaxKind.CloseParenToken); if (followsSpecialCharacter && precededBySpace) { SyntaxToken correctedPreceding = precedingToken.WithoutTrailingWhitespace().WithoutFormatting(); replacements.Add(precedingToken, correctedPreceding); } else if (!followsSpecialCharacter && !precededBySpace) { SyntaxToken correctedPreceding = precedingToken.WithoutTrailingWhitespace(); SyntaxTrivia whitespace = SyntaxFactory.ElasticSpace; correctedPreceding = correctedPreceding .WithTrailingTrivia(correctedPreceding.TrailingTrivia.Add(whitespace)) .WithoutFormatting(); replacements.Add(precedingToken, correctedPreceding); } } if (token.TrailingTrivia.Any(SyntaxKind.WhitespaceTrivia) || token.TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia)) { SyntaxToken corrected = token.WithoutTrailingWhitespace(removeEndOfLineTrivia: true).WithoutFormatting(); replacements.Add(token, corrected); } var transformed = root.ReplaceTokens(replacements.Keys, (original, maybeRewritten) => replacements[original]); Document updatedDocument = document.WithSyntaxRoot(transformed); return Task.FromResult(updatedDocument); }
/// <summary> /// Close braces should never have a newline between the last line of content and the /// closing brace. Also want to remove consecutive new lines before any comments or /// #pragma that preceeds the close brace. /// </summary> private static SyntaxNode FixCloseBraces(SyntaxNode syntaxNode) { var tokensToReplace = syntaxNode.DescendantTokens().Where((token) => { return token.Kind() == SyntaxKind.CloseBraceToken && token.HasLeadingTrivia && (IsSimpleNewLine(token.LeadingTrivia, 0) || IsSimpleNewLine(token.LeadingTrivia, token.LeadingTrivia.Count - 1)); }); return syntaxNode.ReplaceTokens(tokensToReplace, (_, y) => FixCloseBraceLeadingTrivia(y)); }
private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, SyntaxToken token) { Dictionary<SyntaxToken, SyntaxToken> replacements = new Dictionary<SyntaxToken, SyntaxToken>(); if (!token.IsFirstInLine()) { SyntaxToken precedingToken = token.GetPreviousToken(); if (precedingToken.TrailingTrivia.Any(SyntaxKind.WhitespaceTrivia)) { SyntaxToken corrected = precedingToken.WithoutTrailingWhitespace().WithoutFormatting(); replacements[precedingToken] = corrected; } } if (!token.TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia) && token.TrailingTrivia.Any(SyntaxKind.WhitespaceTrivia)) { bool ignoreTrailingWhitespace; SyntaxToken nextToken = token.GetNextToken(); switch (nextToken.Kind()) { case SyntaxKind.CloseBracketToken: case SyntaxKind.OpenParenToken: case SyntaxKind.CommaToken: case SyntaxKind.SemicolonToken: // TODO: "certain types of operator symbols" case SyntaxKind.DotToken: case SyntaxKind.OpenBracketToken: case SyntaxKind.CloseParenToken: ignoreTrailingWhitespace = true; break; case SyntaxKind.GreaterThanToken: ignoreTrailingWhitespace = nextToken.Parent.IsKind(SyntaxKind.TypeArgumentList); break; case SyntaxKind.QuestionToken: ignoreTrailingWhitespace = nextToken.Parent.IsKind(SyntaxKind.ConditionalAccessExpression); break; case SyntaxKind.IdentifierToken: ignoreTrailingWhitespace = token.Parent.IsKind(SyntaxKind.ArrayRankSpecifier); break; default: ignoreTrailingWhitespace = false; break; } if (!ignoreTrailingWhitespace) { SyntaxToken corrected = token.WithoutTrailingWhitespace().WithoutFormatting(); replacements[token] = corrected; } } if (replacements.Count == 0) { return Task.FromResult(document); } var transformed = root.ReplaceTokens(replacements.Keys, (original, maybeRewritten) => replacements[original]); Document updatedDocument = document.WithSyntaxRoot(transformed); return Task.FromResult(updatedDocument); }