2014/12/27

Android:Findbugs

はじめに

FindBugsは次の機能を持つ静的検査ツールである.

  • Javaクラスバイナリに対する解析によりバグパターンの検査を行う
  • 解析結果を出力する

FindBugsはJavaクラスバイナリからバグパターンを解析するプログラム. ソースコードリポジトリへのコミット前後でFindBugsによるコード解析を行い, 潜在的な不具合を排除するツールとして非常に強力である.

Javaソースコードを解析したい場合はPMDが利用できる. 実動作により近いクラスバイナリを検査するという点ではFindBugsが有利であるが, ソースコード自体の品質を向上させたい場合はPMDやLintを使用する.
Groovyコードは同じくクラスコードを生成するがFindBugsによる正しい検査はできない.

また, 解析結果を出力する機能もあり, 各種CIツールとの親和性も高い.

FindBugsの動作環境

  • プラットフォーム非依存(GNU/Linux, MacOS X, Windows可)
  • J2SE 1.5以上のランタイムが必要
  • メモリ512MB以上が必要で, 解析対象が巨大である程これは増加する

FindBugs GUI

FindBugsはそれ単体をプログラムとして配布されている.
http://findbugs.sourceforge.net/ja/manual/installing.html#d0e94

FindBugsを単体実行するGUIツールも用意されているが, 昨今ではIDEアプリケーションのプラグインとして導入・実行されるケースが主であるためここでは割愛する.
http://findbugs.sourceforge.net/ja/manual/gui.html

Bug Pattern

下記ページに日本語訳(FindBugsv2.0.2)が纏められている.
http://www.acroquest.co.jp/webworkshop/JavaTroubleshooting/findbugs/

FindBugsを実行する際にはこれらのBug Patternを検査項目としてインプットする.
プロジェクトの特性に合わせて検査項目はフィルタされることもある.

Analysis Properties

FindBugsがソース解析する際の観点を分析プロパティとして実行時に指定することができる.
分析プロパティには主に次の2点を指定する.

  • 分析対象のメソッドの意味
  • 分析の精度

1点目, 分析対象メソッドの意味を指定することでより正確な分析結果を得ることができ, 誤検出を減らすことができる.
2点目, FindBugsが消費するメモリや分析時間が問題となる場合は精度を落とすことで解決できる場合がある. ただし, 検出されるべきバグを見逃す可能性が高くなるデメリットもある.

分析プロパティは-propertyで指定する. 次はその例.

$ findbugs -textui -property "cfg.noprune=true" myApp.jar

-propertyで指定できる分析オプションの一覧は下記を参照.
http://findbugs.sourceforge.net/ja/manual/analysisprops.html

FindBugs Plug-in

IntelliJ IDEA系 IDEにFindBugsを導入する場合は FindBugs-IDEA プラグインが便利.
https://plugins.jetbrains.com/plugin/3847?pr=idea

FindBugsは日本語情報も充実しており, Webで検索すればいくらでも見つけることができる.

CIツールでFindBugsを自動実行させたい場合, Gradleには標準でFindBugs-pluginが用意されている.
http://gradle.monochromeroad.com/docs/userguide/findbugs_plugin.html

NOTE
上記GradleのFindBugsプラグインはjavaプラグインと併用されることを前提としている.
Androidプロジェクトで作成されるbuild.gradleにはjavaプラグインが適用されないため, FindBugsプラグインを動作させるには少し工夫する必要がある.

次のgroovyコードをbuild.gradleに適用するとfindbugsタスクが追加され, Gradle consoleからfindbugsを実行することができるようになる.

apply plugin: 'findbugs'

task findbugs(type: FindBugs) {
    ignoreFailures = true
    classes = fileTree('build/intermediates/classes/debug/')
    source = fileTree('src/main/java/')
    classpath = files()
    effort = 'max'
}
tasks.withType(FindBugs) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}

参考

以上.