ScalaDay 6

scalac にもっと警告してもらう

More than 3 years have passed since last update.

これはScala Advent Calendar 2014 6日目の記事です。

Scala はコンパイルが遅いことで有名ですが、コンパイルの嬉しいところは、実行前に沢山のプログラムミスやミスっぽいものをキャッチできることです。

C を書くときは -Wall -Wextra -Wpedantic あたりをつけるとたくさん警告だしてくれてありがたいですね。Scala の場合もたくさん警告出して欲しい。scalac 2.11.4 にある警告関連のオプションを見てみましょう。


オプションの区分

とその前に、scalac オプションの区分についておさらいです。オプションは


  • -X や -Y 以外から始まる普通のオプション

  • -X から始まる advanced オプション

  • -Y から始まる private オプション

に分類されています。それぞれ scalac -help, scalac -X, scalac -Y でヘルプを見ることが出来ます。

advanced や private の意味するところは正直良くわかっていませんが、普通のオプションより-Xのほうが、-Xより-Yのほうが変化が激しいようです。


普通の警告オプション

普通のオプションで警告関連のものは次の3つです。



  • -deprecation: @deprecated なAPIが使われている箇所を警告します


  • -feature: langauge feature の import が必要な箇所を警告します


  • -unchecked: ヘルプによると Enable additional warnings where generated code depends on assumptions. とのことです(が、何のことだかよくわかってません…)

とりあえず、この3つは付けましょう。


advanced 警告オプション

advanced な警告関連のオプションは -Xlint-Xfatal-warnings です。

-Xlint は様々な警告を有効にします。有効になる警告は scalac -Xlint:help で一覧できます(scala 2.11.2 以降)。2.11.4 で実行してみるとこうなりました。

Enable or disable specific warnings

adapted-args Warn if an argument list is modified to match the receiver.
nullary-unit Warn when nullary methods return Unit.
inaccessible Warn about inaccessible types in method signatures.
nullary-override Warn when non-nullary `def f()' overrides nullary `def f'.
infer-any Warn when a type argument is inferred to be `Any`.
missing-interpolator A string literal appears to be missing an interpolator id.
doc-detached A ScalaDoc comment appears to be detached from its element.
private-shadow A private field (or class parameter) shadows a superclass field.
type-parameter-shadow A local type parameter shadows a type already in scope.
poly-implicit-overload Parameterized overloaded implicit methods are not visible as view bounds.
option-implicit Option.apply used implicit view.
delayedinit-select Selecting member of DelayedInit
by-name-right-associative By-name parameter of right associative operator.
package-object-classes Class or object defined in package object.
unsound-match Pattern match may not be typesafe.

-Xlint とだけ指定すれば、これら全てが有効になります。とにかく一杯警告出して欲しいので -Xlint も指定しましょう。

-Xfatal-warnings は警告をエラーとして扱うオプションです。

個人的には付けるほうが好みですが、どうしても消せない警告があるときにコンパイルできずに困るかもしれません。とりあえず付けた状態で始めて、どうしようもなくなったら外すという運用が良いと思います。


private 警告オプション

scalac -Y 2>&1 | grep warn するとこのようになります。

  -Yinline-warnings                       Emit inlining warnings. (Normally surpressed due to high volume)

-Ywarn-adapted-args Warn if an argument list is modified to match the receiver.
-Ywarn-dead-code Warn when dead code is identified.
-Ywarn-inaccessible Warn about inaccessible types in method signatures.
-Ywarn-infer-any Warn when a type argument is inferred to be `Any`.
-Ywarn-nullary-override Warn when non-nullary `def f()' overrides nullary `def f'.
-Ywarn-nullary-unit Warn when nullary methods return Unit.
-Ywarn-numeric-widen Warn when numerics are widened.
-Ywarn-unused Warn when local and private vals, vars, defs, and types are are unused.
-Ywarn-unused-import Warn when imports are unused.
-Ywarn-value-discard Warn when non-Unit expression results are unused.

いくつかは -Xlint とかぶっているようですね。

かぶっていないものは


  • -Ywarn-dead-code

  • -Ywarn-numeric-widen

  • -Ywarn-unused

  • -Ywarn-unused-import

  • -Ywarn-value-discard

の5つです。

Scala のバージョンによってあったりなかったりすると思うので、利用できる場合には利用すると良いかと思います。

ちなみに -Ywarn-unused-import を指定すると、 sbt consoleimport するたびに警告されます。 -Xfatal-warnings と同時に指定している場合はエラーになってしまいます。

:paste で import 文と使用箇所をまとめて貼り付けるか、console を使う時だけ -Ywarn-unused-import-Xfatal-warnings のどちらかを外すかで回避します。

console で不便なことを差し引いても警告が出たほうがうれしいですね!


sbt での指定方法

scalac コマンドを直接使う時はコマンドライン引数として指定しますが、sbt を使っている方が多いと思います。

sbt での指定方法は build.sbtscalacOptions ++= Seq(/* ここに警告オプション */) です。


まとめ

Scala 2.11.4 で沢山警告をだすには、次のように build.sbt に書きます。


build.sbt

scalacOptions ++= Seq(

"-deprecation",
"-feature",
"-unchecked",
"-Xlint",
"-Ywarn-dead-code",
"-Ywarn-numeric-widen",
"-Ywarn-unused",
"-Ywarn-unused-import",
"-Ywarn-value-discard"
// 警告をエラーにする(お好みに応じて)
, "-Xfatal-warnings"
)

諸般の事情で 2.11.4 を使っていない人も居ると思います。Scala のバージョンによって存在する警告オプション(特に -Ywarn-なんとか )は異なるので、 scalac -help, scalac -X, scalac -Y を参照して存在する警告オプションを片っ端から有効にしましょう。

私たちが間違った方向に行くのをいつも諌めてくれる scalac 先生に感謝しましょう。