Sawmill

Class CSharpSyntaxNodeExtensions

Extension methods for CSharpSyntaxNodes.

Inheritance
  • Object
  • CSharpSyntaxNodeExtensions
Declaration
public static class CSharpSyntaxNodeExtensions : Object

Methods

ChildrenInContext(CSharpSyntaxNode)

Returns an array containing each immediate child of value paired with a function to replace the child. This is typically useful when you need to replace a node's children one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the child; calling the function with a new child "plugs the hole" in the context.

SelfAndDescendantsInContext<T>(IRewriter<T>, T)DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Declaration
public static ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>[] ChildrenInContext(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to get the contexts for the immediate children

Returns
Type Description

ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>[]

See Also
ChildrenInContext<T>(IRewriter<T>, T)

CountChildren(CSharpSyntaxNode)

Count the immediate children of the value. CountChildren()

Declaration
public static int CountChildren(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value

Returns
Type Description

Int32

value's number of immediate children

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
CountChildren(T) counts the immediate children of the topmost (Add) node.
Assert.Equal(2, rewriter.CountChildren(expr));
See Also
CountChildren(T)

Cursor(CSharpSyntaxNode)

Create a Cursor<T>(IRewriter<T>, T) focused on the root node of value.

Declaration
public static Cursor<CSharpSyntaxNode> Cursor(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The root node on which the newly created Cursor<T>(IRewriter<T>, T) should be focused

Returns
Type Description

Cursor<CSharpSyntaxNode>

A Cursor<T>(IRewriter<T>, T) focused on the root node of value

See Also
Cursor<T>(IRewriter<T>, T)

DescendantAt(CSharpSyntaxNode, IEnumerable<Direction>)

Returns the descendant at a particular location in value

Declaration
public static CSharpSyntaxNode DescendantAt(this CSharpSyntaxNode value, IEnumerable<Direction> path)
Parameters
Type Name Description

CSharpSyntaxNode

value

The rewritable tree type

IEnumerable<Direction>

path

The route to take to find the descendant

Returns
Type Description

CSharpSyntaxNode

The descendant found by following the directions in path

Exceptions
Type Condition

InvalidOperationException

Thrown if path leads off the edge of the tree

See Also
DescendantAt<T>(IRewriter<T>, IEnumerable<Direction>, T)

DescendantsAndSelf(CSharpSyntaxNode)

Yields all of the nodes in the tree represented by value, starting at the bottom.

This is a depth-first post-order traversal.

SelfAndDescendants<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<CSharpSyntaxNode> DescendantsAndSelf(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to traverse

Returns
Type Description

IEnumerable<CSharpSyntaxNode>

An enumerable containing all of the nodes in the tree represented by value, starting at the bottom.

Examples
  Expr expr = new Add(
      new Add(
          new Lit(1),
          new Lit(2)
      ),
      new Lit(3)
  );
  Expr[] expected = new[]
      {
          new Lit(1),
          new Lit(2),
          new Add(new Lit(1), new Lit(2)),
          new Lit(3),
          expr    
      };
  Assert.Equal(expected, rewriter.DescendantsAndSelf(expr));
See Also
DescendantsAndSelf<T>(IRewriter<T>, T)

DescendantsAndSelfInContext(CSharpSyntaxNode)

Yields each node in the tree represented by value paired with a function to replace the node, starting at the bottom. This is typically useful when you need to replace nodes one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the node; calling the function with a new node "plugs the hole" in the context.

This is a depth-first post-order traversal.

DescendantsAndSelf<T>(IRewriter<T>, T)ChildrenInContext<T>(IRewriter<T>, T)SelfAndDescendantsInContext<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>> DescendantsAndSelfInContext(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to get the contexts for the descendants

Returns
Type Description

IEnumerable<ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>>

See Also
DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Fold<T>(CSharpSyntaxNode, SpanFunc<T, CSharpSyntaxNode, T>)

Flattens all the nodes in the tree represented by value into a single result, using an aggregation function to combine each node with the results of folding its children.

Declaration
public static T Fold<T>(this CSharpSyntaxNode value, SpanFunc<T, CSharpSyntaxNode, T> func)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to fold

SpanFunc<T, CSharpSyntaxNode, T>

func

The aggregation function

Returns
Type Description

T

The result of aggregating the tree represented by value.

Type Parameters
Name Description

T

See Also
Fold<T, U>(IRewriter<T>, SpanFunc<U, T, U>, T)
Fold<T, U>(T, SpanFunc<U, T, U>)

GetChildren(CSharpSyntaxNode)

Get the immediate children of the value. GetChildren(Span<T>)

Declaration
public static CSharpSyntaxNode[] GetChildren(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value

Returns
Type Description

CSharpSyntaxNode[]

The immediate children of value

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
GetChildren<T>(IRewriter<T>, T) returns the immediate children of the topmost node.
Expr[] expected = new[]
    {
        new Add(
            new Lit(1),
            new Lit(2)
        ),
        new Lit(3)
    };
Assert.Equal(expected, rewriter.GetChildren(expr));
See Also
GetChildren<T>(IRewriter<T>, T)

GetChildren(CSharpSyntaxNode, Span<CSharpSyntaxNode>)

Copy the immediate children of the value into childrenReceiver. GetChildren(Span<T>)

Declaration
public static void GetChildren(this CSharpSyntaxNode value, Span<CSharpSyntaxNode> childrenReceiver)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value

Span<CSharpSyntaxNode>

childrenReceiver

A Span<T> to copy value's immediate children into. The Span<T>'s Length will be equal to the number returned by CountChildren(T).

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
GetChildren(Span<T>, T) copies the immediate children of the topmost node into the span.
Expr[] expected = new[]
    {
        new Add(
            new Lit(1),
            new Lit(2)
        ),
        new Lit(3)
    };
var array = new Expr[rewriter.CountChildren(expr)];
rewriter.GetChildren(array, expr);
Assert.Equal(expected, array);
See Also
GetChildren(Span<T>, T)

ReplaceDescendantAt<T>(CSharpSyntaxNode, IEnumerable<Direction>, CSharpSyntaxNode)

Replaces the descendant at a particular location in value

Declaration
public static CSharpSyntaxNode ReplaceDescendantAt<T>(this CSharpSyntaxNode value, IEnumerable<Direction> path, CSharpSyntaxNode newDescendant)
Parameters
Type Name Description

CSharpSyntaxNode

value

The rewritable tree type

IEnumerable<Direction>

path

The route to take to find the descendant

CSharpSyntaxNode

newDescendant

The replacement descendant

Returns
Type Description

CSharpSyntaxNode

A copy of value with newDescendant placed at the location indicated by path

Type Parameters
Name Description

T

Exceptions
Type Condition

InvalidOperationException

Thrown if path leads off the edge of the tree

See Also
ReplaceDescendantAt<T>(IRewriter<T>, IEnumerable<Direction>, T, T)

Rewrite(CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>)

Rebuild a tree by applying a transformation function to every node from bottom to top.

Declaration
public static CSharpSyntaxNode Rewrite(this CSharpSyntaxNode value, Func<CSharpSyntaxNode, CSharpSyntaxNode> transformer)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to rewrite

Func<CSharpSyntaxNode, CSharpSyntaxNode>

transformer

The transformation function to apply to every node in the tree

Returns
Type Description

CSharpSyntaxNode

The result of applying transformer to every node in the tree represented by value.

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
Rewrite<T>(IRewriter<T>, Func<T, T>, T) replaces the leaves of the tree with the result of calling transformer,

then replaces their parents with the result of calling transformer, and so on. By the end, Rewrite<T>(IRewriter<T>, Func<T, T>, T) has traversed the whole tree.

Expr expected = transformer(new Add(
    transformer(new Add(
        transformer(new Lit(1)),
        transformer(new Lit(2))
    )),
    transformer(new Lit(3))
));
Assert.Equal(expected, rewriter.Rewrite(transformer, expr));
See Also
Rewrite<T>(IRewriter<T>, Func<T, T>, T)

RewriteChildren(CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>)

Update the immediate children of the value by applying a transformation function to each one.

Declaration
public static CSharpSyntaxNode RewriteChildren(this CSharpSyntaxNode value, Func<CSharpSyntaxNode, CSharpSyntaxNode> transformer)
Parameters
Type Name Description

CSharpSyntaxNode

value

The old value, whose immediate children should be transformed by transformer.

Func<CSharpSyntaxNode, CSharpSyntaxNode>

transformer

A transformation function to apply to each of value's immediate children.

Returns
Type Description

CSharpSyntaxNode

A copy of value with updated children.

See Also
RewriteChildren<T>(IRewriter<T>, Func<T, T>, T)

RewriteDescendantAt<T>(CSharpSyntaxNode, IEnumerable<Direction>, Func<CSharpSyntaxNode, CSharpSyntaxNode>)

Apply a function at a particular location in value

Declaration
public static CSharpSyntaxNode RewriteDescendantAt<T>(this CSharpSyntaxNode value, IEnumerable<Direction> path, Func<CSharpSyntaxNode, CSharpSyntaxNode> transformer)
Parameters
Type Name Description

CSharpSyntaxNode

value

The rewritable tree type

IEnumerable<Direction>

path

The route to take to find the descendant

Func<CSharpSyntaxNode, CSharpSyntaxNode>

transformer

A function to calculate a replacement for the descendant

Returns
Type Description

CSharpSyntaxNode

A copy of value with the result of transformer placed at the location indicated by path

Type Parameters
Name Description

T

Exceptions
Type Condition

InvalidOperationException

Thrown if path leads off the edge of the tree

See Also
RewriteDescendantAt<T>(IRewriter<T>, IEnumerable<Direction>, Func<T, T>, T)

RewriteIter(CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>)

Rebuild a tree by repeatedly applying a transformation function to every node in the tree, until a fixed point is reached. transformer should always eventually return its argument unchanged, or this method will loop. That is, x.RewriteIter(transformer).SelfAndDescendants().All(x => transformer(x) == x).

This is typically useful when you want to put your tree into a normal form by applying a collection of rewrite rules until none of them can fire any more.

Declaration
public static CSharpSyntaxNode RewriteIter(this CSharpSyntaxNode value, Func<CSharpSyntaxNode, CSharpSyntaxNode> transformer)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to rewrite

Func<CSharpSyntaxNode, CSharpSyntaxNode>

transformer

A transformation function to apply to every node in value repeatedly.

Returns
Type Description

CSharpSyntaxNode

The result of applying transformer to every node in the tree represented by value repeatedly until a fixed point is reached.

See Also
RewriteIter<T>(IRewriter<T>, Func<T, T>, T)

SelfAndDescendants(CSharpSyntaxNode)

Yields all of the nodes in the tree represented by value, starting at the top.

This is a depth-first pre-order traversal.

DescendantsAndSelf<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<CSharpSyntaxNode> SelfAndDescendants(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to traverse

Returns
Type Description

IEnumerable<CSharpSyntaxNode>

An enumerable containing all of the nodes in the tree represented by value, starting at the top.

Examples
  Expr expr = new Add(
      new Add(
          new Lit(1),
          new Lit(2)
      ),
      new Lit(3)
  );
  Expr[] expected = new[]
      {
          expr,
          new Add(new Lit(1), new Lit(2)),
          new Lit(1),
          new Lit(2),
          new Lit(3),
      };
  Assert.Equal(expected, rewriter.SelfAndDescendants(expr));
See Also
SelfAndDescendants<T>(IRewriter<T>, T)

SelfAndDescendantsBreadthFirst(CSharpSyntaxNode)

Yields all of the nodes in the tree represented by value in a breadth-first traversal order.

This is a breadth-first pre-order traversal.

Declaration
public static IEnumerable<CSharpSyntaxNode> SelfAndDescendantsBreadthFirst(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to traverse

Returns
Type Description

IEnumerable<CSharpSyntaxNode>

An enumerable containing all of the nodes in the tree represented by value in a breadth-first traversal order.

See Also
SelfAndDescendantsBreadthFirst<T>(IRewriter<T>, T)

SelfAndDescendantsInContext(CSharpSyntaxNode)

Yields each node in the tree represented by value paired with a function to replace the node, starting at the top. This is typically useful when you need to replace nodes one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the node; calling the function with a new node "plugs the hole" in the context.

This is a depth-first pre-order traversal.

SelfAndDescendants<T>(IRewriter<T>, T)ChildrenInContext<T>(IRewriter<T>, T)DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>> SelfAndDescendantsInContext(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to get the contexts for the descendants

Returns
Type Description

IEnumerable<ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>>

See Also
SelfAndDescendantsInContext<T>(IRewriter<T>, T)

SelfAndDescendantsInContextBreadthFirst(CSharpSyntaxNode)

Yields each node in the tree represented by value paired with a function to replace the node, in a breadth-first traversal order. This is typically useful when you need to replace nodes one at a time, such as during mutation testing.

The replacement function can be seen as the "context" of the node; calling the function with a new node "plugs the hole" in the context.

This is a breadth-first pre-order traversal.

SelfAndDescendants<T>(IRewriter<T>, T)ChildrenInContext<T>(IRewriter<T>, T)DescendantsAndSelfInContext<T>(IRewriter<T>, T)

Declaration
public static IEnumerable<ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>> SelfAndDescendantsInContextBreadthFirst(this CSharpSyntaxNode value)
Parameters
Type Name Description

CSharpSyntaxNode

value

The value to get the contexts for the descendants

Returns
Type Description

IEnumerable<ValueTuple<CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode>>>

See Also
SelfAndDescendantsInContextBreadthFirst<T>(IRewriter<T>, T)

SetChildren(CSharpSyntaxNode, ReadOnlySpan<CSharpSyntaxNode>)

Set the immediate children of the value.

Callers should ensure that newChildren contains the same number of children as was returned by GetChildren(Span<T>, T).

SetChildren(ReadOnlySpan<T>)

Declaration
public static CSharpSyntaxNode SetChildren(this CSharpSyntaxNode value, ReadOnlySpan<CSharpSyntaxNode> newChildren)
Parameters
Type Name Description

CSharpSyntaxNode

value

The old value, whose immediate children should be replaced

ReadOnlySpan<CSharpSyntaxNode>

newChildren

The new children

Returns
Type Description

CSharpSyntaxNode

A copy of value with updated children.

Examples

Given a representation of the expression (1+2)+3,

Expr expr = new Add(
    new Add(
        new Lit(1),
        new Lit(2)
    ),
    new Lit(3)
);
SetChildren(ReadOnlySpan<T>, T) replaces the immediate children of the topmost node.
Expr expected = new Add(
    new Lit(4),
    new Lit(5)
);
Assert.Equal(expected, rewriter.SetChildren(Children.Two(new Lit(4), new Lit(5)), expr));
See Also
SetChildren(ReadOnlySpan<T>, T)

ZipFold<U>(CSharpSyntaxNode, CSharpSyntaxNode, Func<CSharpSyntaxNode, CSharpSyntaxNode, IEnumerable<U>, U>)

Flatten all of the nodes in the trees represented by values into a single value at the same time, using an aggregation function to combine nodes with the results of aggregating their children. The trees are iterated in lock-step, much like an n-ary Zip<TFirst,TSecond,TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst,TSecond,TResult>).

When trees are not the same size, the larger ones are truncated both horizontally and vertically. That is, if a pair of nodes have a different number of children, the rightmost children of the larger of the two nodes are discarded.

Declaration
public static U ZipFold<U>(this CSharpSyntaxNode value1, CSharpSyntaxNode value2, Func<CSharpSyntaxNode, CSharpSyntaxNode, IEnumerable<U>, U> func)
Parameters
Type Name Description

CSharpSyntaxNode

value1

CSharpSyntaxNode

value2

Func<CSharpSyntaxNode, CSharpSyntaxNode, IEnumerable<U>, U>

func

The aggregation function

Returns
Type Description

U

The result of aggregating the two trees

Type Parameters
Name Description

U

Examples

Here's an example of using ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[]) to test if two trees are syntactically equal.

static bool Equals(this Expr left, Expr right)
    => left.ZipFold<Expr, bool>(
        right,
        (xs, results) =>
        {
            switch (xs[0])
            {
                case Add a1 when xs[1] is Add a2:
                    return results.All(x => x);
                case Lit l1 when xs[1] is Lit l2:
                    return l1.Value == l2.Value;
                default:
                    return false;
            }
        }
    );
See Also
ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[])

ZipFold<U>(CSharpSyntaxNode[], Func<CSharpSyntaxNode[], IEnumerable<U>, U>)

Flatten all of the nodes in the trees represented by values into a single value at the same time, using an aggregation function to combine nodes with the results of aggregating their children. The trees are iterated in lock-step, much like an n-ary Zip<TFirst,TSecond,TResult>(IEnumerable<TFirst>, IEnumerable<TSecond>, Func<TFirst,TSecond,TResult>).

When trees are not the same size, the larger ones are truncated both horizontally and vertically. That is, if a pair of nodes have a different number of children, the rightmost children of the larger of the two nodes are discarded.

Declaration
public static U ZipFold<U>(this CSharpSyntaxNode[] values, Func<CSharpSyntaxNode[], IEnumerable<U>, U> func)
Parameters
Type Name Description

CSharpSyntaxNode[]

values

The trees to fold

Func<CSharpSyntaxNode[], IEnumerable<U>, U>

func

The aggregation function

Returns
Type Description

U

The result of aggregating the two trees

Type Parameters
Name Description

U

Examples

Here's an example of using ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[]) to test if two trees are syntactically equal.

static bool Equals(this Expr left, Expr right)
    => left.ZipFold<Expr, bool>(
        right,
        (xs, results) =>
        {
            switch (xs[0])
            {
                case Add a1 when xs[1] is Add a2:
                    return results.All(x => x);
                case Lit l1 when xs[1] is Lit l2:
                    return l1.Value == l2.Value;
                default:
                    return false;
            }
        }
    );
See Also
ZipFold<T, U>(IRewriter<T>, Func<T[], IEnumerable<U>, U>, T[])