|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.CodeAnalysis
{
public static partial class SyntaxNodeExtensions
{
/// <summary>
/// Creates a new tree of nodes with the specified nodes, tokens and trivia replaced.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node of the tree of nodes.</param>
/// <param name="nodes">The nodes to be replaced.</param>
/// <param name="computeReplacementNode">A function that computes a replacement node for the
/// argument nodes. The first argument is the original node. The second argument is the same
/// node potentially rewritten with replaced descendants.</param>
/// <param name="tokens">The tokens to be replaced.</param>
/// <param name="computeReplacementToken">A function that computes a replacement token for
/// the argument tokens. The first argument is the original token. The second argument is
/// the same token potentially rewritten with replaced trivia.</param>
/// <param name="trivia">The trivia to be replaced.</param>
/// <param name="computeReplacementTrivia">A function that computes replacement trivia for
/// the specified arguments. The first argument is the original trivia. The second argument is
/// the same trivia with potentially rewritten sub structure.</param>
public static TRoot ReplaceSyntax<TRoot>(
this TRoot root,
IEnumerable<SyntaxNode>? nodes,
Func<SyntaxNode, SyntaxNode, SyntaxNode>? computeReplacementNode,
IEnumerable<SyntaxToken>? tokens,
Func<SyntaxToken, SyntaxToken, SyntaxToken>? computeReplacementToken,
IEnumerable<SyntaxTrivia>? trivia,
Func<SyntaxTrivia, SyntaxTrivia, SyntaxTrivia>? computeReplacementTrivia)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceCore(
nodes: nodes, computeReplacementNode: computeReplacementNode,
tokens: tokens, computeReplacementToken: computeReplacementToken,
trivia: trivia, computeReplacementTrivia: computeReplacementTrivia);
}
/// <summary>
/// Creates a new tree of nodes with the specified old node replaced with a new node.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <typeparam name="TNode">The type of the nodes being replaced.</typeparam>
/// <param name="root">The root node of the tree of nodes.</param>
/// <param name="nodes">The nodes to be replaced; descendants of the root node.</param>
/// <param name="computeReplacementNode">A function that computes a replacement node for the
/// argument nodes. The first argument is the original node. The second argument is the same
/// node potentially rewritten with replaced descendants.</param>
public static TRoot ReplaceNodes<TRoot, TNode>(this TRoot root, IEnumerable<TNode> nodes, Func<TNode, TNode, SyntaxNode> computeReplacementNode)
where TRoot : SyntaxNode
where TNode : SyntaxNode
{
return (TRoot)root.ReplaceCore(nodes: nodes, computeReplacementNode: computeReplacementNode);
}
/// <summary>
/// Creates a new tree of nodes with the specified old node replaced with a new node.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node of the tree of nodes.</param>
/// <param name="oldNode">The node to be replaced; a descendant of the root node.</param>
/// <param name="newNode">The new node to use in the new tree in place of the old node.</param>
public static TRoot ReplaceNode<TRoot>(this TRoot root, SyntaxNode oldNode, SyntaxNode newNode)
where TRoot : SyntaxNode
{
if (oldNode == newNode)
{
return root;
}
return (TRoot)root.ReplaceCore(nodes: new[] { oldNode }, computeReplacementNode: (o, r) => newNode);
}
/// <summary>
/// Creates a new tree of nodes with specified old node replaced with a new nodes.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="oldNode">The node to be replaced; a descendant of the root node and an element of a list member.</param>
/// <param name="newNodes">A sequence of nodes to use in the tree in place of the old node.</param>
public static TRoot ReplaceNode<TRoot>(this TRoot root, SyntaxNode oldNode, IEnumerable<SyntaxNode> newNodes)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceNodeInListCore(oldNode, newNodes);
}
/// <summary>
/// Creates a new tree of nodes with new nodes inserted before the specified node.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="nodeInList">The node to insert before; a descendant of the root node an element of a list member.</param>
/// <param name="newNodes">A sequence of nodes to insert into the tree immediately before the specified node.</param>
public static TRoot InsertNodesBefore<TRoot>(this TRoot root, SyntaxNode nodeInList, IEnumerable<SyntaxNode> newNodes)
where TRoot : SyntaxNode
{
return (TRoot)root.InsertNodesInListCore(nodeInList, newNodes, insertBefore: true);
}
/// <summary>
/// Creates a new tree of nodes with new nodes inserted after the specified node.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="nodeInList">The node to insert after; a descendant of the root node an element of a list member.</param>
/// <param name="newNodes">A sequence of nodes to insert into the tree immediately after the specified node.</param>
public static TRoot InsertNodesAfter<TRoot>(this TRoot root, SyntaxNode nodeInList, IEnumerable<SyntaxNode> newNodes)
where TRoot : SyntaxNode
{
return (TRoot)root.InsertNodesInListCore(nodeInList, newNodes, insertBefore: false);
}
/// <summary>
/// Creates a new tree of nodes with the specified old token replaced with new tokens.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="tokenInList">The token to be replaced; a descendant of the root node and an element of a list member.</param>
/// <param name="newTokens">A sequence of tokens to use in the tree in place of the specified token.</param>
public static TRoot ReplaceToken<TRoot>(this TRoot root, SyntaxToken tokenInList, IEnumerable<SyntaxToken> newTokens)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceTokenInListCore(tokenInList, newTokens);
}
/// <summary>
/// Creates a new tree of nodes with new tokens inserted before the specified token.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="tokenInList">The token to insert before; a descendant of the root node and an element of a list member.</param>
/// <param name="newTokens">A sequence of tokens to insert into the tree immediately before the specified token.</param>
public static TRoot InsertTokensBefore<TRoot>(this TRoot root, SyntaxToken tokenInList, IEnumerable<SyntaxToken> newTokens)
where TRoot : SyntaxNode
{
return (TRoot)root.InsertTokensInListCore(tokenInList, newTokens, insertBefore: true);
}
/// <summary>
/// Creates a new tree of nodes with new tokens inserted after the specified token.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="tokenInList">The token to insert after; a descendant of the root node and an element of a list member.</param>
/// <param name="newTokens">A sequence of tokens to insert into the tree immediately after the specified token.</param>
public static TRoot InsertTokensAfter<TRoot>(this TRoot root, SyntaxToken tokenInList, IEnumerable<SyntaxToken> newTokens)
where TRoot : SyntaxNode
{
return (TRoot)root.InsertTokensInListCore(tokenInList, newTokens, insertBefore: false);
}
/// <summary>
/// Creates a new tree of nodes with the specified old trivia replaced with new trivia.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="oldTrivia">The trivia to be replaced; a descendant of the root node.</param>
/// <param name="newTrivia">A sequence of trivia to use in the tree in place of the specified trivia.</param>
public static TRoot ReplaceTrivia<TRoot>(this TRoot root, SyntaxTrivia oldTrivia, IEnumerable<SyntaxTrivia> newTrivia)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceTriviaInListCore(oldTrivia, newTrivia);
}
/// <summary>
/// Creates a new tree of nodes with new trivia inserted before the specified trivia.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="trivia">The trivia to insert before; a descendant of the root node.</param>
/// <param name="newTrivia">A sequence of trivia to insert into the tree immediately before the specified trivia.</param>
public static TRoot InsertTriviaBefore<TRoot>(this TRoot root, SyntaxTrivia trivia, IEnumerable<SyntaxTrivia> newTrivia)
where TRoot : SyntaxNode
{
return (TRoot)root.InsertTriviaInListCore(trivia, newTrivia, insertBefore: true);
}
/// <summary>
/// Creates a new tree of nodes with new trivia inserted after the specified trivia.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root of the tree of nodes.</param>
/// <param name="trivia">The trivia to insert after; a descendant of the root node.</param>
/// <param name="newTrivia">A sequence of trivia to insert into the tree immediately after the specified trivia.</param>
public static TRoot InsertTriviaAfter<TRoot>(this TRoot root, SyntaxTrivia trivia, IEnumerable<SyntaxTrivia> newTrivia)
where TRoot : SyntaxNode
{
return (TRoot)root.InsertTriviaInListCore(trivia, newTrivia, insertBefore: false);
}
/// <summary>
/// Creates a new tree of nodes with the specified old node replaced with a new node.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node of the tree of nodes.</param>
/// <param name="tokens">The token to be replaced; descendants of the root node.</param>
/// <param name="computeReplacementToken">A function that computes a replacement token for
/// the argument tokens. The first argument is the original token. The second argument is
/// the same token potentially rewritten with replaced trivia.</param>
public static TRoot ReplaceTokens<TRoot>(this TRoot root, IEnumerable<SyntaxToken> tokens, Func<SyntaxToken, SyntaxToken, SyntaxToken> computeReplacementToken)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceCore<SyntaxNode>(tokens: tokens, computeReplacementToken: computeReplacementToken);
}
/// <summary>
/// Creates a new tree of nodes with the specified old token replaced with a new token.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node of the tree of nodes.</param>
/// <param name="oldToken">The token to be replaced.</param>
/// <param name="newToken">The new token to use in the new tree in place of the old
/// token.</param>
public static TRoot ReplaceToken<TRoot>(this TRoot root, SyntaxToken oldToken, SyntaxToken newToken)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceCore<SyntaxNode>(tokens: new[] { oldToken }, computeReplacementToken: (o, r) => newToken);
}
/// <summary>
/// Creates a new tree of nodes with the specified trivia replaced with new trivia.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node of the tree of nodes.</param>
/// <param name="trivia">The trivia to be replaced; descendants of the root node.</param>
/// <param name="computeReplacementTrivia">A function that computes replacement trivia for
/// the specified arguments. The first argument is the original trivia. The second argument is
/// the same trivia with potentially rewritten sub structure.</param>
public static TRoot ReplaceTrivia<TRoot>(this TRoot root, IEnumerable<SyntaxTrivia> trivia, Func<SyntaxTrivia, SyntaxTrivia, SyntaxTrivia> computeReplacementTrivia)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceCore<SyntaxNode>(trivia: trivia, computeReplacementTrivia: computeReplacementTrivia);
}
/// <summary>
/// Creates a new tree of nodes with the specified trivia replaced with new trivia.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node of the tree of nodes.</param>
/// <param name="trivia">The trivia to be replaced.</param>
/// <param name="newTrivia">The new trivia to use in the new tree in place of the old trivia.</param>
public static TRoot ReplaceTrivia<TRoot>(this TRoot root, SyntaxTrivia trivia, SyntaxTrivia newTrivia)
where TRoot : SyntaxNode
{
return (TRoot)root.ReplaceCore<SyntaxNode>(trivia: new[] { trivia }, computeReplacementTrivia: (o, r) => newTrivia);
}
/// <summary>
/// Creates a new tree of nodes with the specified node removed.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node from which to remove a descendant node from.</param>
/// <param name="node">The node to remove.</param>
/// <param name="options">Options that determine how the node's trivia is treated.</param>
/// <returns>New root or null if the root node itself is removed.</returns>
public static TRoot? RemoveNode<TRoot>(this TRoot root,
SyntaxNode node,
SyntaxRemoveOptions options)
where TRoot : SyntaxNode
{
return (TRoot?)root.RemoveNodesCore(new[] { node }, options);
}
/// <summary>
/// Creates a new tree of nodes with the specified nodes removed.
/// </summary>
/// <typeparam name="TRoot">The type of the root node.</typeparam>
/// <param name="root">The root node from which to remove a descendant node from.</param>
/// <param name="nodes">The nodes to remove.</param>
/// <param name="options">Options that determine how the nodes' trivia is treated.</param>
public static TRoot? RemoveNodes<TRoot>(
this TRoot root,
IEnumerable<SyntaxNode> nodes,
SyntaxRemoveOptions options)
where TRoot : SyntaxNode
{
return (TRoot?)root.RemoveNodesCore(nodes, options);
}
internal const string DefaultIndentation = " ";
internal const string DefaultEOL = "\r\n";
/// <summary>
/// Creates a new syntax node with all whitespace and end of line trivia replaced with
/// regularly formatted trivia.
/// </summary>
/// <typeparam name="TNode">The type of the node.</typeparam>
/// <param name="node">The node to format.</param>
/// <param name="indentation">A sequence of whitespace characters that defines a single level of indentation.</param>
/// <param name="elasticTrivia">If true the replaced trivia is elastic trivia.</param>
public static TNode NormalizeWhitespace<TNode>(this TNode node, string indentation, bool elasticTrivia)
where TNode : SyntaxNode
{
return (TNode)node.NormalizeWhitespaceCore(indentation, DefaultEOL, elasticTrivia);
}
/// <summary>
/// Creates a new syntax node with all whitespace and end of line trivia replaced with
/// regularly formatted trivia.
/// </summary>
/// <typeparam name="TNode">The type of the node.</typeparam>
/// <param name="node">The node to format.</param>
/// <param name="indentation">An optional sequence of whitespace characters that defines a single level of indentation.</param>
/// <param name="eol">An optional sequence of whitespace characters used for end of line.</param>
/// <param name="elasticTrivia">If true the replaced trivia is elastic trivia.</param>
public static TNode NormalizeWhitespace<TNode>(this TNode node, string indentation = DefaultIndentation, string eol = DefaultEOL, bool elasticTrivia = false)
where TNode : SyntaxNode
{
return (TNode)node.NormalizeWhitespaceCore(indentation, eol, elasticTrivia);
}
/// <summary>
/// Creates a new node from this node with both the leading and trailing trivia of the specified node.
/// </summary>
public static TSyntax WithTriviaFrom<TSyntax>(this TSyntax syntax, SyntaxNode node)
where TSyntax : SyntaxNode
{
return syntax.WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia());
}
/// <summary>
/// Creates a new node from this node without leading or trailing trivia.
/// </summary>
public static TSyntax WithoutTrivia<TSyntax>(this TSyntax syntax)
where TSyntax : SyntaxNode
{
return syntax.WithoutLeadingTrivia().WithoutTrailingTrivia();
}
/// <summary>
/// Creates a new token from this token without leading or trailing trivia.
/// </summary>
public static SyntaxToken WithoutTrivia(this SyntaxToken token)
=> token.WithTrailingTrivia(default(SyntaxTriviaList))
.WithLeadingTrivia(default(SyntaxTriviaList));
/// <summary>
/// Creates a new node from this node with the leading trivia replaced.
/// </summary>
public static TSyntax WithLeadingTrivia<TSyntax>(
this TSyntax node,
SyntaxTriviaList trivia) where TSyntax : SyntaxNode
{
var first = node.GetFirstToken(includeZeroWidth: true);
var newFirst = first.WithLeadingTrivia(trivia);
return node.ReplaceToken(first, newFirst);
}
/// <summary>
/// Creates a new node from this node with the leading trivia replaced.
/// </summary>
public static TSyntax WithLeadingTrivia<TSyntax>(
this TSyntax node,
IEnumerable<SyntaxTrivia>? trivia) where TSyntax : SyntaxNode
{
var first = node.GetFirstToken(includeZeroWidth: true);
var newFirst = first.WithLeadingTrivia(trivia);
return node.ReplaceToken(first, newFirst);
}
/// <summary>
/// Creates a new node from this node with the leading trivia removed.
/// </summary>
public static TSyntax WithoutLeadingTrivia<TSyntax>(
this TSyntax node
) where TSyntax : SyntaxNode
{
return node.WithLeadingTrivia((IEnumerable<SyntaxTrivia>?)null);
}
/// <summary>
/// Creates a new node from this node with the leading trivia replaced.
/// </summary>
public static TSyntax WithLeadingTrivia<TSyntax>(
this TSyntax node,
params SyntaxTrivia[]? trivia) where TSyntax : SyntaxNode
{
return node.WithLeadingTrivia((IEnumerable<SyntaxTrivia>?)trivia);
}
/// <summary>
/// Creates a new node from this node with the trailing trivia replaced.
/// </summary>
public static TSyntax WithTrailingTrivia<TSyntax>(
this TSyntax node,
SyntaxTriviaList trivia) where TSyntax : SyntaxNode
{
var last = node.GetLastToken(includeZeroWidth: true);
var newLast = last.WithTrailingTrivia(trivia);
return node.ReplaceToken(last, newLast);
}
/// <summary>
/// Creates a new node from this node with the trailing trivia replaced.
/// </summary>
public static TSyntax WithTrailingTrivia<TSyntax>(
this TSyntax node,
IEnumerable<SyntaxTrivia>? trivia) where TSyntax : SyntaxNode
{
var last = node.GetLastToken(includeZeroWidth: true);
var newLast = last.WithTrailingTrivia(trivia);
return node.ReplaceToken(last, newLast);
}
/// <summary>
/// Creates a new node from this node with the trailing trivia removed.
/// </summary>
public static TSyntax WithoutTrailingTrivia<TSyntax>(this TSyntax node) where TSyntax : SyntaxNode
{
return node.WithTrailingTrivia((IEnumerable<SyntaxTrivia>?)null);
}
/// <summary>
/// Creates a new node from this node with the trailing trivia replaced.
/// </summary>
public static TSyntax WithTrailingTrivia<TSyntax>(
this TSyntax node,
params SyntaxTrivia[]? trivia) where TSyntax : SyntaxNode
{
return node.WithTrailingTrivia((IEnumerable<SyntaxTrivia>?)trivia);
}
/// <summary>
/// Attaches the node to a SyntaxTree that the same options as <paramref name="oldTree"/>
/// </summary>
[return: NotNullIfNotNull(nameof(node))]
internal static SyntaxNode? AsRootOfNewTreeWithOptionsFrom(this SyntaxNode? node, SyntaxTree oldTree)
{
return node != null ? oldTree.WithRootAndOptions(node, oldTree.Options).GetRoot() : null;
}
}
}
|