PMD Apex language module providing static code analysis support for Salesforce Apex programming language.
npx @tessl/cli install tessl/maven-net-sourceforge-pmd--pmd-apex@7.13.0PMD Apex provides comprehensive static code analysis capabilities for Salesforce Apex programming language as part of the PMD static code analyzer ecosystem. It integrates with apex-parser and Summit AST libraries to parse Apex source code and generate abstract syntax trees (AST) for rule-based analysis, enabling automated code quality checks, security vulnerability detection, and adherence to coding standards within Apex development workflows.
<dependency><groupId>net.sourceforge.pmd</groupId><artifactId>pmd-apex</artifactId><version>7.13.0</version></dependency>import net.sourceforge.pmd.lang.apex.ApexLanguageModule;
import net.sourceforge.pmd.lang.apex.ast.*;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics;
import net.sourceforge.pmd.lang.apex.multifile.ApexMultifileAnalysis;// Register language module
ApexLanguageModule apexModule = ApexLanguageModule.getInstance();
// Parse Apex code into AST
ApexParser parser = new ApexParser();
ASTApexFile apexFile = parser.parse(parserTask);
// Create custom rule
public class MyApexRule extends AbstractApexRule {
@Override
public Object visit(ASTUserClass node, Object data) {
// Rule logic for class analysis
String className = node.getQualifiedName().getClassName();
return super.visit(node, data);
}
@Override
public Object visit(ASTMethod node, Object data) {
// Rule logic for method analysis
int complexity = MetricsUtil.computeMetric(ApexMetrics.CYCLO, node);
return super.visit(node, data);
}
}
// Multifile analysis
ApexMultifileAnalysis analysis = processor.getMultiFileState();
List<Issue> issues = analysis.getFileIssues("MyClass.cls");PMD Apex is built around several key components:
ApexLanguageModule) for PMD integration and language registrationApexVisitor interface with traversal methods for each AST node typeCore language module registration and configuration for PMD integration. Provides entry points for parser creation, language properties, and violation suppression handling.
public class ApexLanguageModule {
public static ApexLanguageModule getInstance();
public ApexLanguageProcessor createProcessor(LanguagePropertyBundle bundle);
public ApexLanguageProperties newPropertyBundle();
public CpdLexer createCpdLexer(LanguagePropertyBundle bundle);
}
public class ApexLanguageProcessor {
public LanguageVersionHandler services();
public ApexMultifileAnalysis getMultiFileState();
}Complete Abstract Syntax Tree representation for Apex code with 95+ node types covering all language constructs. Includes parser, root nodes, and visitor pattern for tree traversal.
public class ApexParser {
public ASTApexFile parse(ParserTask task);
}
public interface ApexNode<T> {
boolean hasRealLoc();
String getDefiningType();
ASTApexFile getRoot();
}
public interface ApexVisitor<P, R> {
R visit(ASTUserClass node, P data);
R visit(ASTMethod node, P data);
R visit(ASTVariableExpression node, P data);
// 80+ additional visit methods for all AST node types
}Complexity and quality metrics calculation for Apex code analysis. Provides cyclomatic complexity, cognitive complexity, and weighted method count metrics.
public class ApexMetrics {
public static final Metric<ASTMethod, Integer> CYCLO;
public static final Metric<ASTMethod, Integer> COGNITIVE_COMPLEXITY;
public static final Metric<ASTUserClass, Integer> WEIGHED_METHOD_COUNT;
}Cross-file analysis capabilities using ApexLink for analyzing dependencies and relationships across multiple Apex files in a Salesforce project.
public class ApexMultifileAnalysis {
public boolean isFailed();
public List<Issue> getFileIssues(String fileName);
}Base classes and framework for creating custom PMD rules. Includes abstract base rule class with visitor pattern integration and access to AST traversal.
public abstract class AbstractApexRule implements ApexVisitor<Object, Object> {
public void apply(Node target, RuleContext ctx);
// Inherits 80+ visit methods from ApexVisitor
}Lexical analysis for detecting code duplication within Apex codebases. Integrates with PMD's Copy-Paste Detection (CPD) framework.
public class ApexCpdLexer {
public void tokenize(TextDocument textDocument, TokenFactory tokenFactory);
}public interface ApexNode<T> {
boolean hasRealLoc();
String getDefiningType();
ASTApexFile getRoot();
}
public interface ApexVisitor<P, R> {
R visit(ASTApexFile node, P data);
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(ASTMethod node, P data);
R visit(ASTField node, P data);
R visit(ASTProperty node, P data);
R visit(ASTParameter node, P data);
R visit(ASTBlockStatement node, P data);
R visit(ASTIfBlockStatement node, P data);
R visit(ASTWhileLoopStatement node, P data);
R visit(ASTForLoopStatement node, P data);
R visit(ASTVariableExpression node, P data);
R visit(ASTMethodCallExpression node, P data);
R visit(ASTBinaryExpression node, P data);
R visit(ASTAssignmentExpression node, P data);
R visit(ASTSoqlExpression node, P data);
R visit(ASTSoslExpression node, P data);
// 70+ additional visit methods for remaining AST node types
}
public interface ApexQualifiableNode {
ApexQualifiedName getQualifiedName();
}
public interface AccessNode {
// Access modifier related methods
}public enum BinaryOperator {
ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION,
LEFT_SHIFT, RIGHT_SHIFT_SIGNED, RIGHT_SHIFT_UNSIGNED,
BITWISE_AND, BITWISE_OR, BITWISE_XOR, NULL_COALESCING
}
public enum BooleanOperator {
EQUAL, NOT_EQUAL, ALT_NOT_EQUAL, EXACTLY_EQUAL, EXACTLY_NOT_EQUAL,
LESS_THAN, GREATER_THAN, LESS_THAN_OR_EQUAL, GREATER_THAN_OR_EQUAL,
LOGICAL_AND, LOGICAL_OR
}
public enum AssignmentOperator {
EQUALS, ADDITION_EQUALS, SUBTRACTION_EQUALS, MULTIPLICATION_EQUALS,
DIVISION_EQUALS, LEFT_SHIFT_EQUALS, RIGHT_SHIFT_SIGNED_EQUALS,
RIGHT_SHIFT_UNSIGNED_EQUALS, BITWISE_AND_EQUALS, BITWISE_OR_EQUALS,
BITWISE_XOR_EQUALS
}
public enum PrefixOperator {
POSITIVE, NEGATIVE, LOGICAL_NOT, BITWISE_NOT, INCREMENT, DECREMENT
}
public enum PostfixOperator {
INCREMENT, DECREMENT
}
public enum ReferenceType {
LOAD, STORE, METHOD, CLASS, NONE
}
public enum TriggerUsage {
AFTER_DELETE, AFTER_INSERT, AFTER_UNDELETE, AFTER_UPDATE,
BEFORE_DELETE, BEFORE_INSERT, BEFORE_UNDELETE, BEFORE_UPDATE
}public class ApexQualifiedName {
public boolean isClass();
public boolean isOperation();
public String getClassName();
public static ApexQualifiedName ofString(String qualifiedName);
}