PMD language module for static analysis of Apache Velocity Template Language (VTL) files
—
Complete Abstract Syntax Tree representation of Velocity templates with 40+ specialized node types for expressions, directives, references, and control structures. The AST framework provides a comprehensive visitor pattern implementation for traversing and analyzing parsed Velocity templates.
Core interface implemented by all Velocity AST nodes, providing visitor pattern support and tree navigation.
/**
* Base interface for all Velocity AST nodes.
* Extends PMD's Node interface with Velocity-specific visitor support.
*/
public interface VmNode extends Node {
/**
* Accept a visitor and invoke the appropriate visit method.
* Central method for visitor pattern implementation.
* @param visitor The visitor to accept
* @param data Context data passed through visitor traversal
* @return Result from visitor method execution
*/
Object jjtAccept(VmParserVisitor visitor, Object data);
/**
* Accept a visitor for all child nodes.
* Convenience method for traversing child nodes.
* @param visitor The visitor to apply to children
* @param data Context data passed through visitor traversal
* @return Result from child visitor executions
* @deprecated This method is not useful, the logic for combining
* children values should be present on the visitor, not the node
*/
@Deprecated
Object childrenAccept(VmParserVisitor visitor, Object data);
/**
* Get a specific child node by index.
* @param index Zero-based index of child node
* @return Child node at specified index
* @throws IndexOutOfBoundsException if index is invalid
*/
VmNode getChild(int index);
/**
* Get the parent node of this node.
* @return Parent node, or null if this is the root node
*/
VmNode getParent();
/**
* Get an iterable over all child nodes.
* @return Iterable for traversing child nodes
*/
Iterable<? extends VmNode> children();
}Abstract base class providing common functionality for all Velocity AST nodes.
/**
* Abstract base implementation for all Velocity AST nodes.
* Provides common functionality including position tracking, token access,
* and tree structure management.
* @deprecated Marked as internal API - use VmNode interface instead
*/
@Deprecated
@InternalApi
public abstract class AbstractVmNode extends AbstractJjtreeNode implements VmNode {
/**
* Called when node is opened during parsing.
* Part of JavaCC tree construction lifecycle.
*/
public void jjtOpen();
/**
* Called when node is closed during parsing.
* Part of JavaCC tree construction lifecycle.
*/
public void jjtClose();
/**
* Get the first token associated with this node.
* @return First token of this node's source text
*/
public Token getFirstToken();
/**
* Get the last token associated with this node.
* @return Last token of this node's source text
*/
public Token getLastToken();
/**
* Get the literal text representation of this node.
* @return String representation of the node's source text
*/
public String literal();
/**
* Get the node type identifier.
* @return Integer constant identifying the node type
*/
public int getType();
/**
* Set additional information for this node.
* @param info Integer value for node-specific metadata
*/
public void setInfo(int info);
/**
* Get additional information for this node.
* @return Integer value containing node-specific metadata
*/
public int getInfo();
/**
* Mark this node as invalid due to parse errors.
*/
public void setInvalid();
/**
* Check if this node is marked as invalid.
* @return true if node has parse errors, false otherwise
*/
public boolean isInvalid();
/**
* Get the line number where this node begins.
* @return Line number (1-based) in source template
*/
public int getLine();
/**
* Get the column number where this node begins.
* @return Column number (1-based) in source template
*/
public int getColumn();
/**
* Get the name of the template containing this node.
* @return Template filename or identifier
*/
public String getTemplateName();
/**
* Dump the AST structure starting from this node.
* @param prefix String prefix for indentation
* @param alreadyDumped Whether parent nodes have been dumped
* @param writer Output writer for dump content
*/
public void dump(String prefix, boolean alreadyDumped, Writer writer);
}Default visitor adapter providing base traversal logic for all AST node types.
/**
* Default implementation of VmParserVisitor that provides base traversal
* logic for all Velocity AST node types. Extend this class to create
* custom visitors that only override specific visit methods.
*/
public class VmParserVisitorAdapter implements VmParserVisitor {
/**
* Default visit method for base VmNode interface.
* @param node The node being visited
* @param data Context data passed through traversal
* @return null by default, subclasses may return meaningful values
*/
public Object visit(VmNode node, Object data);
// Visit methods for all specific node types
public Object visit(ASTprocess node, Object data);
public Object visit(ASTReference node, Object data);
public Object visit(ASTDirective node, Object data);
public Object visit(ASTMethod node, Object data);
public Object visit(ASTIndex node, Object data);
// Mathematical operation nodes
public Object visit(ASTAddNode node, Object data);
public Object visit(ASTSubtractNode node, Object data);
public Object visit(ASTMulNode node, Object data);
public Object visit(ASTDivNode node, Object data);
public Object visit(ASTModNode node, Object data);
public Object visit(ASTMathNode node, Object data);
// Logical operation nodes
public Object visit(ASTOrNode node, Object data);
public Object visit(ASTAndNode node, Object data);
public Object visit(ASTNotNode node, Object data);
// Comparison operation nodes
public Object visit(ASTEQNode node, Object data);
public Object visit(ASTNENode node, Object data);
public Object visit(ASTLTNode node, Object data);
public Object visit(ASTGTNode node, Object data);
public Object visit(ASTLENode node, Object data);
public Object visit(ASTGENode node, Object data);
// Control flow nodes
public Object visit(ASTIfStatement node, Object data);
public Object visit(ASTElseStatement node, Object data);
public Object visit(ASTElseIfStatement node, Object data);
public Object visit(ASTForeachStatement node, Object data);
public Object visit(ASTSetDirective node, Object data);
public Object visit(ASTBlock node, Object data);
// Expression and assignment nodes
public Object visit(ASTExpression node, Object data);
public Object visit(ASTAssignment node, Object data);
// Data structure nodes
public Object visit(ASTMap node, Object data);
public Object visit(ASTObjectArray node, Object data);
public Object visit(ASTIntegerRange node, Object data);
// Content and text nodes
public Object visit(ASTText node, Object data);
public Object visit(ASTTextblock node, Object data);
public Object visit(ASTComment node, Object data);
// Literal value nodes
public Object visit(ASTFloatingPointLiteral node, Object data);
public Object visit(ASTIntegerLiteral node, Object data);
public Object visit(ASTStringLiteral node, Object data);
public Object visit(ASTTrue node, Object data);
public Object visit(ASTFalse node, Object data);
// Identifier and word nodes
public Object visit(ASTIdentifier node, Object data);
public Object visit(ASTWord node, Object data);
// Escape and directive nodes
public Object visit(ASTEscape node, Object data);
public Object visit(ASTEscapedDirective node, Object data);
}Represent Velocity variable references ($variable, $object.property).
/**
* AST node representing Velocity variable references.
* Handles both simple references ($var) and complex references ($obj.prop).
*/
public class ASTReference extends AbstractVmNode {
/**
* Get the root identifier string of the reference.
* For $user.name, returns "user".
* @return Root variable name
*/
public String getRootString();
/**
* Set the literal text representation of this reference.
* @param literal String representation to set
*/
public void setLiteral(String literal);
/**
* Get the literal text representation of this reference.
* @return Complete reference string including $ prefix
*/
public String literal();
}Represent Velocity directives (#if, #foreach, #set, etc.).
/**
* AST node representing Velocity directives.
* Handles all directive types including control flow and utility directives.
*/
public class ASTDirective extends AbstractVmNode {
// Inherits all AbstractVmNode functionality
// Specific directive behavior determined by child nodes and context
}Represent method invocations within Velocity templates.
/**
* AST node representing method calls in Velocity templates.
* Handles both simple method calls and chained method invocations.
*/
public class ASTMethod extends AbstractVmNode {
// Inherits all AbstractVmNode functionality
// Method name and parameters accessible via child nodes
}Specialized nodes for different mathematical operations.
/**
* AST node representing addition operations.
*/
public class ASTAddNode extends AbstractVmNode {
// Inherits position tracking and tree navigation
// Left and right operands accessible via child nodes
}
/**
* AST node representing subtraction operations.
*/
public class ASTSubtractNode extends AbstractVmNode;
/**
* AST node representing multiplication operations.
*/
public class ASTMulNode extends AbstractVmNode;
/**
* AST node representing division operations.
*/
public class ASTDivNode extends AbstractVmNode;
/**
* AST node representing modulo operations.
*/
public class ASTModNode extends AbstractVmNode;
/**
* Base AST node for mathematical operations.
*/
public class ASTMathNode extends AbstractVmNode;Handle Velocity escape sequences and escaped directives.
/**
* AST node representing escape sequences in Velocity templates.
* Handles backslash escaping of special characters.
*/
public class ASTEscape extends AbstractVmNode {
// Inherits all AbstractVmNode functionality
// Escaped character accessible via token information
}Helper methods for common AST node operations.
/**
* Utility class providing helper methods for AST node operations.
* Contains static methods for common node analysis tasks.
*/
public class NodeUtils {
// Static utility methods for node analysis and manipulation
// Implementation details vary based on specific utility needs
}import net.sourceforge.pmd.lang.vm.ast.VmParserVisitorAdapter;
import net.sourceforge.pmd.lang.vm.ast.ASTReference;
import net.sourceforge.pmd.lang.vm.ast.ASTDirective;
public class TemplateAnalyzer extends VmParserVisitorAdapter {
@Override
public Object visit(ASTReference node, Object data) {
String refName = node.getRootString();
System.out.println("Found reference: " + refName +
" at line " + node.getLine());
return super.visit(node, data);
}
@Override
public Object visit(ASTDirective node, Object data) {
System.out.println("Found directive at line " + node.getLine());
// Traverse child nodes to analyze directive structure
return node.childrenAccept(this, data);
}
}import net.sourceforge.pmd.lang.vm.ast.VmNode;
public void analyzeNode(VmNode node) {
// Position information
int line = node.getLine();
int column = node.getColumn();
String template = node.getTemplateName();
// Content information
String literal = node.literal();
Token firstToken = node.getFirstToken();
Token lastToken = node.getLastToken();
// Tree navigation
VmNode parent = node.getParent();
int childCount = node.getNumChildren();
// Child iteration
for (VmNode child : node.children()) {
analyzeNode(child);
}
}import net.sourceforge.pmd.lang.vm.ast.VmParserVisitor;
public class CustomVelocityVisitor implements VmParserVisitor {
@Override
public Object visit(VmNode node, Object data) {
// Default handling for any node type
return node.childrenAccept(this, data);
}
@Override
public Object visit(ASTReference node, Object data) {
// Custom handling for variable references
String refName = node.getRootString();
if (isProblematicReference(refName)) {
reportIssue(node, "Problematic reference: " + refName);
}
return null;
}
// Implement only the visit methods you need
// Unimplemented methods will use default behavior
private boolean isProblematicReference(String refName) {
return refName != null && refName.length() > 50;
}
private void reportIssue(VmNode node, String message) {
System.err.println(message + " at " +
node.getTemplateName() + ":" + node.getLine());
}
}Install with Tessl CLI
npx tessl i tessl/maven-net-sourceforge-pmd--pmd-vm