⚙️

Kotlin の静的解析ツール Detekt でルールをディレクトリごとにオンオフする

2024/03/09に公開

日本語でざっと方法を探したけどパッとみつからなかったので簡単にまとめる。

設定する

プロジェクトごとにいろいろ都合はあるはずで、「このテストクラスが巨大なのは妥当じゃん」とか「リクエスト送受信とかデータベースで 3 とか出てくるのはどうしようもないじゃん」みたいな状況は絶対にある。 [1][2]

そういうときは detekt.yml などの設定ファイルでルールごとに excludes を設定すると制御できる。

complexity:
  LargeClass:
    excludes:
      - "**/test/**"

吟味した上で、必要に応じて活用したい。

標準設定について

どうしても 3 などの数値が出てきやすいデータベース関係のコードなどは、MagicNumberexcludes で無効化する。

style:
  MagicNumber:
    excludes:
      - "**/database/**"

しかしこれで検査を実行すると、テストコードが急に怒られるようになる。

$ ./gradlew detekt
/xxx/xxx/src/test/kotlin/xxx/XxxTest.kt:16:28
This expression contains a magic number.
Consider defining it to a well named constant. [MagicNumber]

実は Detekt は標準設定がいろいろされており、ルールによっては最初から excludes が設定されていることがある。

標準のルールが知りたい場合は、設定ファイルをいったん消してから次のコマンドを実行すると 1,000 行くらいの設定ファイルが吐き出される。

$ ./gradlew detektGenerateConfig

Successfully copied default config to /xxx/xxx/detekt.yml

MagicNumber に該当する部分は次のとおり。

style:
  MagicNumber:
    active: true
    excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts' ]
    ignoreNumbers:
      - '-1'
      - '0'
      - '1'
      - '2'
    ignoreHashCodeFunction: true
    ignorePropertyDeclaration: false
    ignoreLocalVariableDeclaration: false
    ignoreConstantDeclaration: true
    ignoreCompanionObjectPropertyDeclaration: true
    ignoreAnnotation: false
    ignoreNamedArgument: true
    ignoreEnums: false
    ignoreRanges: false
    ignoreExtensionFunctions: true

最初からテストっぽいものが除外されているとわかる。
ちなみに 01 の使用は実は許されている。

ignore~ のようなルール固有の設定は、説明と初期値を公式ドキュメントで確認できる。

https://detekt.dev/docs/rules/style#magicnumber

おまけ: @Suppress との付き合い方

@Suppress アノテーションを使うとディレクトリ単位ではなく該当箇所のみ無効化できる。

@Suppress("MagicNumber")
fun getValue(): Int {
    return 3
}

ただし @Suppress の運用をベースにすると「この @Suppress はいいけどその @Suppress はだめでしょ」みたいなことが起きる。

静的解析ツールを使って検査を自動化したはずなのに、@Suppress の運用が妥当かを人間がチェックするのは本末転倒だろう。

原則 @Suppress は使用しないのが望ましいと思う。

おまけ: ルールの探し方

ルールを書く際に LargeClasscomplexity の設定、MagicNumberstyle の設定、と決められている。

complexity:
  LargeClass:
    ...

style:
  MagicNumber:
    ...

しかしエラーメッセージにはカテゴリ名が書いてないので、 MagicNumber というルールに抵触したことしかわからない。

This expression contains a magic number.
Consider defining it to a well named constant. [MagicNumber]

カテゴリを調べたいときは、公式サイト ( https://detekt.dev/ ) で Search すればいい。

最初全部 style の下に書くものだと思い込んでいてハマった。

[style.MagicNumber] とか怒ってくれればいいのにな?

脚注
  1. where status = 3 みたいなのは意味を把握しやすいようにリファクタリングする前提。 ↩︎

  2. でも if (status = 3) return Status.ACTIVE みたいなところは ACTIVE = 3 の定数を作る価値ってあまりなくない?みたいな状況。 ↩︎

Discussion