Scalaの静的チェックツール試してみた

みなさん、Scalaの静的チェックツール使ってますか？

今回、Githubで☆多めな次の4つの静的チェックツールを試してみました。(2015/12/21時点)

- [WartRemover](https://github.com/puffnfresh/wartremover)(414)
- [Scalastyle](https://github.com/scalastyle/scalastyle)(332)
- [Linter Compiler Plugin](https://github.com/HairyFotr/linter)(135)
- [Scapegoat](https://github.com/sksamuel/scalac-scapegoat-plugin)(112)

それぞれのツールを使って、[fpinscala/exercises](https://github.com/fpinscala/fpinscala)をlintにかけてみます。

## 比較結果

以下の点を比較しました。

- デフォルトで用意されてるルールの数
- fpinscala/exercisesをlintして検出されたエラーの数

初期設定で出るエラーの量が多いほど、心を折る効果が高くていいですね。

ルール, エラーはそれぞれで粒度も違いますので、参考程度に...
WartRemoverはデフォルトでは何もルールが有効になっていないので、Warts.allですべてのルールを設定しました。

||ルール数|エラー数|
|:--|:--|:--|:--|
|WartRemover|27|328 errors|
|Scalastyle|63|266 warnings|
|Linter Compiler Plugin|103|6 warnings|
|Scapegoat|107|8 errors, 163 warnings, 35 infos|

## 使い方
ではそれぞれのlinterをfpinscalaのsbtプロジェクトに組み込んで、使い方をみていきましょう。

## WartRemover

sbtプラグインが提供されています。

`project/plugins.sbt`を以下の内容で作り、`project/Build.scala`に追記します。

```scala:project/plugins.sbt
addSbtPlugin("org.brianmckenna" % "sbt-wartremover" % "0.14")
```

```scala:project/Build.scala
object FPInScalaBuild extends Build {
  val opts = Project.defaultSettings ++ Seq(
    scalaVersion := "2.11.7",
    resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/",
    wartremover.wartremoverErrors ++= wartremover.Warts.all
  )
...
```

これで、compileタスクでWartRemoverが有効になります。

```bash
$ sbt exercises/compile
...
[error] 328 errors found
[error] (exercises/compile:compileIncremental) Compilation failed
[error] Total time: 12 s, completed Dec 21, 2015 7:11:31 PM
```

## Scalastyle

これもsbtプラグインが提供されています。

```scala:project/plugins.sbt
addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.8.0")
```

Scalastyleもcompileタスクに組み込むことはできますが、`scalastyle`というタスクが定義されるので、それを使ってみます。

```bash
$ sbt exercises/scalastyleGenerateConfig exercises/scalastyle
...
[info] Processed 22 file(s)
[info] Found 0 errors
[info] Found 266 warnings
[info] Found 0 infos
[info] Finished in 45 ms
```

また、結果が`exercises/target/scalastyle-result.xml`に出力されます。

## Linter Compiler Plugin

これは名前の通りCompiler Pluginです。

```scala:project/Build.scala
object FPInScalaBuild extends Build {
  val opts = Project.defaultSettings ++ Seq(
    scalaVersion := "2.11.7",
    resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/",
    addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1.12")
  )
...
```

これでphaseが追加されます。

```bash
$ sbt exercises/compile
...
[warn] 6 warnings found
```

余談ですが、Linter Compiler Pluginは[scalastyle使ってるみたい](https://github.com/HairyFotr/linter/blob/master/project/plugins.sbt)ですね

## Scapegoat

こちらもsbtプラグインです。

```scala:project/plugins.sbt
addSbtPlugin("com.sksamuel.scapegoat" %% "sbt-scapegoat" % "1.0.0")
```

これで`scapegoat`タスクが定義されます。

```bash
$ sbt exercises/scapegoat
...
[warning] fpinscala.testing.Gen.scala:20: Unused method parameter
          Unused method parameter (val f: A => Boolean = _)

[warning] fpinscala.testing.Gen.scala:24: Unused method parameter
          Unused method parameter (val a: => A = _)

[error] [scapegoat] Analysis complete - 8 errors 163 warns 35 infos
```

## まとめ

☆の数どおり、(ほぼ)初期設定で検出するエラーの数・compileタスクへの組み込みの容易さはWartRemover, Scalastyleに軍配が上がりそうです。

また今回は紹介できませんでしたが、WartRemoverではWartTraverserをextendsして手軽に独自ルールが定義できるようです。

Scapegoatの[README](https://github.com/sksamuel/scalac-scapegoat-plugin/blob/master/README.md)には、

> In fact it could be beneficial as the total set of possible warnings is the union of the inspections of all the enabled tools.

と述べられており、複数のlintツールを使ってもいいかもしれません。