CtPath (javadoc) defines the path to a CtElement (javadoc) in a model, similarly to XPath for XML. For example, .spoon.test.path.testclasses.Foo.foo#body#statement[index=0] represents the first statement of the body of method foo. A CtPathis based on: names of elements (e.g., foo), and roles of elements with respect to their parent (e.g., body). A role is a relation between two AST nodes. For instance, a “then” branch in an if/then/else is a role (and not a node). All roles can be found in CtRole. In addition, each getter or setter in the metamodel is annotated with its role.

Evaluating AST paths

Paths are used to find code elements, from a given root element.

path = new CtPathStringBuilder().fromString(".spoon.test.path.testclasses.Foo.foo#body#statement[index=0]");
List<CtElement> l = path.evaluateOn(root)

Creating AST paths

From an existing element

Method getPath in CtElement returns a path

CtPath path = anElement.getPath();

From a string

CtPathStringBuilder (javadoc), creates a path object from a string according to the following syntax:

  • .<name> which denotes a child element with name name, e.g., .fr.inria.Spoon (the fully qualified name)
  • #<role> which denotes all children on CtRole role statements, #body#statement[index=2]#else is the else branch of the second statement of a method body
  • name=<somename> - filter which accepts only elements with somename. E.g., #field[name=abc]
  • signature=<somesignature> - filter which accepts only methods and constructors with signature somesignature.
    • Example of method signature: #method[signature=compare(java.lang.String,java.lang.String)]
    • Example of constructor signature: #constructor[signature=(int)]
  • index=<idx> - fitler which accepts only idx-th element of the List. The first element has index 0. The fifth type member in a class #typeMember[index=4]

From the API

The low-level CtPathBuilder (javadoc) defines a fluent API to build your path:

  • name(String, String[]) (javadoc) adds a name matcher to the current path.
  • type(Class, String[]) (javadoc) matches on element of a given type.
  • role(CtPathRole, String[]) (javadoc) matches on elements by their role (where CtPathRole gives all constants supported).
  • wildcard() (javadoc) matches only on elements child of current one.
  • recursiveWildcard() (javadoc) matches on any child and sub-children.

For instance, if we want all elements named by “toto” and with a default value in a project. Use CtPathBuilder like the example below.

CtPath p1 = new CtPathBuilder().recursiveWildcard().name("toto").role(CtPathRole.DEFAULT_VALUE).build();
// equivalent to
CtPath p2 = new CtPathStringBuilder().fromString(".**.toto#default_value").build();

// takes all elements named "toto" in the project. 
new CtPathBuilder().recursiveWildcard().name("toto")

// takes the first element named "toto", a package or a class in the default package, at the root of your project.
new CtPathBuilder().name("toto").recursiveWildcard()