靜態分析工具及使用總結(二)
?
這里主要介紹三種開源的工具,PMD、CheckStyle和FindBugs,著重是在Ant里的調用,據說商業軟件JTest也是著名的代碼分析工具,哈哈,要花錢的沒有用過。
?
Checkstyle
(http://checkstyle.sourceforge.net/)版本4.2
簡介:
Checkstyle
是一個開發工具,可以幫助程序員遵循代碼規范的編寫代碼,
它自動的處理這些讓人厭煩但卻十分重要的工作,它具有高可配置性,支持絕大多數的代碼規范,比如Sun推薦的代碼約定(http://java.sun.com/docs/codeconv/)和其它眾所周知的約定,Checkstyle可以檢查代碼的很多方面,從傳統觀點看,它主要是用來檢查代碼層面的,自從第三版以后,它的內部架構作了重大改變,很多其它意圖的檢測加了進來,現在Checkstyle可以檢查像類設計的問題,重復代碼,如鎖的雙重檢查的bug模式。
?
配置:
Checkstyle
配置插件式的modules應用在java代碼上,modules是一個以
Checker module
為根的樹形結構,根下的層次包括:
FileSetChecks
取一組輸入文件,并提示錯誤信息
Filters
過濾審核事件,包括錯誤信息
AuditListeners
報告接受的事件
許多的檢查是TreeWalker FileSetChecks module下的submodules,TreeWalker單獨的轉換每個java源文件成抽象的語法樹,然后根據這些submodules處理得到結果,這些submodules會輪流的查看樹的某個方面。Checkstyle從一個XML文檔中獲得配置,XML的元素指定了module的層次配置和屬性,如果用命令行的方式調用Checkstyle,需要提供一個包含配置文檔的文件,在Ant中調用也是。Checkstyle發布版本中的doc目錄下包含一個示例配置文件sun_checks.xml,這個文件配置Checkstyle檢查代碼是否符合Sun的代碼約定。
?
??? 如:
<module?name="Checker">
????<module?name="PackageHtml"/>
????<module?name="TreeWalker">
????????<module?name="AvoidStarImport"/>
????????<module?name="ConstantName"/>
????????<module?name="EmptyBlock"/>
????</module>
</module>

在這個配置里,根Check module包括PackageHtml(檢查所有的包都必須包含包說明)和TreeWalker(檢查java源代碼方面的),以上Checkstyle通過module的名字來裝載一個類,還有其它的方式來裝載module類,比如指定帶包全名的類,如<module name="com.puppycrawl.tools.checkstyle.TreeWalker">。
每個module都會有一些默認的屬性,如果默認值不符合你的要求,你可以指定它,更詳細的參考請參閱文檔。
?
用法:
可以在命令行下執行Checkstyle,如:
???
java com.puppycrawl.tools.checkstyle.Main -c docs/sun_checks.xml \ -r src/
表示對src下的所有java源文件進行檢查,而配置文件是用的sun_checks.xml
我主要介紹在Ant中的調用
????? 下面列出主要的Ant配置信息:
<
path?
id
="checkstyle.path"
>
????
????
<
fileset?
dir
="${lib.dir}/checkstyle-4.2"
>
????????
<
include?
name
="**/*.jar"
?
/>
????
</
fileset
>
</
path
>
<
target?
name
="checkstyle"
>
????
<
taskdef?
resource
="checkstyletask.properties"
?classpathref
="checkstyle.path"
/>
<
checkstyle?
config
="${lib.dir}/checkstyle-4.2/sun_checks.xml"
????????failureProperty
="checkstyle.failure"
????????failOnViolation
="false"
>
????????
<!--
?uncomment?to?print?to?console?as?well?
-->
????????
<!--
formatter?type="plain"/
-->
????????
<
formatter?
type
="xml"
?tofile
="d:\checkstyle.xml"
/>
????????
<
fileset?
dir
="${src.dir}"
>
????????????
<
include?
name
="**/*.java"
/>
????????
</
fileset
>
????
</
checkstyle
>
????
<
style?
in
="d:\checkstyle.xml"
?out
="d:\checkstyle.html"
?
style
="${lib.dir}/checkstyle-4.2/contrib/checkstyle-noframes.xsl"
/>
</
target
>
自帶檢查介紹:
Checkstyle
自帶了很多的檢查,其網站上有按功能劃分的參考,分為標準
檢查和可選檢查,可選檢查提供了J2EE方面的檢查,如EJB和LocalHomeInterface等的一些檢查。標準檢查涵蓋以下方面:
Javadoc Comments
和javadoc注釋有關的檢查,如檢查類、方法等的javadoc注釋
Naming Conventions
命名規范的檢查,可以按照正則表達式去檢查類、方法等的命名
Headers
檢查文件是否以某些行開頭,如“Copyright All rights reserved”
Imports
和import有關的檢查,如檢查是否有使用“*”的import
Size Violations
代碼塊大小的檢查,如類、方法等的代碼行數
Whitespace
空白處的檢查,如檢查是否有tab符合(’\t’)
Modifiers
修飾符號的檢查,如修飾符號的順序
Block Checks
塊的檢查,如檢查是否有空塊或不必要、無效的塊等
Coding
編碼相關的一系列檢查,如空的條件,私有變量如果沒有改變值應該聲明成
Final
,代碼中的魔法數字,Switch缺少default等
Class Design
類設計的有關檢查,如只有私有構造函數的類應該聲明為final
Duplicate Code
檢查重復代碼
Metrics
度量方面的檢查,如布爾表達式的復雜,類依賴的復雜,算法的復雜
Miscellaneous
其它混雜的檢查,如文件是否以新行結尾,TODO的注釋,沒有注釋main
方法
?
擴展Checkstyle:
Checkstyle
有三種方式進行擴展,編寫checks、編寫filters和編寫
listeners
。
?
編寫checks
Checkstyle
有兩種checks,在你開始之前,你要想好想要實現哪種檢查,Checkstyle的功能是由可嵌入它的modules進行擴展的,modules中也可以包含modules,它們可以構成一個樹形結構,直接訪問Checkstyle內核的頂級module擴展了FileSetCheck接口,實際上也是一個module,它構成樹形結構的根,這很好理解,它們讀入一組輸入文件,并且引發錯誤信息。Checkstyle提供了一些FileSetCheck的擴展,比如說TreeWalker,TreeWalker分別轉換java源文件成一個抽象語法樹,根據每個submodules去處理結果,這些submodules會輪流檢查樹的某些方面。
?
每個java程序是由文件組織的,文件又由一些特定的結構構成,你必須對基本的java語法很了解,Checkstyle是使用ANTLR(http://www.antlr.org/)去解析java代碼的,這個工具可以把java源文件中的字符流轉換成一個樹形的結構。Checkstyle提供了一個GUI的工具,它可以把java源文件轉換成樹形結構。
?
當ASTs(抽象語法樹)工作時,我們可以很簡單的通過一個方法去確定AST的節點,但這不是編寫插件的方法,這些類不會具有檢查功能,而TreeWalker包括遵循Check接口的一系列對象,它是一個抽象類并且提供了一些有用的方法,它提供一些以AST做參數的方法,這些方法可以對AST進行檢查操作,如visitToken()。單獨的Checks不能在AST里移動,而是TreeWalker會從AST的根節點到葉節點進行遞歸,并且調用檢查方法,移動采用的是深度優先算法。
當一個檢查方法調用時,TreeWalker會調用beginTree()使Checks可以做一些初始化的操作,然后從根節點到葉節點的遞歸過程中,會調用visitToken(),當一個節點處理完,TreeWalker從這個節點返回前會調用leaveToken(),離開根的時候會調用finishTree()。
?
??? 編寫好后,我們可以通過下面方式集成:
<module?name="Checker">
??<module?name="TreeWalker">
????<!--?your?Check?goes?here?-->
????<module?name="com.mycompany.checks.MethodLimitCheck">
??????<property?name="max"?value="45"/>
????</module>
??</module>
</module>

這種方式編寫的Checks有兩個缺陷,不能確定具體的表達式的類型和不能訪問其它文件的內容。另一種方式是編寫FileSetChecks,編寫FileSetChecks更簡單,只要繼承
AbstractFileSetCheck
和實現process(File[] files)方法,這種Checks沒有限制,所以我們甚至可以做,找一個全局的代碼問題,如未使用的public方法,重復的代碼,或者像TreeWalker檢查java那樣檢查C#代碼。
?
編寫filters
當Checks通過監聽器生成報告時,審核事件上有一組的過濾器,Filter接口和類FilterSet通過一組過濾器支持審核事件的過濾。我們編寫Filters可以選擇實現接口Filter或繼承類FilterSet。
?
編寫listeners
一個Checkstyle listener在一個Checker檢查文件的期間會監視進度,一個Checker在重大事件發生時會通知其上的listeners,比如檢查開始或記錄錯誤,listeners會適當的響應,一個Checker能附加任意數量的listeners,一次審核總會加上發布版本里的listeners以報告事件,如DefaultLogger或XMLLogger,DefaultLogger在事件發生時會輸出簡單的文本,而XMLLogger會輸入XML文檔。對一般用戶來說,這兩個我們已經夠用了,但如果你有別的需要,那你就需要定制你的listener了,比如說,你想在Checkstyle運行時,得到詳細的進度信息,或者過濾錯誤事件。
?
一個listener必須實現AuditListener接口,在一次審核過程中,Checker會通知其上的AuditListener六種事件,審核開始/結束,過濾開始/結束,記錄錯誤/異常。有事件發生需要通知listener時的事件稱為AuditEvent,一個文件相關的事件包含文件名,記錄錯誤的事件包含錯誤信息,嚴重級別,信息產生的源比如說是一個Checker,和文件行數、和錯誤有關的列數,異常通知的事件包含錯誤的AuditEvent和異常細節。
?
定制listener時需實現AuditListener,如果有可配置的屬性,就必須繼承AutomaticBean。Checkstyle的文檔里提供了兩個listeners的例子,一個是使用當前的Logger記錄信息CommonLoggingListener,一個是用郵件發送審核報告MailLogger。
?
?
參考文檔:
Checkstyle
官方文檔(http://checkstyle.sourceforge.net/)
代碼靜態分析(http://blog.donews.com/foxgem/archive/2005/04/23/347444.aspx)