Kotlinの静的解析ツールDetektを導入する (Part 1/2)

よく使われてるKotlinのLintツールとしては、ktlintがあると思いますが、今回はDetektを紹介したいと思います。

DetektはKotlinのコード静的解析ツールになっていて、フォーマットエラーやCode smellを検出してくれるものになります。

ktlintに比べて更に細かいことをしてくれますし、コードで問題がありそうな箇所も検出してくれるの、うまく運用すると非常に強力なものになると思います。

セットアップ

Detektの導入はドキュメントを見ても分かりにくい部分があるので、まずは最低限の設定でやっていきます。

今回はKotlin DSLを使った例になります。

まずはDetektのGardle Pluginをプロジェクト直下の build.gradle に追加します。

plugins {
id("io.gitlab.arturbosch.detekt").version("1.22.0-RC1")
}

次に各モジュールでDetektのプラグインを有効にします。モジュール分割をしていない場合は適宜置き換えてください。

subprojects {
apply(plugin = "io.gitlab.arturbosch.detekt")
detekt {
// ここに設定を書いていく
}
}

これだけで一応は動かくすことが出来ます。

./gradlew tasks — all | grep detekt を実行してDetektのGradleタスクが生成されていればOKです。

Detektの実行

Detektの実行には2つの種類があり、Type Resolution(型解決)を使用した解析を行うかどうかです。

Type Resolutionは現在まだExperimetalになっています。

Type Resolutionを使用しない

単純にコードのフォーマットやスタイルだけを解析する場合は、以下のように実行します。

$ ./gradlew detekt

これを実行してルールに違反してるものがある場合はエラーになると思います。またレポートファイルはデフォルトでは buid/reports/detekt フォルダに出力されます。

Type Resolutionを使用

Type Resolutionを使用することで更に高度な解析ができるようになります。

DetekのGradle PluginによってType Resolutionを使用するためのタスクが生成されているのでそちらを使用します。 main のsourceSetの場合は detektMaintest のsourceSetの場合は detektTest になります。

$ ./gradlew detektMain
$ ./gradlew detektTest

Androidの場合は detekt<Variant> のタスクを使用していきます。同様にUnitTestとAndroidTestもそれぞれ別のタスクになってるので、そちらを実行します。

$ ./gradlew detektDebug
$ ./gradlew detektDebugUnitTest
$ ./gradlew detektDebugAndroidTest

Detektの設定ファイル生成

デフォルトの設定を変更するには、設定ファイルを使ってDetektの動作を制御することができます。

設定ファイルを生成するためには、 以下のコマンドで生成することが出来ます。

./gradlew detektGenerateConfig

実行後に、 config/detekt/detekt.yml が生成されます。この内容はすべてデフォルトになってるので必要な項目を編集します。
Detektの設定について後述します。

ただ、この状態だとすべての設定ファイルに記載されています。
次で説明しますが、Gradleの設定で buildUponDefaultConfig = true にすることで上書きしたい項目だけを detekt.yml に記載するだけでよくなります。

Gradle Pluginの設定

Gradle側で設定できる項目について簡単に紹介します。詳細はドキュメントを確認してみてください。

設定項目の例です。

Detektの設定

DetektではYAMLファイルにて設定をしていきます。

繰り返しになりますが、 detektGenerateConfig で生成した設定ファイルはすべての項目が出力されてだいぶ膨大ですが、 Gradle側で buildUponDefaultConfig = true を設定することでデフォルトから変更したい箇所だけを記述することが出来ます。

ここではよく設定されるだろう項目について見ていきます。

レポートファイル

出力するレポートファイルを指定することが出来ます。DetektはText, XML, HTML, Markdown, Sarifをサポートしています。

Detektで設定するには出力しないものを指定する感じになります。

output-reports:
active: true
exclude:
- 'HtmlOutputReport'
- 'MdOutputReport'

この例だとHTMLとMarkdownのものは出力しない設定になります。

ルールの設定

ルールの有効・無効、ルールごとの設定などもYAMLで設定していきます。

DetektではRule Setといういくつかのルールがまとめられたものがあり、その中にルールがある感じになります。

ドキュメントのサイドバーの Rules Documentation を展開すると提供されてるRule Setが確認できます。このRule Setのなかに複数のルールがあります。

このドキュメントを見ながら設定していくのが良いと思います。

例で Style Rule Set から MandatoryBracesIfStatements のルールを見ていきます。 https://detekt.dev/docs/rules/style#mandatorybracesifstatements

ドキュメントのキャプチャにコメントしていますが、この内容をもとに設定していきます。このルールは複数行のif文で中括弧が無いものを検出します。ドキュメントを見るとをデフォルトでは無効になっているので、有効にする設定をします。

style:
MandatoryBracesIfStatements:
active: true

この例では style がRule Set、MandatoryBracesIfStatementsがルール(Issueとも呼ばれる)になっています。

基本的に有効、無効は active を設定するだけで切り替えられます。

もう一つ他の例を見てみます。 Complexity Rule SetNamedArguments のルールを見てみます。
https://detekt.dev/docs/rules/complexity#namedarguments

このルールは引数の数が多い場合は名前付き引数で渡す必要があります。

最初の例と異なる部分として、 Requires Type Resolution と、 Configuration options があります。
このルールはType Resolutionを使用する必要があるので、 detektMain 等で実行しないと検出されません。
ルール固有の設定は以下のようにYAMLで設定できます。

complexity:
NamedArguments:
active: true
threshold: 1 # デフォルトは3だけど、1に変更している

Detektが提供してるルールは他にもたくさんあるので、一通り眺めておくと良いと思います。

つづく

長くなりそうだったので、続きは別記事で書きました。

--

--

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Kenji Abe

Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO