FluentASTVisitor.java
/*******************************************************************************
* Copyright (c) 2026 Carsten Hammer.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Carsten Hammer
*******************************************************************************/
package org.sandbox.ast.api.jdt;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.SimpleName;
import org.sandbox.ast.api.expr.MethodInvocationExpr;
import org.sandbox.ast.api.expr.SimpleNameExpr;
/**
* An ASTVisitor that pre-converts JDT nodes to fluent API wrappers.
*
* <p>Subclasses override the {@code visitXxx(FluentType, JDTType)} methods instead of
* the raw {@code visit(JDTType)} methods. The raw JDT node is still available for
* position checks, parent navigation, and rewriting.</p>
*
* <h2>Usage:</h2>
* <pre>
* FluentASTVisitor visitor = new FluentASTVisitor() {
* {@literal @}Override
* protected boolean visitMethodInvocation(MethodInvocationExpr expr, MethodInvocation node) {
* // No need to call JDTConverter.convert() - expr is already converted
* if (expr.isMethodCall("add", 1)) {
* // Use fluent API
* }
* return true;
* }
* };
* astNode.accept(visitor);
* </pre>
*
* <h2>Design:</h2>
* <ul>
* <li>Only node types with existing {@link JDTConverter} conversions are wrapped</li>
* <li>The {@code visit()} methods are {@code final} to force use of fluent overrides</li>
* <li>Other {@code visit()} methods (FieldAccess, CastExpression, etc.) remain overridable</li>
* <li>Raw JDT nodes remain accessible for AST rewriting and parent traversal</li>
* </ul>
*/
public class FluentASTVisitor extends ASTVisitor {
/**
* Creates a new FluentASTVisitor.
*/
public FluentASTVisitor() {
super();
}
/**
* Creates a new FluentASTVisitor with doc tag visiting control.
*
* @param visitDocTags whether to visit Javadoc tags
*/
public FluentASTVisitor(boolean visitDocTags) {
super(visitDocTags);
}
/**
* Pre-converts the MethodInvocation to a fluent wrapper and delegates to
* {@link #visitMethodInvocation(MethodInvocationExpr, MethodInvocation)}.
*
* <p>This method is {@code final}. Subclasses must override
* {@link #visitMethodInvocation(MethodInvocationExpr, MethodInvocation)} instead.</p>
*/
@Override
public final boolean visit(MethodInvocation node) {
return visitMethodInvocation(JDTConverter.convert(node), node);
}
/**
* Pre-converts the SimpleName to a fluent wrapper and delegates to
* {@link #visitSimpleName(SimpleNameExpr, SimpleName)}.
*
* <p>This method is {@code final}. Subclasses must override
* {@link #visitSimpleName(SimpleNameExpr, SimpleName)} instead.</p>
*/
@Override
public final boolean visit(SimpleName node) {
return visitSimpleName(JDTConverter.convert(node), node);
}
/**
* Called when visiting a MethodInvocation. Override this instead of {@code visit(MethodInvocation)}.
*
* @param expr the pre-converted fluent wrapper
* @param node the raw JDT node (for position checks, parent navigation, rewriting)
* @return {@code true} to visit children, {@code false} to skip
*/
protected boolean visitMethodInvocation(MethodInvocationExpr expr, MethodInvocation node) {
return true;
}
/**
* Called when visiting a SimpleName. Override this instead of {@code visit(SimpleName)}.
*
* @param expr the pre-converted fluent wrapper
* @param node the raw JDT node (for position checks, parent navigation, rewriting)
* @return {@code true} to visit children, {@code false} to skip
*/
protected boolean visitSimpleName(SimpleNameExpr expr, SimpleName node) {
return true;
}
}