<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      用PMD自動執行Java代碼靜態區分

      [摘要]作者:仙人掌工作室   一、基礎知識   PMD是一種分析Java代碼錯誤的工具。與其他分析工具不同的是,PMD通過靜態分析獲知代碼錯誤。也就是說,在不運行Java程序的情況下報告錯誤。PMD附帶了...
      作者:仙人掌工作室

        一、基礎知識

        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能夠助你一臂之力!  


      日韩精品一区二区三区高清