You're not blind :slightly_smiling_face: `visit(Ex...
# groovy
p
You're not blind 🙂
visit(Expression)
isn't a traversal hook. It's a default convenience method on
GroovyCodeVisitor
that just does
if (expr != null) expr.visit(this)
. The traversal itself goes through double dispatch: each node calls its specific
visitXxx
method (
visitBinaryExpression
,
visitMethodCallExpression
, ...), and the
CodeVisitorSupport
implementation of each one visits the children. Nothing ever routes back through
visit(Expression)
, so
CodeVisitorSupport
has no single catch-all. To see every expression with one override, use
ClassCodeExpressionTransformer
and override
transform(Expression)
.
super.transform(e)
calls
e.transformExpression(this)
, which sends each child back through
transform
, so you get every expression, nested ones included:
Copy code
def t = new ClassCodeExpressionTransformer() {
    SourceUnit getSourceUnit() { sourceUnit }
    Expression transform(Expression e) {
        // your per-expression logic here
        if (e instanceof ClosureExpression) { e.code.visit(this); return e }  // closures aren't descended into by default
        super.transform(e)
    }
}
classNode.visitContents(t)   // or methodNode.code.visit(t), module.statementBlock.visit(t)
Two caveats: • Closure bodies are skipped unless you handle them yourself, as in the line above (this is documented on the class). • It's a transformer:
transformExpression
builds copies of many node types and writes them back into the tree. So use it for read-only walking only if node identity doesn't matter to you (e.g. you're not keeping references or metadata keyed on the original nodes). Otherwise you're stuck overriding the specific
visitXxx
methods of
CodeVisitorSupport
/
ClassCodeVisitorSupport
, or overriding a few common ones and calling super.