Class AstQuery<T extends ASTNode>

java.lang.Object
org.codehaus.groovy.ast.query.AstQuery<T>
Type Parameters:
T - the node type produced by this query

public final class AstQuery<T extends ASTNode> extends Object
A small, read-only, fluent query API over a Groovy AST subtree.

An AstQuery selects descendant nodes of a root, optionally filtered by type and by an arbitrary predicate, and exposes terminal operations that collect or test the matches. It is a declarative alternative to hand-writing a ClassCodeVisitorSupport subclass for the common "find / collect / detect" cases.

 import org.codehaus.groovy.ast.query.AstQuery
 import org.codehaus.groovy.ast.expr.MethodCallExpression
 import org.codehaus.groovy.ast.builder.AstBuilder

 def code = new AstBuilder().buildFromString('foo(); bar()')[0]
 assert AstQuery.from(code).descendants(MethodCallExpression).count() == 2
 

Traversal and pruning

By default the traversal descends through closures but does not descend into nested classes, mirroring ClassCodeVisitorSupport. Use notInto(Class[]) to stop descending at a boundary type (for example ClosureExpression) and into(Class[]) to opt back in past a default boundary. Nested classes are currently the only default boundary, so into(ClassNode.class) is the only case in which into(Class[]) has an effect.

Notes

  • The query is read-only; it never mutates the AST.
  • Matches are produced in document (pre-)order.
  • Instances are immutable and re-runnable: each builder method returns a new query and each terminal performs a fresh traversal, short-circuiting where it can (for example any() and findFirst()).
Since:
6.0.0
  • Method Details

    • from

      public static AstQuery<ASTNode> from(ASTNode root)
      Starts a query rooted at the given node.
      Parameters:
      root - the subtree root to query; must not be null
      Returns:
      a query selecting (by default) all descendants of root
    • descendants

      public AstQuery<ASTNode> descendants()
      Selects all descendant nodes regardless of type.
      Returns:
      a query over every descendant
    • descendants

      public <U extends ASTNode> AstQuery<U> descendants(Class<U> type)
      Selects descendant nodes that are instances of the given type.
      Type Parameters:
      U - the node type
      Parameters:
      type - the node type to match
      Returns:
      a query over descendants of that type
    • descendants

      @SafeVarargs public final AstQuery<ASTNode> descendants(Class<? extends ASTNode>... types)
      Selects descendant nodes that are instances of any of the given types.
      Parameters:
      types - the node types to match (logical OR)
      Returns:
      a query over descendants matching any type
    • andSelf

      public AstQuery<T> andSelf()
      Includes the root node itself as a candidate (it is excluded by default).
      Returns:
      a query that also considers the root
    • where

      public AstQuery<T> where(Predicate<? super T> p)
      Restricts the selection to nodes satisfying the predicate. Multiple where calls are combined with logical AND.
      Parameters:
      p - the predicate (a Groovy Closure coerces to this functional type)
      Returns:
      the refined query
    • where

      public AstQuery<T> where(BiPredicate<? super T,AstContext> p)
      Restricts the selection to nodes satisfying a predicate that also inspects the enclosing AstContext. Combined with logical AND with any other refinements.
      Parameters:
      p - the contextual predicate (a two-argument Groovy Closure coerces to it)
      Returns:
      the refined query
    • notInto

      @SafeVarargs public final AstQuery<T> notInto(Class<? extends ASTNode>... boundary)
      Stops the traversal from descending into the subtrees rooted at nodes of the given types. The boundary nodes themselves are still candidates; only their contents are skipped.
      Parameters:
      boundary - the boundary types (for example ClosureExpression.class)
      Returns:
      the query with the added boundaries
    • into

      @SafeVarargs public final AstQuery<T> into(Class<? extends ASTNode>... types)
      Opts the traversal in to descending past a default boundary. Currently the only default boundary is nested classes, so into(ClassNode.class) makes the traversal recurse into inner classes.
      Parameters:
      types - the boundary types to descend into
      Returns:
      the query with the boundaries opened
    • list

      public List<T> list()
      Collects all matches in document order.
      Returns:
      the matching nodes
    • any

      public boolean any()
      Returns:
      true if at least one node matches; stops at the first match
    • none

      public boolean none()
      Returns:
      true if no node matches; stops at the first match
    • count

      public long count()
      Returns:
      the number of matching nodes
    • findFirst

      public Optional<T> findFirst()
      Returns:
      the first match in document order, if any; stops at the first match
    • first

      public T first()
      Returns:
      the first match in document order, or null; stops at the first match
    • forEach

      public void forEach(Consumer<? super T> action)
      Performs the given action for each match in document order.
      Parameters:
      action - the action
    • forEach

      public void forEach(BiConsumer<? super T,AstContext> action)
      Performs the given action, with enclosing context, for each match in document order.
      Parameters:
      action - the action receiving the node and its AstContext
    • stream

      public Stream<T> stream()
      Returns:
      a sequential Stream of the matches in document order