Gradle には標準の静的解析プラグインとして、PMD が組み込まれています。 PMD でソースコードを解析すると、潜在的な不具合や、複雑度が高く将来的に負債になりそうなコードを検出することができます。 よい設計やコーディングができているかが一目瞭然になりますので、すべての Java プロジェクトに採用したいところです。
PMD と似たような静的解析ツールに FindBugs がありますが、FindBugs がコンパイル後のクラスコードに対する解析であるのに対し、PMD はコンパイル前のソースコードを解析します。 無駄なコードはコンパイルの段階で最適化されて削除されてしまうことがあるため、このような無駄なコードを発見するためには、PMD で解析することが必要になります。 また、本家の PMD はコードクローンの発見などの機能 (CPD: Copy/Paste Detector) も備えていますが、Gradle の PMD プラグインはまだ CPD の直接サポートはされていないようです (2015-09-14)。
PMD による静的解析を実施するには、下記のような感じで pmd プラグインを読み込んで設定します。
apply plugin: 'java'
apply plugin: 'pmd'
repositories {
mavenCentral()
}
// PMD のコンフィギュレーション
pmd {
toolVersion '5.3.3' // 使用する PMD のバージョン
ignoreFailures = true // PMD で警告が出てもビルドエラーにしない
consoleOutput = true // コンソールにも解析結果を出力
ruleSets = [ // 適用する PMD ルール(プロジェクトごとに要調整)
'java-basic', // good practices which should be followed
'java-braces', // regarding the use and placement of braces
'java-clone', // questionable usages of the clone() method
'java-codesize', // problems related to code size or complexity
'java-design', // flag suboptimal code implementations
'java-empty', // empty statements of any kind
'java-finalizers', // problems that can occur with finalizers
'java-imports', // problems that can occur with import statements
'java-strictexception', // strict guidelines about throwing and catching exceptions
'java-strings', // manipulation of the String, StringBuffer, or StringBuilder instances
'java-sunsecure', // check the security guidelines from Sun
'java-typeresolution', // rules which resolve java Class files for comparison
'java-unnecessary', // find useless or unnecessary code
'java-unusedcode' // find unused or ineffective code
]
}
PMD プラグインによって、pmdMain や pmdTest などのタスクが定義されます。 これらのタスクは、check タスクに依存するタスクとして定義されるので、check タスクを定義する java プラグインも読み込んでおく必要があります。
pmdMain
あるいは check
タスクを実行することで、PMD による静的解析を実行することができます。
$ gradle pmdMain
:pmdMain
11 PMD rule violations were found. See the report at: /home/maku/myapp/build/reports/pmd/main.html
BUILD SUCCESSFUL
PMD による解析結果は、下記のように出力されます。
マルチプロジェクト構成のプロジェクトでは、サブプロジェクト内で共通の PMD 設定を使用できると便利です。 ここでは、共通の PMD 設定を下記のように定義し、すべてのサブプロジェクトに適用してみます。
apply plugin: 'pmd'
pmd {
toolVersion '5.3.3'
ignoreFailures = true
ruleSets = [
'java-basic', // good practices which everyone should follow
'java-braces', // braces rules
'java-clone', // questionable usages of the clone() method
'java-codesize', // find code size, complexity problems
'java-design', // questionable designs
...
]
}
そして、ルートプロジェクトのビルドスクリプト内で、下記のようにロードすれば OK です。
subprojects {
apply plugin: 'java'
apply from: "$rootDir/gradle/pmd.gradle"
repositories {
mavenCentral()
}
}
PMD で設定できるルールセットは、他にもいろいろ定義されています。
PMD のルールセットは、XML 形式の別ファイルに定義しておくことができます。
複数のプロジェクトで使用するルールセットを定義する場合は、このように設定ファイルとして作成して共有するのがよいでしょう。
ここでは、プロジェクトのルートディレクトリの config/pmd-settings.xml
として配置することにします。
Gradle スクリプトの中では、下記のように ruleSetFiles
でルールセットの XML ファイルを指定します。
apply plugin: 'pmd'
pmd {
toolVersion '5.3.3'
ignoreFailures = true
consoleOutput = true
ruleSetFiles = files("$rootDir/config/pmd-settings.xml")
ruleSets = [] // To apply only the custom rules
}
ポイントは、ruleSets
を空っぽにしておくことです。
この指定を忘れると、XML ファイルで定義したルールと、デフォルトのルールの両方が有効になってしまいます(少なくとも上記で使用している ver 5.3.3 では)。
XML ファイルの中で、何らかのルールを無効 (exclude
) にしている場合は、忘れずに ruleSets
を空にしておかないと、ルールの無効化がうまくいかなかったりします。