Selectors allow traversing nodes of any syntax tree. Selectors return arrays of nodes.
syntax rule NestedIfs on ApexClass {
when ifStatement x {
var nestedIfs = [x : find descendants having it.type == "ifStatement"]
if (nestedIfs.size > 5) {
capture x // too many ifs
}
}
}
Selectors allow to navigate from an AST to others, such as their ancestors
, descendants
, and siblings
.
// given x, find all its ancestors
[x : find ancestors]
// given x, find all its descendants
[x : find descendants]
// given x, find all its left/right siblings
[x : find left siblings] // only left
[x : find right siblings] // only right
[x : find siblings] // left + right
Selectors allow using any expression as filters (the nth node can be reference using the identifier it
)
// given x, find all its descendants with type expression
[x : find descendants having it.type == "expression"]
// given x, find all its descendants with type expression and 1+ sub-nodes
[x : find descendants having (it.type == "expression" && it.size > 1)]
Selectors can be chained any number of times to allow movement in the syntax tree, using then
between selectors.
// given x, find its subexpressions,
// then move to their left siblings having 2 subnodes
[x : find descendants having (it.type == "expression")
then find left siblings having (it.type == "variableDeclaratorId")]
When chaining selectors it may be helpful to skip
, limit
the elements traversed
// given x, finds all its subexpressions, but skip the first 2
[x : find descendants having type = "expression"
then skip 2]
// given x, finds all its subexpressions, and keep only the first 3
[x : find descendants having type = "expression"
then limit 3]