Java language support module for the PMD static code analyzer with AST processing, symbol resolution, type system, metrics, and 400+ built-in rules
—
The PMD Java module provides comprehensive Abstract Syntax Tree (AST) processing capabilities with 187+ node types covering all Java language constructs. This includes support for modern Java features like records, pattern matching, sealed classes, and preview features through Java 24.
The foundation of AST processing is the JavaNode interface, which all Java AST nodes implement.
/**
* Root interface for all Nodes of the Java AST
*/
public interface JavaNode extends JjtreeNode<JavaNode> {
/**
* Returns the node representing the type declaration this node is found in
* @return The enclosing type declaration or null if not inside a type
*/
ASTTypeDeclaration getEnclosingType();
/**
* Returns the compilation unit this node belongs to
*/
@NonNull ASTCompilationUnit getRoot();
/**
* Returns the symbol table for the program point represented by this node
*/
@NonNull JSymbolTable getSymbolTable();
/**
* Returns the type system with which this node was created
*/
TypeSystem getTypeSystem();
}All concrete AST nodes extend AbstractJavaNode which provides the base implementation.
/**
* Base implementation for all Java AST nodes
*/
public abstract class AbstractJavaNode implements JavaNode {
/**
* Accept method for the visitor pattern
*/
protected abstract <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data);
}The root node of all Java ASTs representing a complete source file.
/**
* The root node of all Java ASTs
*/
public final class ASTCompilationUnit extends AbstractJavaNode implements RootNode {
/**
* Returns the package declaration, if there is one
*/
@Nullable ASTPackageDeclaration getPackageDeclaration();
/**
* Returns the package name of this compilation unit
* @return Package name or empty string if no package declaration
*/
@NonNull String getPackageName();
/**
* Returns the top-level type declarations declared in this compilation unit
*/
NodeStream<ASTTypeDeclaration> getTypeDeclarations();
/**
* Returns the module declaration, if this is a modular compilation unit
*/
@Nullable ASTModuleDeclaration getModuleDeclaration();
/**
* Returns comments associated with this compilation unit
*/
List<JavaComment> getComments();
/**
* Checks if this is a simple compilation unit (Java 22+ preview feature)
*/
boolean isSimpleCompilationUnit();
}/**
* Represents a class declaration
*/
public final class ASTClassDeclaration extends AbstractTypeDeclaration
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
/**
* Returns the simple name of this class
*/
@NonNull String getSimpleName();
/**
* Returns the superclass type, or null if this extends Object implicitly
*/
@Nullable ASTClassType getSuperClassTypeNode();
/**
* Returns the implemented interfaces
*/
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
/**
* Returns the type parameters of this class
*/
@Nullable ASTTypeParameters getTypeParameters();
/**
* Returns the body of this class containing field and method declarations
*/
ASTClassBody getBody();
/**
* Returns the class symbol for symbol resolution
*/
JClassSymbol getSymbol();
/**
* Checks if this is a local class (defined within a method or initializer)
*/
boolean isLocal();
/**
* Checks if this is a nested class (not top-level)
*/
boolean isNested();
}/**
* Represents an interface declaration
*/
public final class ASTInterfaceDeclaration extends AbstractTypeDeclaration
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
/**
* Returns the simple name of this interface
*/
@NonNull String getSimpleName();
/**
* Returns the extended interfaces
*/
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
/**
* Returns the type parameters of this interface
*/
@Nullable ASTTypeParameters getTypeParameters();
/**
* Returns the body of this interface
*/
ASTInterfaceBody getBody();
/**
* Returns the interface symbol
*/
JClassSymbol getSymbol();
}/**
* Represents a record declaration (Java 14+)
*/
public final class ASTRecordDeclaration extends AbstractTypeDeclaration
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
/**
* Returns the simple name of this record
*/
@NonNull String getSimpleName();
/**
* Returns the record components (parameters)
*/
ASTRecordComponentList getComponentList();
/**
* Returns the implemented interfaces
*/
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
/**
* Returns the type parameters of this record
*/
@Nullable ASTTypeParameters getTypeParameters();
/**
* Returns the body of this record
*/
ASTRecordBody getBody();
/**
* Returns the record symbol
*/
JClassSymbol getSymbol();
}/**
* Represents an enum declaration
*/
public final class ASTEnumDeclaration extends AbstractTypeDeclaration
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
/**
* Returns the simple name of this enum
*/
@NonNull String getSimpleName();
/**
* Returns the implemented interfaces
*/
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
/**
* Returns the type parameters (for generic enums - rare)
*/
@Nullable ASTTypeParameters getTypeParameters();
/**
* Returns the body of this enum
*/
ASTEnumBody getBody();
/**
* Returns the enum symbol
*/
JClassSymbol getSymbol();
}/**
* A method invocation expression (qualified and unqualified)
*/
public final class ASTMethodCall extends AbstractInvocationExpr
implements QualifiableExpression {
/**
* Returns the name of the invoked method
*/
@NonNull String getMethodName();
/**
* Returns the argument list of this method call
*/
@NonNull ASTArgumentList getArguments();
/**
* Returns explicit type arguments if present (e.g., obj.<String>method())
*/
@Nullable ASTTypeArguments getExplicitTypeArguments();
/**
* Returns the qualifier expression (left side of the dot)
*/
@Nullable ASTExpression getQualifier();
/**
* Returns the resolved method symbol
*/
JMethodSymbol getMethodType();
/**
* Returns the return type of this method call
*/
JTypeMirror getTypeMirror();
}/**
* A field access expression
*/
public final class ASTFieldAccess extends AbstractJavaExpr
implements QualifiableExpression, AssignmentTarget {
/**
* Returns the name of the accessed field
*/
@NonNull String getName();
/**
* Returns the qualifier expression (object whose field is accessed)
*/
@Nullable ASTExpression getQualifier();
/**
* Returns the resolved field symbol
*/
JFieldSymbol getReferencedSym();
/**
* Returns the type of this field access
*/
JTypeMirror getTypeMirror();
}/**
* A variable access expression (local variables, parameters)
*/
public final class ASTVariableAccess extends AbstractJavaExpr
implements AssignmentTarget {
/**
* Returns the name of the accessed variable
*/
@NonNull String getName();
/**
* Returns the resolved variable symbol
*/
JVariableSymbol getReferencedSym();
/**
* Returns the type of this variable
*/
JTypeMirror getTypeMirror();
}/**
* A lambda expression (Java 8+)
*/
public final class ASTLambdaExpression extends AbstractJavaExpr {
/**
* Returns the parameter list of this lambda
*/
ASTLambdaParameterList getParameters();
/**
* Returns the body of this lambda (expression or block)
*/
JavaNode getBody();
/**
* Checks if the body is a block statement
*/
boolean isBlockBody();
/**
* Checks if the body is an expression
*/
boolean isExpressionBody();
/**
* Returns the functional interface type this lambda implements
*/
JTypeMirror getTypeMirror();
}/**
* Base class for all literal expressions
*/
public abstract class ASTLiteral extends AbstractJavaExpr {
/**
* Returns the constant value represented by this literal
*/
Object getConstValue();
/**
* Returns the type of this literal
*/
JTypeMirror getTypeMirror();
}
/**
* A string literal
*/
public final class ASTStringLiteral extends ASTLiteral {
/**
* Returns the string value (with escape sequences processed)
*/
String getConstValue();
/**
* Checks if this is a text block (Java 15+)
*/
boolean isTextBlock();
}
/**
* A numeric literal (integers, floats, etc.)
*/
public final class ASTNumericLiteral extends ASTLiteral {
/**
* Returns the numeric value as Number
*/
Number getConstValue();
/**
* Returns the base of this numeric literal (2, 8, 10, or 16)
*/
int getBase();
/**
* Checks if this literal has a suffix (L, F, D, etc.)
*/
boolean hasSuffix();
}
/**
* A boolean literal (true/false)
*/
public final class ASTBooleanLiteral extends ASTLiteral {
/**
* Returns the boolean value
*/
boolean isTrue();
}/**
* An if statement
*/
public final class ASTIfStatement extends AbstractJavaStatement {
/**
* Returns the condition expression
*/
ASTExpression getCondition();
/**
* Returns the then-branch statement
*/
ASTStatement getThenBranch();
/**
* Returns the else-branch statement, if present
*/
@Nullable ASTStatement getElseBranch();
/**
* Checks if this if statement has an else clause
*/
boolean hasElse();
}
/**
* A for statement
*/
public final class ASTForStatement extends AbstractJavaStatement {
/**
* Returns the init clause (traditional for loop)
*/
@Nullable ASTForInit getInit();
/**
* Returns the condition expression
*/
@Nullable ASTExpression getCondition();
/**
* Returns the update clause
*/
@Nullable ASTForUpdate getUpdate();
/**
* Returns the loop body
*/
ASTStatement getBody();
}
/**
* An enhanced for statement (for-each, Java 5+)
*/
public final class ASTForeachStatement extends AbstractJavaStatement {
/**
* Returns the loop variable declaration
*/
ASTForeachVariable getVariable();
/**
* Returns the iterable expression
*/
ASTExpression getIterable();
/**
* Returns the loop body
*/
ASTStatement getBody();
}/**
* A switch statement with modern pattern matching support
*/
public final class ASTSwitchStatement extends AbstractJavaStatement {
/**
* Returns the switch expression (what we're switching on)
*/
ASTExpression getTestedExpression();
/**
* Returns all switch branches (cases and default)
*/
NodeStream<ASTSwitchBranch> getBranches();
/**
* Checks if this is a switch expression (returns a value)
*/
boolean isExpressionSwitch();
}
/**
* A switch branch (case or default)
*/
public abstract class ASTSwitchBranch extends AbstractJavaNode {
/**
* Returns the statements in this branch
*/
NodeStream<ASTStatement> getStatements();
/**
* Checks if this branch is a switch arrow branch (->)
*/
boolean isArrowBranch();
}
/**
* A switch labeled rule (case with arrow syntax)
*/
public final class ASTSwitchArrowBranch extends ASTSwitchBranch {
/**
* Returns the case labels for this branch
*/
NodeStream<ASTSwitchLabel> getLabels();
/**
* Returns the right-hand side (expression or statement)
*/
JavaNode getRightHandSide();
}/**
* Base class for all type nodes in the AST
*/
public abstract class ASTType extends AbstractJavaNode implements Iterable<ASTType> {
/**
* Returns the type mirror this AST node represents
*/
JTypeMirror getTypeMirror();
}
/**
* A primitive type (int, boolean, etc.)
*/
public final class ASTPrimitiveType extends ASTType {
/**
* Returns the kind of primitive type
*/
JPrimitiveType.PrimitiveTypeKind getKind();
}
/**
* A class or interface type (possibly generic)
*/
public final class ASTClassType extends ASTType {
/**
* Returns the simple name of this type
*/
@NonNull String getSimpleName();
/**
* Returns the type arguments if this is a parameterized type
*/
@Nullable ASTTypeArguments getTypeArguments();
/**
* Returns the qualifier if this is a qualified type name
*/
@Nullable ASTClassType getQualifier();
/**
* Returns the resolved type symbol
*/
JClassSymbol getReferencedSym();
}
/**
* An array type
*/
public final class ASTArrayType extends ASTType {
/**
* Returns the element type of this array
*/
ASTType getElementType();
/**
* Returns the array dimensions
*/
ASTArrayDimensions getDimensions();
/**
* Returns the number of dimensions
*/
int getArrayDepth();
}/**
* Base visitor implementation for traversing Java ASTs
*/
public abstract class JavaVisitorBase<P, R> implements JavaVisitor<P, R> {
// Visit methods for all AST node types (187+ methods)
// Compilation unit and top-level declarations
public R visit(ASTCompilationUnit node, P data);
public R visit(ASTPackageDeclaration node, P data);
public R visit(ASTImportDeclaration node, P data);
// Type declarations
public R visit(ASTClassDeclaration node, P data);
public R visit(ASTInterfaceDeclaration node, P data);
public R visit(ASTEnumDeclaration node, P data);
public R visit(ASTRecordDeclaration node, P data);
public R visit(ASTAnnotationTypeDeclaration node, P data);
// Method and field declarations
public R visit(ASTMethodDeclaration node, P data);
public R visit(ASTConstructorDeclaration node, P data);
public R visit(ASTFieldDeclaration node, P data);
// Expressions (30+ visit methods)
public R visit(ASTMethodCall node, P data);
public R visit(ASTFieldAccess node, P data);
public R visit(ASTVariableAccess node, P data);
public R visit(ASTLambdaExpression node, P data);
public R visit(ASTMethodReference node, P data);
// Literals
public R visit(ASTStringLiteral node, P data);
public R visit(ASTNumericLiteral node, P data);
public R visit(ASTBooleanLiteral node, P data);
public R visit(ASTNullLiteral node, P data);
// Statements (25+ visit methods)
public R visit(ASTIfStatement node, P data);
public R visit(ASTForStatement node, P data);
public R visit(ASTForeachStatement node, P data);
public R visit(ASTWhileStatement node, P data);
public R visit(ASTSwitchStatement node, P data);
public R visit(ASTTryStatement node, P data);
// Type nodes
public R visit(ASTPrimitiveType node, P data);
public R visit(ASTClassType node, P data);
public R visit(ASTArrayType node, P data);
public R visit(ASTWildcardType node, P data);
// Pattern nodes (Java 14+)
public R visit(ASTTypePattern node, P data);
public R visit(ASTRecordPattern node, P data);
// Default delegation method
protected R visitJavaNode(JavaNode node, P data);
}Usage Examples:
// Example visitor to find all method calls
public class MethodCallVisitor extends JavaVisitorBase<Void, Void> {
private List<String> methodNames = new ArrayList<>();
@Override
public Void visit(ASTMethodCall node, Void data) {
methodNames.add(node.getMethodName());
return super.visit(node, data); // Continue traversing children
}
public List<String> getMethodNames() {
return methodNames;
}
}
// Example visitor to calculate complexity
public class ComplexityVisitor extends JavaVisitorBase<Void, Integer> {
@Override
public Integer visit(ASTIfStatement node, Void data) {
int complexity = 1; // Base complexity for if
if (node.hasElse()) {
complexity += 1; // Additional for else
}
return complexity + super.visit(node, data);
}
@Override
public Integer visit(ASTForStatement node, Void data) {
return 1 + super.visit(node, data); // Add 1 for loop
}
@Override
protected Integer visitJavaNode(JavaNode node, Void data) {
int total = 0;
for (JavaNode child : node.children()) {
Integer childComplexity = child.acceptVisitor(this, data);
if (childComplexity != null) {
total += childComplexity;
}
}
return total;
}
}/**
* Interface for nodes that can have modifiers
*/
public interface ModifierOwner {
/**
* Returns the modifier list
*/
ASTModifierList getModifiers();
/**
* Returns the visibility of this declaration
*/
Visibility getVisibility();
/**
* Returns the effective visibility (considering enclosing scopes)
*/
Visibility getEffectiveVisibility();
/**
* Checks if this declaration has the specified modifiers
*/
boolean hasModifiers(JModifier... modifiers);
/**
* Checks if this declaration has explicit (written) modifiers
*/
boolean hasExplicitModifiers(JModifier... modifiers);
}/**
* Interface for nodes that can be annotated
*/
public interface Annotatable {
/**
* Returns all declared annotations on this element
*/
NodeStream<ASTAnnotation> getDeclaredAnnotations();
/**
* Checks if an annotation is present by binary name
*/
boolean isAnnotationPresent(String binaryName);
/**
* Checks if an annotation is present by class
*/
boolean isAnnotationPresent(Class<? extends java.lang.annotation.Annotation> clazz);
/**
* Returns a specific annotation by binary name
*/
@Nullable ASTAnnotation getAnnotation(String binaryName);
/**
* Returns a specific annotation by class
*/
@Nullable ASTAnnotation getAnnotation(Class<? extends java.lang.annotation.Annotation> clazz);
}Install with Tessl CLI
npx tessl i tessl/maven-net-sourceforge-pmd--pmd-java