散々tweetしているし、少し前にblogに書きましたが、
それを正式に本体に入れてリリースしました。という話
https://docs.scala-lang.org/scala3/reference/metaprogramming/tasty-inspect.html
モチベーションやメリットは、例えばこのあたり。 あくまで、complie時にcompiler pluginとしてではなく、別のタイミングで何度も実行可能なのがポイント。
twitter.comwartremoverのsbt pluginからTASTy inspectorを呼び出して、コンパイル"後"にlint実行可能なやつが大体出来てきた。
— Kenji Yoshida (@xuwei_k) 2022年4月1日
これだとlintする項目を後から増やしても、コンパイル自体は、やり直す必要がないから、一度コンパイルしたものさえあれば色々素早く試せて便利。
それはscalafixもそうなのだけど、
大まかなアーキテクチャや内部構造
- 依存が増えるので、wartremover本体とは別のwartremover-inspectorのsub project作成
- wartremover-inspectorの内部自体は、色々整理したりパラメーター増やしたが、根本的には前blog書いたようなもの
- さらに、sbt pluginと共通のinterfaceであるwartremover-inspector-commonも作成
- wartremover-inspectorは、wartremover-inspector-commonとwartremoverのcoreに依存
- sbt-pluginは、新たにwartremover-inspector-commonに依存
- sbt-pluginから、derivedProjectsというsbtの機能使った暗黙的にproject追加する機能を使って、inspectorの実行projectを作っておく
- extraProjectsはbugがあって辛い
- と思ったらderivedProjectsもbugあるような https://github.com/sbt/sbt/issues/6860
- TASTy inspectorは、NIGHTLYでないと致命的なbugがある気がするので、あえてNIGHTLY指定
- sbtからwartremover-inspectorを呼び出す方式を色々悩んだが、引数を全部JSON文字列にして、直接リフレクションで呼び出して、結果もJSONで受け取るようにした
あとは、色々細かい機能追加しました(まだもっと色々やりたい)
- mainとtestで別々に実行できる
- もちろんsub project毎に実行出来る
- exclude
- errorやwarningをそのまま標準出力に出すか?
- errorやwarningを受け取って、そのJSONをファイルに書き出すか?
- 外部のwartや、ローカルに直接書いてdependsOnさせたものも正しく動くように
- errorが見つかったらTaskを失敗にするかどうか?
- 存在しないwartが指定されていたら、taskを失敗させるか、とりあえず存在したやつのみで継続するか?
最終的にまだ変わる可能性があるし、面倒なので、詳細な使い方あまり書きませんが、ひとまず以下のような設定書いて
project/plugins.sbt
addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.0.0-RC5")
build.sbt
scalaVersion := "3.1.2" Compile / wartremoverInspect / wartremoverWarnings ++= /* ここに検査するwart */ Compile / wartremoverInspect / wartremoverErrors ++= /* ここに検査するwart */
wartremoverInspect
というTask実行すると動くはずです。
ちなみに sbtのこれ により、明示的なproject定義がゼロだと動かないです。
バグ見つけたら教えてください。