小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

用PMD自動(dòng)執(zhí)行Java代碼靜態(tài)分析

 左目右于 2011-08-28
一、基礎(chǔ)知識(shí)
  PMD是一種分析Java代碼錯(cuò)誤的工具。與其他分析工具不同的是,PMD通過(guò)靜態(tài)分析獲知代碼錯(cuò)誤。也就是說(shuō),在不運(yùn)行Java程序的情況下報(bào)告錯(cuò)誤。PMD附帶了許多可以直接使用的規(guī)則,利用這些規(guī)則可以找出Java源程序的許多問(wèn)題,例如沒(méi)有用到的變量、多余的變量創(chuàng)建操作、空的catch塊,等等。此外,用戶(hù)還可以自己定義規(guī)則,檢查Java代碼是否符合某些特定的編碼規(guī)范。例如,你可以編寫(xiě)一個(gè)規(guī)則,要求PMD找出所有創(chuàng)建Thread和Socket對(duì)象的操作。
  最初,PMD是為了支持Cougaar項(xiàng)目而開(kāi)發(fā)的。Cougaar是美國(guó)國(guó)防高級(jí)研究計(jì)劃局(Defense Advanced Research Projects Agency,DARPA)的一個(gè)項(xiàng)目。DARPA開(kāi)放了PMD的源代碼,所以PMD被發(fā)布到了SourceForge網(wǎng)站上。不久前,PMD的下載次數(shù)就超過(guò)了14000次,頁(yè)面瀏覽次數(shù)超過(guò)了130000次。更重要的是,在源代碼開(kāi)放作者的努力下,越來(lái)越多的PMD規(guī)則和IDE插件被開(kāi)發(fā)出來(lái),然后加入到了PMD的核心項(xiàng)目之中。
  你可以從PMD的網(wǎng)站下載PMD的二進(jìn)制版本,或下載帶源代碼的版本,下載得到的都是ZIP文件。假設(shè)你下載了二進(jìn)制版本,先把它解壓縮到任意一個(gè)目錄。接下來(lái)怎么做,就要看你準(zhǔn)備怎么用它——最簡(jiǎn)單的,如果要在一個(gè)Java源代碼目錄中運(yùn)行PMD,只需直接在命令行上運(yùn)行下面的命令:
C:\data\pmd\pmd>java -jar lib\pmd-1.02.jar c:\j2sdk1.4.1_01\src\java\util
text rulesets/unusedcode.xml
  輸出結(jié)果類(lèi)如:

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'
  除了直接在命令行上運(yùn)行PMD之外,還可以通過(guò)Ant、Maven或者各種集成開(kāi)發(fā)環(huán)境(IDE)運(yùn)行PMD,例如jEdit、Netbeans、Eclipse、Emacs、IDEAJ和JBuilder等。
  二、內(nèi)建規(guī)則
  PMD本身就附帶了許多規(guī)則。下面是幾個(gè)例子。
沒(méi)有用到的代碼顯然是應(yīng)該被清除的。
public class Foo {
// 下面這個(gè)實(shí)例變量沒(méi)有用到
private List bar = new ArrayList(500);
}
如果用一個(gè)接口也能達(dá)到同樣的目標(biāo),為什么要返回一個(gè)具體的類(lèi)?例如,下例可以改用List接口。
public ArrayList getList() {
return new ArrayList();
}
當(dāng)if的條件為真時(shí),if代碼塊其實(shí)不做任何事情。下面這段代碼其實(shí)可以寫(xiě)得更加簡(jiǎn)潔一些。
public void doSomething(int y) {
if (y >= 2) {
} else {
System.out.println("Less than two");
}
}
為什么要?jiǎng)?chuàng)建一個(gè)新的String對(duì)象?只
要改用String x="x"就可以了。
String x = new String("x");
 
  PMD還包含其他許多內(nèi)建規(guī)則,但從上面幾個(gè)例子已經(jīng)可以看出PMD的基本工作方式。只要定義適當(dāng)?shù)撵o態(tài)規(guī)則,PMD就可以象一個(gè)富有經(jīng)驗(yàn)的程序員那樣,幫你指出代碼存在的問(wèn)題。
  三、工作原理
  PMD的核心是JavaCC解析器生成器。PMD結(jié)合運(yùn)用JavaCC和EBNF(擴(kuò)展巴科斯-諾爾范式,Extended Backus-Naur Formal)語(yǔ)法,再加上JJTree,把Java源代碼解析成抽象語(yǔ)法樹(shù)(AST,Abstract Syntax Tree)。顯然,這句話(huà)不那么好懂,且看下文具體說(shuō)明。
  從根本上看,Java源代碼只是一些普通的文本。不過(guò),為了讓解析器承認(rèn)這些普通的文本是合法的Java代碼,它們必須符合某種特定的結(jié)構(gòu)要求。這種結(jié)構(gòu)可以用一種稱(chēng)為EBNF的句法元語(yǔ)言表示,通常稱(chēng)為“語(yǔ)法”(Grammar)。JavaCC根據(jù)語(yǔ)法要求生成解析器,這個(gè)解析器就可以用于解析用Java編程語(yǔ)言編寫(xiě)的程序。
  不過(guò)實(shí)際運(yùn)行中的PMD還要經(jīng)過(guò)JJTree的一次轉(zhuǎn)換。JJTree是一個(gè)JavaCC的插件,通過(guò)AST擴(kuò)充JavaCC生成的解析器。AST是一個(gè)Java符號(hào)流之上的語(yǔ)義層。有了JJTree,語(yǔ)法分析的結(jié)果不再是“System, ., out, ., . println”之類(lèi)的符號(hào)序列,而是一個(gè)由對(duì)象構(gòu)成的樹(shù)型層次結(jié)構(gòu)。例如,下面是一段簡(jiǎn)單的Java代碼以及與之對(duì)應(yīng)的AST。
