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 CtPath
is 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()