分享
 
 
 

用PMD自动执行Java代码静态分析

王朝java/jsp·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

一、基础知识

PMD是一种分析Java代码错误的工具。与其他分析工具不同的是,PMD通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题,例如没有用到的变量、多余的变量创建操作、空的catch块,等等。此外,用户还可以自己定义规则,检查Java代码是否符合某些特定的编码规范。例如,你可以编写一个规则,要求PMD找出所有创建Thread和Socket对象的操作。

最初,PMD是为了支持Cougaar项目而开发的。Cougaar是美国国防高级研究计划局(Defense Advanced Research Projects Agency,DARPA)的一个项目。DARPA开放了PMD的源代码,所以PMD被发布到了SourceForge网站上。不久前,PMD的下载次数就超过了14000次,页面浏览次数超过了130000次。更重要的是,在源代码开放作者的努力下,越来越多的PMD规则和IDE插件被开发出来,然后加入到了PMD的核心项目之中。

你可以从PMD的网站下载PMD的二进制版本,或下载带源代码的版本,下载得到的都是ZIP文件。假设你下载了二进制版本,先把它解压缩到任意一个目录。接下来怎么做,就要看你预备怎么用它——最简单的,假如要在一个Java源代码目录中运行PMD,只需直接在命令行上运行下面的命令:

C:\data\pmd\pmd>java -jar lib\pmd-1.02.jar c:\j2sdk1.4.1_01\src\java\util

text rulesets/unusedcode.xml

输出结果类如:

c:\j2sdk1.4.1_01\src\java\util\AbstractMap.java 650

Avoid unused local variables sUCh as 'v'

c:\j2sdk1.4.1_01\src\java\util\Date.java 438

Avoid unused local variables such as 'millis'

除了直接在命令行上运行PMD之外,还可以通过Ant、Maven或者各种集成开发环境(IDE)运行PMD,例如jEdit、Netbeans、Eclipse、Emacs、IDEAJ和JBuilder等。

二、内建规则

PMD本身就附带了许多规则。下面是几个例子。

没有用到的代码显然是应该被清除的。

public class Foo {

// 下面这个实例变量没有用到

private List bar = new ArrayList(500);

}

假如用一个接口也能达到同样的目标,为什么要返回一个具体的类?例如,下例可以改用List接口。

public ArrayList getList() {

return new ArrayList();

}

当if的条件为真时,if代码块其实不做任何事情。下面这段代码其实可以写得更加简洁一些。

public void doSomething(int y) {

if (y >= 2) {

} else {

System.out.println("Less than two");

}

}

为什么要创建一个新的String对象?只要改用String x="x"就可以了。

String x = new String("x");

PMD还包含其他许多内建规则,但从上面几个例子已经可以看出PMD的基本工作方式。只要定义适当的静态规则,PMD就可以象一个富有经验的程序员那样,帮你指出代码存在的问题。

三、工作原理

PMD的核心是JavaCC解析器生成器。PMD结合运用JavaCC和EBNF(扩展巴科斯-诺尔范式,Extended Backus-Naur Formal)语法,再加上JJTree,把Java源代码解析成抽象语法树(AST,Abstract Syntax Tree)。显然,这句话不那么好懂,且看下文具体说明。

从根本上看,Java源代码只是一些普通的文本。不过,为了让解析器承认这些普通的文本是合法的Java代码,它们必须符合某种特定的结构要求。这种结构可以用一种称为EBNF的句法元语言表示,通常称为“语法”(Grammar)。JavaCC根据语法要求生成解析器,这个解析器就可以用于解析用Java编程语言编写的程序。

不过实际运行中的PMD还要经过JJTree的一次转换。JJTree是一个JavaCC的插件,通过AST扩充JavaCC生成的解析器。AST是一个Java符号流之上的语义层。有了JJTree,语法分析的结果不再是“System, ., out, ., . println”之类的符号序列,而是一个由对象构成的树型层次结构。例如,下面是一段简单的Java代码以及与之对应的AST。

Java源代码:

public class Foo {

public void bar() {

System.out.println("hello world");

}

}

对应的抽象语法树

CompilationUnit

TypeDeclaration

ClassDeclaration

UnmodifiedClassDeclaration

ClassBody

ClassBodyDeclaration

MethodDeclaration

ResultType

MethodDeclarator

FormalParameters

Block

BlockStatement

Statement

StatementEXPression

PrimaryExpression

PrimaryPrefix

Name

PrimarySuffix

Arguments

ArgumentList

Expression

PrimaryExpression

PrimaryPrefix

Literal

四、编写规则

前面我们看到了Java源代码以及与之对应的对象层次结构。下面我们就要利用这些对象编写PMD规则检查代码存在的问题。

一般地,一个PMD规则可以看成一个Visitor,它遍历AST,寻找多个对象之间的一种特定模式,这种模式表示代码存在的问题。问题模式可能简单也可能复杂,简单的如查找代码中是否包含new Thread要害词,复杂的如确定一个类是否正确覆盖了equals和hashcode。

下面是一个寻找空if语句的简单PMD规则。

//扩展AbstractRule,以启用Visitor模式

public class EmptyIfStmtRule extends AbstractRule implements Rule {

//当源代码中出现一个Block,下面的方法被调用

public Object visit(ASTBlock node, Object data){

//假如父节点是一个if语句且代码块里面没有任何内容

if ((node.jjtGetParent().jjtGetParent() instanceof ASTIfStatement)

&& node.jjtGetNumChildren()==0) {

//肯定代码存在问题。把一个RuleViolation加入到Report。

RuleContext ctx = (RuleContext)data;

ctx.getReport().addRuleViolation(createRuleViolation(ctx,

node.getBeginLine()));

}

//继续检查树的下一个节点

return super.visit(node, data);

}

}

也许你不能一下子把握这段代码,其实它的思路还是比较简单的:

#扩展AbstractRule基类。

#声明一个“钩子”,一旦我们感爱好的节点出现,它就会被调用(称为“回调”)。在上面的例子中,我们要求在每一个ASTBlock出现时得到通知,所以声明visit(ASTBlock node, Object data)。

#在回调函数中,判定是否出现了我们正在检查的问题。本例我们检查是否存在空的if块,所以先判定当前是否在ASTIfStatement之内,然后判定它是否有子节点。

当然,我们还可以按照另一种方法进行检查:声明一个要求检查ASTIfStatement的回调函数,然后在回调函数中检查是否存在子节点。

五、配置规则

写好自定义规则之后,接下来要把它加入到某个PMD规则集。所谓PMD规则集,就是由一组PMD规则构成的集合。每个PMD规则集由一个XML文件定义,下面是一个PMD规则的配置信息的例子:

<rule name="EmptyIfStmt"

message="避免使用空的if语句"

class="net.sourceforge.pmd.rules.EmptyIfStmtRule">

<description>

找到空的if语句:if检查了条件,但if块里面没有任何内容。

</description>

<priority>3</priority>

<example>

<![CDATA[

if (absValue < 1) {

// not good

}

</XMLCDATA>

</example>

</rule>

可以看出,规则配置文件包含了许多有用的信息。要运行新添加的规则,只需把规则集XML文件和Java源代码文件放入CLASSPATH,然后运行PMD。

结束语:本文介绍了PMD如何在不编译代码的情况下分析和寻找代码存在的问题,通过几个简单的例子了解了EBNF语法、JavaCC和AST,以及如何用PMD检查代码存在的问题、如何编写和运用定制PMD规则等。愿PMD能够助你一臂之力!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有