PMD Source Code Reading (3) — Rule Checking
PMD uses built-in coding rules to perform static checks on the code. It obtains the abstract syntax tree (AST) of the code through JavaCC and JJTree, and then checks the nodes of the syntax tree.
Note: The PMD version studied in this article is 5.5.2, and the tool used to automatically generate class diagrams from code is the Eclipse plugin AmaterasUML.
1. Program Entry
We chose to start execution from the command line, with the program entry being the main method of the net.sourceforge.pmd.PMD class in the pmd-core subproject. After a series of jumps, we arrived at the processSource method of SourceCodeProcessor. The parse method treats a code file as a node and then uses the apply method of RuleSets to check that node.
// processSource method of SourceCodeProcessor (removing some unrelated code)
private void processSource(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) {
LanguageVersion languageVersion = ctx.getLanguageVersion();
Parser parser = PMD.parserFor(languageVersion, configuration);
Node rootNode = parse(ctx, sourceCode, parser);
Language language = languageVersion.getLanguage();
List<Node> acus = Collections.singletonList(rootNode);
ruleSets.apply(acus, ctx, language);
}
// processSource method of SourceCodeProcessor (removing some unrelated code)
private void processSource(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) {
LanguageVersion languageVersion = ctx.getLanguageVersion();
Parser parser = PMD.parserFor(languageVersion, configuration);
Node rootNode = parse(ctx, sourceCode, parser);
Language language = languageVersion.getLanguage();
List<Node> acus = Collections.singletonList(rootNode);
ruleSets.apply(acus, ctx, language);
}
The apply method of RuleSets will call the apply method of each RuleSet within RuleSets, and the apply method of RuleSet will call the apply method of each Rule within the RuleSet. The apply method of Rule is as follows:
void apply(List<? extends Node> nodes, RuleContext ctx);
void apply(List<? extends Node> nodes, RuleContext ctx);
2. Rule Checking
2.1 Abstract Syntax Tree
The abstract syntax tree is a tree representation of the abstract syntax structure of source code. PMD uses JavaCC and JJTree to generate node representations for each Java language element. The generated code is in the net.sourceforge.pmd.lang.java.ast package.
The inheritance diagram of syntax tree nodes is as follows:
The code generated by JavaCC and JJTree can generate a corresponding tree structure for a piece of Java code. We can run the designer.bat provided by PMD, which allows us to visually see the tree structure of the code.
2.2 Visitor Pattern
The results of JavaCC and JJTree also include a Visitor for accessing the syntax tree structure. Through the visitor pattern, we can process the nodes we need while traversing the syntax tree.
public interface JavaParserVisitor
{
public Object visit(ASTCompilationUnit node, Object data);
public Object visit(ASTPackageDeclaration node, Object data);
public Object visit(ASTImportDeclaration node, Object data);
public Object visit(ASTTypeDeclaration node, Object data);
public Object visit(ASTClassOrInterfaceDeclaration node, Object data);
public Object visit(ASTExtendsList node, Object data);
public Object visit(ASTImplementsList node, Object data);
public Object visit(ASTEnumDeclaration node, Object data);
public Object visit(ASTEnumBody node, Object data);
public Object visit(ASTEnumConstant node, Object data);
public Object visit(ASTTypeParameters node, Object data);
public Object visit(ASTTypeParameter node, Object data);
public Object visit(ASTTypeBound node, Object data);
public Object visit(ASTClassOrInterfaceBody node, Object data);
public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data);
public Object visit(ASTFieldDeclaration node, Object data);
public Object visit(ASTVariableDeclarator node, Object data);
// omitted below
}
public interface JavaParserVisitor
{
public Object visit(ASTCompilationUnit node, Object data);
public Object visit(ASTPackageDeclaration node, Object data);
public Object visit(ASTImportDeclaration node, Object data);
public Object visit(ASTTypeDeclaration node, Object data);
public Object visit(ASTClassOrInterfaceDeclaration node, Object data);
public Object visit(ASTExtendsList node, Object data);
public Object visit(ASTImplementsList node, Object data);
public Object visit(ASTEnumDeclaration node, Object data);
public Object visit(ASTEnumBody node, Object data);
public Object visit(ASTEnumConstant node, Object data);
public Object visit(ASTTypeParameters node, Object data);
public Object visit(ASTTypeParameter node, Object data);
public Object visit(ASTTypeBound node, Object data);
public Object visit(ASTClassOrInterfaceBody node, Object data);
public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data);
public Object visit(ASTFieldDeclaration node, Object data);
public Object visit(ASTVariableDeclarator node, Object data);
// omitted below
}
2.3 Rules and Rule Sets
PMD defines a large number of rules, and the inheritance diagram is as follows:
The applyRule method of AbstractJavaRule:
public void apply(List<? extends Node> nodes, RuleContext ctx) {
visitAll(nodes, ctx);
}
public void apply(List<? extends Node> nodes, RuleContext ctx) {
visitAll(nodes, ctx);
}
AbstractJavaRule implements the JavaParserVisitor interface, so each rule in PMD is a Visitor. These Visitors access the syntax elements of interest by overriding various visit methods and perform checks on them.
Taking AvoidDollarSignsRule as an example:
public class AvoidDollarSignsRule extends AbstractJavaRule {
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.getImage().indexOf('
A rule set, as the name suggests, is a collection of rules, stored in XML format, which contains rules belonging to the same category. These XML files are placed in the resource directory.
Taking basic.xml as an example, the file content is as follows:
3. Output Results
Similar to CPD, PMD also defines multiple Renderers to output in different formats, which will not be detailed here.
) != -1) {
addViolation(data, node);
return data;
}
return super.visit(node, data);
}
public Object visit(ASTVariableDeclaratorId node, Object data) {
if (node.getImage().indexOf('
A rule set, as the name suggests, is a collection of rules, stored in XML format, which contains rules belonging to the same category. These XML files are placed in the resource directory.
Taking basic.xml as an example, the file content is as follows:
3. Output Results
Similar to CPD, PMD also defines multiple Renderers to output in different formats, which will not be detailed here.
) != -1) {
addViolation(data, node);
return data;
}
return super.visit(node, data);
}
public Object visit(ASTMethodDeclarator node, Object data) {
if (node.getImage().indexOf('
A rule set, as the name suggests, is a collection of rules, stored in XML format, which contains rules belonging to the same category. These XML files are placed in the resource directory.
Taking basic.xml as an example, the file content is as follows:
3. Output Results
Similar to CPD, PMD also defines multiple Renderers to output in different formats, which will not be detailed here.
) != -1) {
addViolation(data, node);
return data;
}
return super.visit(node, data);
}
}
public class AvoidDollarSignsRule extends AbstractJavaRule {
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (node.getImage().indexOf('
A rule set, as the name suggests, is a collection of rules, stored in XML format, which contains rules belonging to the same category. These XML files are placed in the resource directory.
Taking basic.xml as an example, the file content is as follows:
3. Output Results
Similar to CPD, PMD also defines multiple Renderers to output in different formats, which will not be detailed here.
) != -1) {
addViolation(data, node);
return data;
}
return super.visit(node, data);
}
public Object visit(ASTVariableDeclaratorId node, Object data) {
if (node.getImage().indexOf('
A rule set, as the name suggests, is a collection of rules, stored in XML format, which contains rules belonging to the same category. These XML files are placed in the resource directory.
Taking basic.xml as an example, the file content is as follows:
3. Output Results
Similar to CPD, PMD also defines multiple Renderers to output in different formats, which will not be detailed here.
) != -1) {
addViolation(data, node);
return data;
}
return super.visit(node, data);
}
public Object visit(ASTMethodDeclarator node, Object data) {
if (node.getImage().indexOf('
A rule set, as the name suggests, is a collection of rules, stored in XML format, which contains rules belonging to the same category. These XML files are placed in the resource directory.
Taking basic.xml as an example, the file content is as follows:
3. Output Results
Similar to CPD, PMD also defines multiple Renderers to output in different formats, which will not be detailed here.
) != -1) {
addViolation(data, node);
return data;
}
return super.visit(node, data);
}
}
A rule set, as the name suggests, is a collection of rules, stored in XML format, which contains rules belonging to the same category. These XML files are placed in the resource directory.
Taking basic.xml as an example, the file content is as follows:
3. Output Results
Similar to CPD, PMD also defines multiple Renderers to output in different formats, which will not be detailed here.
Comments
No comments yet. Be the first to comment!