Java源代碼:
public class Foo {
public void bar() {
System.out.println("hello world");
}
}
對(duì)應(yīng)的抽象語(yǔ)法樹(shù)
CompilationUnit
TypeDeclaration
ClassDeclaration
UnmodifiedClassDeclaration
ClassBody
ClassBodyDeclaration
MethodDeclaration
ResultType
MethodDeclarator
FormalParameters
Block
BlockStatement
Statement
StatementExpression
PrimaryExpression
PrimaryPrefix
Name
PrimarySuffix
Arguments
ArgumentList
Expression
PrimaryExpression
PrimaryPrefix
Literal
 
  四、編寫(xiě)規(guī)則
  前面我們看到了Java源代碼以及與之對(duì)應(yīng)的對(duì)象層次結(jié)構(gòu)。下面我們就要利用這些對(duì)象編寫(xiě)PMD規(guī)則檢查代碼存在的問(wèn)題。
  一般地,一個(gè)PMD規(guī)則可以看成一個(gè)Visitor,它遍歷AST,尋找多個(gè)對(duì)象之間的一種特定模式,這種模式表示代碼存在的問(wèn)題。問(wèn)題模式可能簡(jiǎn)單也可能復(fù)雜,簡(jiǎn)單的如查找代碼中是否包含new Thread關(guān)鍵詞,復(fù)雜的如確定一個(gè)類(lèi)是否正確覆蓋了equals和hashcode。
  下面是一個(gè)尋找空if語(yǔ)句的簡(jiǎn)單PMD規(guī)則。
//擴(kuò)展AbstractRule,以啟用Visitor模式
public class EmptyIfStmtRule extends AbstractRule implements Rule {
//當(dāng)源代碼中出現(xiàn)一個(gè)Block,下面的方法被調(diào)用
public Object visit(ASTBlock node, Object data){
//如果父節(jié)點(diǎn)是一個(gè)if語(yǔ)句且代碼塊里面沒(méi)有任何內(nèi)容
if ((node.jjtGetParent().jjtGetParent() instanceof ASTIfStatement)
&& node.jjtGetNumChildren()==0) {
//肯定代碼存在問(wèn)題。把一個(gè)RuleViolation加入到Report。
RuleContext ctx = (RuleContext)data;
ctx.getReport().addRuleViolation(createRuleViolation(ctx,
node.getBeginLine()));
}
//繼續(xù)檢查樹(shù)的下一個(gè)節(jié)點(diǎn)
return super.visit(node, data);
}
}
  也許你不能一下子掌握這段代碼,其實(shí)它的思路還是比較簡(jiǎn)單的:
  #擴(kuò)展AbstractRule基類(lèi)。
  #聲明一個(gè)“鉤子”,一旦我們感興趣的節(jié)點(diǎn)出現(xiàn),它就會(huì)被調(diào)用(稱(chēng)為“回調(diào)”)。在上面的例子中,我們要求在每一個(gè)ASTBlock出現(xiàn)時(shí)得到通知,所以聲明visit(ASTBlock node, Object data)。
  #在回調(diào)函數(shù)中,判斷是否出現(xiàn)了我們正在檢查的問(wèn)題。本例我 們檢查是否存在空的if塊,所以先判斷當(dāng)前是否在A(yíng)STIfStatement之內(nèi),然后判斷它是否有子節(jié)點(diǎn)。
  當(dāng)然,我們還可以按照另一種方法進(jìn)行檢查:聲明一個(gè)要求檢查ASTIfStatement的回調(diào)函數(shù),然后在回調(diào)函數(shù)中檢查是否存在子節(jié)點(diǎn)。
  五、配置規(guī)則
  寫(xiě)好自定義規(guī)則之后,接下來(lái)要把它加入到某個(gè)PMD規(guī)則集。所謂PMD規(guī)則集,就是由一組PMD規(guī)則構(gòu)成的集合。每個(gè)PMD規(guī)則集由一個(gè)XML文件定義,下面是一個(gè)PMD規(guī)則的配置信息的例子:
<rule name="EmptyIfStmt"
message="避免使用空的if語(yǔ)句"
class="net.sourceforge.pmd.rules.EmptyIfStmtRule">
<description>
找到空的if語(yǔ)句:if檢查了條件,但if塊里面沒(méi)有任何內(nèi)容。
</description>
<priority>3</priority>
<example>
<![CDATA[
if (absValue < 1) {
// not good
}
</XMLCDATA>
</example>
</rule>
  可以看出,規(guī)則配置文件包含了許多有用的信息。要運(yùn)行新添加的規(guī)則,只需把規(guī)則集XML文件和Java源代碼文件放入CLASSPATH,然后運(yùn)行PMD。
  結(jié)束語(yǔ):本文介紹了PMD如何在不編譯代碼的情況下分析和尋找代碼存在的問(wèn)題,通過(guò)幾個(gè)簡(jiǎn)單的例子了解了EBNF語(yǔ)法、JavaCC和AST,以及如何用PMD檢查代碼存在的問(wèn)題、如何編寫(xiě)和運(yùn)用定制PMD規(guī)則等。愿PMD能夠助你一臂之力!
文章出處:飛諾網(wǎng)(www.):http://www./course/3_program/java/javaxl/20100630/290433.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多