选择显示字体大小

用pmd自动执行java代码静态分析

xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 

 一、基础知识
  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能够助你一臂之力!


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons