PMD Apex language module providing static code analysis support for Salesforce Apex programming language.
—
Complete Abstract Syntax Tree representation for Apex code with 95+ node types covering all language constructs from type declarations to expressions and statements. Provides parsing capabilities and visitor pattern for tree traversal and analysis.
Creates AST from Apex source code.
/**
* Parses Apex source code into an Abstract Syntax Tree
* @param task - Parser task containing source code and configuration
* @returns Root ASTApexFile node representing the parsed file
*/
public class ApexParser {
public ASTApexFile parse(ParserTask task);
}Represents the root of an Apex file AST.
/**
* Root node representing an entire Apex file
*/
public class ASTApexFile implements ApexNode<ASTApexFile> {
/** Get the main class, interface, enum, or trigger in this file */
public ASTUserClassOrInterface<?> getMainNode();
/** Get multifile analysis issues for this file */
public List<Issue> getGlobalIssues();
/** Get AST metadata information */
public AstInfo getAstInfo();
}Base interfaces for all AST nodes and visitor pattern.
/**
* Root interface for all Apex AST nodes
* @param <T> The concrete node type
*/
public interface ApexNode<T> {
/** Check if node has real source location */
boolean hasRealLoc();
/** Get the defining type for this node */
String getDefiningType();
/** Get the root ASTApexFile node */
ASTApexFile getRoot();
}
/**
* Visitor pattern interface for traversing Apex AST
* @param <P> Parameter type passed to visit methods
* @param <R> Return type from visit methods
*/
public interface ApexVisitor<P, R> {
// Root node
R visit(ASTApexFile node, P data);
// Type declarations
R visit(ASTUserClass node, P data);
R visit(ASTUserInterface node, P data);
R visit(ASTUserEnum node, P data);
R visit(ASTUserTrigger node, P data);
R visit(ASTAnonymousClass node, P data);
// Members
R visit(ASTMethod node, P data);
R visit(ASTField node, P data);
R visit(ASTProperty node, P data);
R visit(ASTParameter node, P data);
R visit(ASTUserClassMethods node, P data);
R visit(ASTUserExceptionMethods node, P data);
// Statements
R visit(ASTBlockStatement node, P data);
R visit(ASTIfBlockStatement node, P data);
R visit(ASTIfElseBlockStatement node, P data);
R visit(ASTWhileLoopStatement node, P data);
R visit(ASTDoLoopStatement node, P data);
R visit(ASTForLoopStatement node, P data);
R visit(ASTForEachStatement node, P data);
R visit(ASTBreakStatement node, P data);
R visit(ASTContinueStatement node, P data);
R visit(ASTReturnStatement node, P data);
R visit(ASTThrowStatement node, P data);
R visit(ASTTryCatchFinallyBlockStatement node, P data);
R visit(ASTCatchBlockStatement node, P data);
R visit(ASTRunAsBlockStatement node, P data);
R visit(ASTExpressionStatement node, P data);
R visit(ASTStatementExecuted node, P data);
R visit(ASTMultiStatement node, P data);
// Switch statements
R visit(ASTSwitchStatement node, P data);
R visit(ASTElseWhenBlock node, P data);
R visit(ASTTypeWhenBlock node, P data);
R visit(ASTValueWhenBlock node, P data);
R visit(ASTLiteralCase node, P data);
R visit(ASTIdentifierCase node, P data);
// DML statements
R visit(ASTDmlInsertStatement node, P data);
R visit(ASTDmlUpdateStatement node, P data);
R visit(ASTDmlDeleteStatement node, P data);
R visit(ASTDmlUpsertStatement node, P data);
R visit(ASTDmlMergeStatement node, P data);
R visit(ASTDmlUndeleteStatement node, P data);
// Expressions
R visit(ASTExpression node, P data);
R visit(ASTBinaryExpression node, P data);
R visit(ASTBooleanExpression node, P data);
R visit(ASTAssignmentExpression node, P data);
R visit(ASTPrefixExpression node, P data);
R visit(ASTPostfixExpression node, P data);
R visit(ASTTernaryExpression node, P data);
R visit(ASTCastExpression node, P data);
R visit(ASTInstanceOfExpression node, P data);
R visit(ASTNestedExpression node, P data);
// Variable and reference expressions
R visit(ASTVariableExpression node, P data);
R visit(ASTThisVariableExpression node, P data);
R visit(ASTSuperVariableExpression node, P data);
R visit(ASTTriggerVariableExpression node, P data);
R visit(ASTJavaVariableExpression node, P data);
R visit(ASTReferenceExpression node, P data);
R visit(ASTEmptyReferenceExpression node, P data);
R visit(ASTArrayLoadExpression node, P data);
R visit(ASTArrayStoreExpression node, P data);
R visit(ASTNestedStoreExpression node, P data);
R visit(ASTIllegalStoreExpression node, P data);
// Method call expressions
R visit(ASTMethodCallExpression node, P data);
R visit(ASTThisMethodCallExpression node, P data);
R visit(ASTSuperMethodCallExpression node, P data);
R visit(ASTJavaMethodCallExpression node, P data);
// Object creation
R visit(ASTNewObjectExpression node, P data);
R visit(ASTNewListInitExpression node, P data);
R visit(ASTNewListLiteralExpression node, P data);
R visit(ASTNewMapInitExpression node, P data);
R visit(ASTNewMapLiteralExpression node, P data);
R visit(ASTNewSetInitExpression node, P data);
R visit(ASTNewSetLiteralExpression node, P data);
R visit(ASTNewKeyValueObjectExpression node, P data);
// Literals and constants
R visit(ASTLiteralExpression node, P data);
R visit(ASTClassRefExpression node, P data);
R visit(ASTPackageVersionExpression node, P data);
// SOQL/SOSL
R visit(ASTSoqlExpression node, P data);
R visit(ASTSoslExpression node, P data);
R visit(ASTBindExpressions node, P data);
// Variable declarations
R visit(ASTVariableDeclaration node, P data);
R visit(ASTVariableDeclarationStatements node, P data);
R visit(ASTFieldDeclaration node, P data);
R visit(ASTFieldDeclarationStatements node, P data);
// Annotations and modifiers
R visit(ASTAnnotation node, P data);
R visit(ASTAnnotationParameter node, P data);
R visit(ASTModifier node, P data);
R visit(ASTModifierNode node, P data);
R visit(ASTModifierOrAnnotation node, P data);
// Method/constructor components
R visit(ASTMethodBlockStatement node, P data);
R visit(ASTConstructorPreamble node, P data);
R visit(ASTConstructorPreambleStatement node, P data);
// Comments
R visit(ASTFormalComment node, P data);
// Utility nodes
R visit(ASTMapEntryNode node, P data);
R visit(ASTStandardCondition node, P data);
R visit(ASTInvalidDependentCompilation node, P data);
}
/**
* Base implementation of ApexVisitor with default traversal behavior
*/
public abstract class ApexVisitorBase<P, R> implements ApexVisitor<P, R> {
// Default implementations that traverse child nodes
}AST nodes representing class, interface, enum, and trigger declarations.
/**
* Apex class declaration
*/
public class ASTUserClass extends BaseApexClass<ASTUserClass>
implements ApexQualifiableNode, AccessNode {
// Class-specific methods
}
/**
* Interface declaration
*/
public class ASTUserInterface extends BaseApexClass<ASTUserInterface>
implements ApexQualifiableNode, AccessNode {
// Interface-specific methods
}
/**
* Enum declaration
*/
public class ASTUserEnum extends BaseApexClass<ASTUserEnum>
implements ApexQualifiableNode, AccessNode {
// Enum-specific methods
}
/**
* Trigger declaration
*/
public class ASTUserTrigger extends BaseApexClass<ASTUserTrigger>
implements ApexQualifiableNode {
/** Get trigger usage patterns (before/after insert/update/delete/undelete) */
public Set<TriggerUsage> getUsages();
}
/**
* Anonymous class declaration
*/
public class ASTAnonymousClass extends BaseApexClass<ASTAnonymousClass> {
// Anonymous class-specific methods
}AST nodes for class members like methods, fields, and properties.
/**
* Method declaration
*/
public class ASTMethod extends AbstractApexNode<ASTMethod>
implements ApexQualifiableNode, AccessNode {
/** Get method name */
public String getName();
/** Get method parameters */
public List<ASTParameter> getParameters();
/** Check if method is constructor */
public boolean isConstructor();
}
/**
* Field declaration
*/
public class ASTField extends AbstractApexNode<ASTField>
implements ApexQualifiableNode, AccessNode {
/** Get field name */
public String getName();
/** Get field type */
public String getType();
}
/**
* Property declaration
*/
public class ASTProperty extends AbstractApexNode<ASTProperty>
implements ApexQualifiableNode, AccessNode {
/** Get property name */
public String getName();
/** Check if property has getter */
public boolean hasGetter();
/** Check if property has setter */
public boolean hasSetter();
}
/**
* Method parameter
*/
public class ASTParameter extends AbstractApexNode<ASTParameter> {
/** Get parameter name */
public String getName();
/** Get parameter type */
public String getType();
}AST nodes for various types of expressions.
/**
* Binary operation expression (arithmetic, comparison, logical)
*/
public class ASTBinaryExpression extends AbstractApexNode<ASTBinaryExpression> {
/** Get the binary operator */
public BinaryOperator getOperator();
/** Get left operand */
public ASTExpression getLeftOperand();
/** Get right operand */
public ASTExpression getRightOperand();
}
/**
* Boolean operation expression (comparison, logical)
*/
public class ASTBooleanExpression extends AbstractApexNode<ASTBooleanExpression> {
/** Get the boolean operator */
public BooleanOperator getOperator();
/** Get left operand */
public ASTExpression getLeftOperand();
/** Get right operand */
public ASTExpression getRightOperand();
}
/**
* Assignment expression
*/
public class ASTAssignmentExpression extends AbstractApexNode<ASTAssignmentExpression> {
/** Get the assignment operator */
public AssignmentOperator getOperator();
/** Get left side (target) of assignment */
public ASTExpression getLeftOperand();
/** Get right side (value) of assignment */
public ASTExpression getRightOperand();
}
/**
* Method call expression
*/
public class ASTMethodCallExpression extends AbstractApexNode<ASTMethodCallExpression> {
/** Get method name */
public String getMethodName();
/** Get method arguments */
public List<ASTExpression> getArguments();
/** Get target object (null for static calls) */
public ASTExpression getTarget();
}
/**
* Variable reference expression
*/
public class ASTVariableExpression extends AbstractApexNode<ASTVariableExpression> {
/** Get variable name */
public String getVariableName();
}
/**
* SOQL query expression
*/
public class ASTSoqlExpression extends AbstractApexNode<ASTSoqlExpression> {
/** Get SOQL query string */
public String getQuery();
/** Get bind expressions in the query */
public List<ASTBindExpressions> getBindExpressions();
}
/**
* SOSL search expression
*/
public class ASTSoslExpression extends AbstractApexNode<ASTSoslExpression> {
/** Get SOSL search string */
public String getSearch();
/** Get bind expressions in the search */
public List<ASTBindExpressions> getBindExpressions();
}/**
* Interface for nodes that can have qualified names
*/
public interface ApexQualifiableNode {
/** Get qualified name for this node */
ApexQualifiedName getQualifiedName();
}
/**
* Interface for nodes with access modifiers
*/
public interface AccessNode {
// Access modifier related methods
}
/**
* Represents qualified names for classes and methods
*/
public class ApexQualifiedName {
/** Check if this represents a class */
public boolean isClass();
/** Check if this represents an operation/method */
public boolean isOperation();
/** Get the class portion of the qualified name */
public String getClassName();
/** Create qualified name from string representation */
public static ApexQualifiedName ofString(String qualifiedName);
}
/**
* Comment container interface
*/
public interface ASTCommentContainer {
// Comment-related methods
}
/**
* Utility for building comments
*/
public class ApexCommentBuilder {
// Comment building utilities
}Usage Examples:
// Parse Apex code
ApexParser parser = new ApexParser();
ASTApexFile apexFile = parser.parse(parserTask);
// Get main type declaration
ApexNode<?> mainNode = apexFile.getMainNode();
if (mainNode instanceof ASTUserClass) {
ASTUserClass classNode = (ASTUserClass) mainNode;
ApexQualifiedName qname = classNode.getQualifiedName();
System.out.println("Class: " + qname.getClassName());
}
// Custom visitor for analysis
public class ComplexityVisitor extends ApexVisitorBase<Object, Object> {
private int methodCount = 0;
@Override
public Object visit(ASTMethod node, Object data) {
methodCount++;
String methodName = node.getName();
System.out.println("Found method: " + methodName);
return super.visit(node, data);
}
@Override
public Object visit(ASTBinaryExpression node, Object data) {
BinaryOperator op = node.getOperator();
System.out.println("Binary operation: " + op);
return super.visit(node, data);
}
}
// Use visitor
ComplexityVisitor visitor = new ComplexityVisitor();
apexFile.jjtAccept(visitor, null);
// Navigate AST manually
if (apexFile.getMainNode() instanceof ASTUserClass) {
ASTUserClass classNode = (ASTUserClass) apexFile.getMainNode();
// Find all methods in the class
List<ASTMethod> methods = classNode.findDescendantsOfType(ASTMethod.class);
for (ASTMethod method : methods) {
System.out.println("Method: " + method.getName());
// Analyze method parameters
for (ASTParameter param : method.getParameters()) {
System.out.println(" Parameter: " + param.getName() + " : " + param.getType());
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-net-sourceforge-pmd--pmd-apex