--------------------------------------------------------------------------------
Last Published: 2012-01-31 | SourceForge > PMD SourceForge.net Project Page | Hosted by SourceForge
--------------------------------------------------------------------------------
Overview
Download PMD 5.0 Alpha
What's new in PMD 5.0 Alpha
PMD in the news
PMD-related products and books
Best practices
Future directions
Similar projects
Credits
License
What does 'PMD' mean?
Usage
Installation
Command line usage
Ant task usage
Maven plugin usage
Mvn plugin usage
IDE plugin usage
Suppressing warnings
Finding duplicated code
JSP support
Customizing PMD
Compiling PMD
How to write a rule
Writing XPath rules
How to make a rule set
How it works
Rule guidelines
PMD developers information
For example
Run PMD on a Sourceforge project
Rule Sets
jsp
Basic JSF
Basic JSP
xsl
XPath in XSL
java
Design
Coupling
Jakarta Commons Logging
Basic
Strict Exceptions
Security Code Guidelines
Android
Java Logging
Controversial
Comments
Type Resolution
Empty Code
String and StringBuffer
Code Size
Braces
Unused Code
Unnecessary
J2EE
JavaBeans
Migration
Import Statements
JUnit
Naming
Finalizer
Optimization
Clone Implementation
ecmascript
Basic Ecmascript
Unnecessary
Braces
xml
Basic XML
Project Documentation
Project Information
Project Reports
How to write a PMD rule
Writing PMD rules is cool because you don't have to wait for us to get around to implementing feature requests.
Get a development environment set up first
Here's some initial information on compiling PMD
Java or XPath?
There are two way to write rules:
•Write a rule using Java
•Write an XPath expression
We'll cover the Java way first and the XPath way second. Most of this documentation is applicable to both methods, too, so read on.
Figure out what you want to look for
Lets's figure out what problem we want to spot. We can use "While loops must use braces" as an example. In the source code below, it's easy to get lost visually - it's kind of hard to tell what the curly braces belong to.
class Example {
void bar() {
while (baz)
buz.doSomething();
}
}So we know what an example in source code looks like, which is half the battle.
Write a test-data example and look at the AST
PMD doesn't use the source code directly; it uses a JavaCC generated parser to parse the source code and produce an AST (Abstract Syntax Tree). The AST for the code above looks like this:
CompilationUnit
TypeDeclaration
ClassDeclaration:(package private)
UnmodifiedClassDeclaration(Example)
ClassBody
ClassBodyDeclaration
MethodDeclaration:(package private)
ResultType
MethodDeclarator(bar)
FormalParameters
Block
BlockStatement
Statement
WhileStatement
Expression
PrimaryExpression
PrimaryPrefix
Name:baz
Statement
StatementExpression:null
PrimaryExpression
PrimaryPrefix
Name:buz.doSomething
PrimarySuffix
ArgumentsYou can generate this yourself by:
•Run the batch file bin/designer.bat
•Paste the code into the left text area and click the "Go" button
•Note that there's another panel and a textfield to test out XPath expressions; more on that later.
•Here's a screenshot:
So you can see in the example above that the AST for a WhileStatement looks kind of like this (excluding that expression gibberish for clarity):
WhileStatement
Expression
Statement
StatementExpression
If you were to add curly braces around the call to buz.doSomething()and click "Go" again, you'd see that the AST would change a bit. It'd look like this:
WhileStatement
Expression
Statement
Block
BlockStatement
Statement
StatementExpression
Ah ha! We see that the curly braces add a couple more AST nodes - a Block and a BlockStatement. So all we have to do is write a rule to detect a WhileStatement that has a Statement that's not followed by a Block, and we've got a rule violation.
By the way, all this structural information - i.e., the fact that a Statement may be followed a Block - is concisely defined in the EBNF grammar. So, for example, the Statement definition looks like this:
void Statement() :
{}
{
LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement()
| LOOKAHEAD(2) LabeledStatement()
| Block()
| EmptyStatement()
| StatementExpression() ";"
| SwitchStatement()
| IfStatement()
| WhileStatement()
| DoStatement()
| ForStatement()
| BreakStatement()
| ContinueStatement()
| ReturnStatement()
| ThrowStatement()
| SynchronizedStatement()
| TryStatement()
}
showing that a Statement may be followed by all sorts of stuff.
Write a rule class
Create a new Java class that extends net.sourceforge.pmd.AbstractRule:
import net.sourceforge.pmd.*;
public class WhileLoopsMustUseBracesRule extends AbstractRule {
}
That was easy. PMD works by creating the AST and then traverses it recursively so a rule can get a callback for any type it's interested in. So let's make sure our rule gets called whenever the AST traversal finds a WhileStatement:
import net.sourceforge.pmd.*;
import net.sourceforge.pmd.ast.*;
public class WhileLoopsMustUseBracesRule extends AbstractRule {
public Object visit(ASTWhileStatement node, Object data) {
System.out.println("hello world");
return data;
}
}
We stuck a println() in there for now so we can see when our rule gets hit.
Put the WhileLoopsMustUseBracesRule rule in a ruleset file
Now our rule is written - at least, the shell of it is - and now we need to tell PMD about it. We need to add it to a ruleset XML file. Look at rulesets/basic.xml; it's got lots of rule definitions in it. Copy and paste one of these rules into a new ruleset - call it mycustomrules.xml or something. Then fill in the elements and attributes:
•name - WhileLoopsMustUseBracesRule
•message - Use braces for while loops
•class - Wherever you put the rule. Note this doesn't have to be in net.sourceforge.pmd; it can be in com.yourcompany.util.pmd or whereever you want
•description - Use braces for while loops
•example - A little code snippet in CDATA tags that shows a rule violation
The whole ruleset file should look something like this:
<?xml version="1.0"?>
<ruleset name="My custom rules"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
<rule name="WhileLoopsMustUseBracesRule"
message="Avoid using 'while' statements without curly braces"
class="WhileLoopsMustUseBracesRule">
<description>
Avoid using 'while' statements without using curly braces
</description>
<priority>3</priority>
<example>
<![CDATA[
public void doSomething() {
while (true)
x++;
}
]]>
</example>
</rule>
</ruleset>
Run PMD using your new ruleset
OK, let's run the new rule so we can see something work. Like this:
pmd.bat c:\path\to\my\src xml c:\path\to\mycustomrules.xml
This time your "hello world" will show up right after the AST gets printed out. If it doesn't, post a message to the forum so we can improve this document :-)
Write code to add rule violations where appropriate
Now that we've identified our problem, recognized the AST pattern that illustrates the problem, written a new rule, and plugged it into a ruleset, we need to actually make our rule find the problem, create a RuleViolation, and put it in the Report, which is attached to the RuleContext. Like this:
public class WhileLoopsMustUseBracesRule extends AbstractRule {
public Object visit(ASTWhileStatement node, Object data) {
SimpleNode firstStmt = (SimpleNode)node.jjtGetChild(1);
if (!hasBlockAsFirstChild(firstStmt)) {
addViolation(data, node);
}
return super.visit(node,data);
}
private boolean hasBlockAsFirstChild(SimpleNode node) {
return (node.jjtGetNumChildren() != 0 && (node.jjtGetChild(0) instanceof ASTBlock));
}
}
TODO - if you don't understand the code for the rule, post a message to the forum so we can improve this document :-)
Writing a rule as an XPath expression
Daniel Sheppard integrated an XPath engine into PMD, so now you can write rules as XPath expressions. For example, the XPath expression for our WhileLoopsMustUseBracesRule looks like this:
//WhileStatement[not(Statement/Block)]
Concise, eh? Here's an article with a lot more detail.
Note that for XPath rules you'll need to set the class attribute in the rule definition to net.sourceforge.pmd.lang.rule.XPathRule. Like this:
<rule name="EmptyCatchBlock"
message="Avoid empty catch blocks"
class="net.sourceforge.pmd.lang.rule.XPathRule">
<description>
etc., etc.
Note that access modifiers are held as attributes, so, for example,
//FieldDeclaration[@Private='true']finds all private fields. You can see the code that determines all the attributes here
Thanks to Miguel Griffa for writing a longer XPath tutorial.
I want to implement a rule that analyse more than the class !
An obvious limitation of the previous mechanism is the "class-centric" focus of the rule. How can you implement a rule that checks stuff accross the all source code ? Let's take a dummy example. Let's say you want to implement a rule that count how many Expression Node you have in your source code (told you, it was a dummy example
![](/images/smiles/icon_smile.gif)
).
You realize quite simply. You just have to add static field to the RulesContext, as an attribute, and uses Rule.start() and Rule.end() hook to initialized and finalize your rule's implementation :
package net.sourceforge.pmd.rules;
import java.util.concurrent.atomic.AtomicLong;
import net.sourceforge.pmd.AbstractJavaRule;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.ast.ASTExpression;
public class CountRule extends AbstractJavaRule {
private static final String COUNT = "count";
@Override
public void start(RuleContext ctx) {
ctx.setAttribute(COUNT, new AtomicLong());
super.start(ctx);
}
@Override
public Object visit(ASTExpression node, Object data) {
// How many Expression nodes are there in all files parsed! I must know!
RuleContext ctx = (RuleContext)data;
AtomicLong total = (AtomicLong)ctx.getAttribute(COUNT);
total.incrementAndGet();
return super.visit(node, data);
}
@Override
public void end(RuleContext ctx) {
AtomicLong total = (AtomicLong)ctx.getAttribute(COUNT);
addViolation(ctx, null, new Object[] { total });
ctx.removeAttribute(COUNT);
super.start(ctx);
}
}
As you can see in this example, the method start will be call the first time the rule is going to be used, so you can initialize properly your rule here. Once the rule will have finished to parses the source code, the method end() will be invoke you can assert there if, or not, your rule has been violated.
Note that the example log a violation without a proper classname. This is not really a good idea. Indeed, a lot of aggregating tools that PMD (Such as XRadar, or Sonar) probably uses this kind of meta data on their aggregation processes. So, when implements such a rule, always try to find a way to add classname to the violation report.
I need somekind of Type Resolution for my rule !
1.Inside an XPath query PMD XPath syntax includes now a new function called typeof which determines if a node (ClassOrInterfaceType only right now) is of the provided type. it also scans the type's hierarchy, so if you extend a class it will also find this out.
Here a an example of use, inside an XPath Query:
//ClassOrInterfaceDeclaration[
//ClassOrInterfaceType[typeof(@Image, 'junit.framework.TestCase','TestCase')]
]
This query will match on such source code:
import junit.framework.TestCase;
public class Foo extends TestCase { }
Bundle it up
To use your rules as part of a nightly build or whatever, it's helpful to bundle up both the rule and the ruleset.xml file in a jar file. Then you can put that jar file on the CLASSPATH of your build. Setting up a script or an Ant task to do this can save you some tedious typing.
Repeat as necessary
I've found that my rules usually don't work the first time, and so I have to go back and tweak them a couple times. That's OK, if we were perfect programmers PMD would be useless anyhow :-).
As an acceptance test of sorts, I usually run a rule on the JDK 1.4 source code and make sure that a random sampling of the problems found are in fact legitimate rule violations. This also ensures that the rule doesn't get confused by nested inner classes or any of the other oddities that appear at various points in the JDK source.
You're rolling now. If you think a rule would benefit the Java development community as a whole, post a message to the forum so we can get the rule moved into one of the core rulesets.
Or, if you can improve one of the existing rules, that'd be great too! Thanks!
Finally, for many more details on writing rules, pick up PMD Applied!
--------------------------------------------------------------------------------
© 2002-2012 InfoEther
--------------------------------------------------------------------------------
分享到:
相关推荐
PMD_ruleset规则文件,已经最基本的验证进行了导入。在Eclipse导入即可
**PMD规则文件详解** PMD(英文全称:Poor Man's Dynamic Code Analyzer)是一款开源的静态代码分析工具,主要用于检测Java源代码中可能存在的问题,如潜在的bug、不良的习惯以及可读性差的代码等。在软件开发过程...
在“pmd-rulesets”这个项目中,我们看到了针对Undertow框架的特定定制规则,这对于提高Undertow应用程序的性能和可维护性至关重要。 1. **PMD的运行机制** PMD通过解析Java源代码,运用预定义或自定义的规则进行...
$JAVA_HOME/bin/java -Dpmd.language=en -cp $BASE_PATH/p3c-pmd-2.0.0.jar net.sourceforge.pmd.PMD -d $TEMPDIR -R rulesets/java/ali-comment.xml,rulesets/java/ali-concurrent.xml,rulesets/java/ali-constant....
**PMD** 是一个开源的静态代码分析工具,主要用于检测Java源代码中的潜在问题,比如冗余代码、未使用的变量、空捕获块等。它通过应用一系列预定义的规则来帮助开发者提升代码质量,避免潜在的bug,并遵循最佳编程...
**PMD规则详解:自定义PMD规则在Motech中的应用** PMD(Pattern Matching for Java)是一款开源的静态代码分析工具,它主要用于检测Java源代码中的潜在问题,如未使用的变量、空的循环体、复杂的表达式等。PMD通过...
PMD 代码检查工具使用指南 PMD 是一个静态代码分析工具,主要用于检查 Java 代码的质量和可读性。下面是 PMD 的使用指南,包括安装、运行、规则配置和自定义规则等方面的内容。 安装和运行 PMD 可以通过命令行或...
The PMD Camera, also known as the CamCube 2.0, is a high-resolution 3D video camera that offers an innovative approach to capturing both distance and grayscale images simultaneously. This advanced ...
3. 指定待分析的源代码目录,例如:`pmd -d /path/to/source/code`。 4. 指定要应用的规则集,可以使用默认规则集,也可以自定义,如:`-r rulesets/java/clone.xml`。 5. 输出结果,PMD会生成XML、HTML或文本格式的...
如果预定义的规则不能满足特定需求,开发者可以通过实现PMD的Rule接口来创建自己的规则。这涉及到解析AST节点、定义匹配逻辑以及生成报告信息。 7. 结束语 PMD作为一款强大的静态代码分析工具,能够显著提高代码...
"Eclipse 中 PMD 插件的配置和使用" Eclipse 是一个功能强大的集成开发环境(IDE),它提供了丰富的插件来扩展其功能。PMD(Programming Mistake Detector)是一款流行的插件,用于检测 Java 代码中的错误和不良...
PMD是一种分析Java代码错误的工具。与其他分析工具不同的是,PMD通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多...
3. **RuleSets**:预定义的一系列检查规则,如"Design", "Controversial", "Coupling", "ErrorProne"和"Performance"等,可以根据项目需求选择或自定义。 4. **文档**:包含了详细的用户指南、API文档和规则集说明...
**PMDPlugin for IDEA:IDEA PMD插件详解** PMDPlugin for IDEA是一款针对IntelliJ IDEA(简称IDEA)开发的插件,它的主要功能是集成PMD工具,帮助开发者在编码过程中实时检测并指出项目中的潜在问题。PMD是一款...
**PMD集成Eclipse插件** 是一种强大的静态代码分析工具,它可以帮助开发人员发现并修复Java源代码中的潜在问题,如冗余代码、未使用的变量、不良编程习惯等。集成PMD到Eclipse环境中,可以提升代码质量和可维护性,...
首先,DNA序列由四种核苷酸组成:腺嘌呤(A)、胸腺嘧啶(T)、胞嘧啶(C)和鸟嘌呤(G)。PMD-18T载体序列中包含了这些碱基的组合,形成了一条连续的DNA链。例如,序列中的"TCGCGCGTTT CGGTGATGAC GGTGAAAACC ...
"PMD 工具使用说明中文版" PMD(Program Muscle Detective)是一款静态分析工具,用于检测 Java 代码中的错误和不良实践。下面是 PMD 工具使用说明中文版中涉及的一些重要知识点: 1. PMD 安装与运行 PMD 可以...
pmd -d /path/to/source -r rulesets/java/controversial.xml ``` 2. **IDE集成**:在IDE中,通常可以在项目设置中配置PMD插件,设置规则集,并在保存代码时自动运行检查。 **四、PMD规则集** PMD的规则集分为多...
PMD检查工具4.0是一款针对Java编程语言的静态代码分析工具,旨在帮助开发者发现并修复源代码中的潜在问题,如冗余代码、未使用的变量、空捕获块、复杂度过高的方法等。该工具在Java开发领域广泛应用,通过自定义规则...
通过`Rule Designer`,你可以使用XPath来定义自己的检查规则,但需要对XPath和PMD的工作原理有一定了解。 6. **PMD规则对比**:相比于CheckStyle和FindBugs,PMD的自定义规则更灵活,允许用户使用XPath定义各种规则...