Scalaで基本的には警告をエラーにしたいが、特定の警告を警告のままにしたい

というパターンがScala標準で不可能な気がするので、build.sbtで頑張るサンプルを作ってみたのですが、Scala標準で不可能ですよね???

どういうパターンか?をもう少し詳細に説明すると

  • 直せる警告は出来るだけはやく気がついて、はやく直した方がいい
  • とはいえ、簡単に直せない警告もある
  • あるいは、重要ではない警告(unused importとか?)は、最悪merge後に別に直す、とかにしたほうが、開発の効率はいい場合もある?
  • Scala標準では警告関連だと、以下のような色々な機能がある
  • しかしそれらを組み合わせても微妙にやりたいことが足りない気がしてきた
  • CIで -Werror にしてしまうのは、原理的に警告が増えたままmergeされなくなって、簡単に設定可能で便利だが、割と重大だと思うデメリットがある
    • @nowarn-Wconf で抑制するパターンが多くなり過ぎてしまうと厳しい。 @nowarn の追加自体を別途検知する、みたいなことは原理上不可能ではないが、イタチごっこというか、何のためにやってるのかよくわからなくなるというか、buildやコードが変に複雑になり過ぎる
    • @nowarn で抑制するより「簡単には直せないけど頑張れば直せるもの」に関して、「警告は警告のままにして出したまま」の方が「これ直さないといけないなぁ〜」というのが常に意識されやすいはず?
    • 理由を書きつつ @nowarn なら、まだマシな可能性があって、警告を避けるためだけに謎に変な書き方されたら最悪である
  • そういうデメリットがあって、警告のdiffを出すsbt plugin作ったりした https://xuwei-k.hatenablog.com/entry/2022/10/27/103253
  • -Wconf で柔軟に警告にするものとエラーにするものを選べるが、自分が知る限り表題の「基本的には警告をエラーにしたいが、特定の警告を警告のままにしたい」は不可能ですよね???
    • あくまで「警告のままにしたい」がポイントで、完全に抑制はしたくない
    • -Werror だと絶対に全ての警告がエラーに昇格してしまうはず?(そこから特定のものを抑制にすることは可能)
    • つまり -Wconf では「デフォルトで警告のもののうち、特定の選んだものをエラーに昇格することは可能」だがその逆をやりたい
    • 言い換えると、ホワイトリストブラックリストというか、ポリコレ的に最近はそういう言い方ではなくてdenylist、allowlistという言い方ですかね?

書いてみたサンプルの build.sbt が以下です。

import sbt.internal.inc.Analysis

scalaVersion := "2.13.16"

scalacOptions += "-deprecation"

Seq(Compile, Test).map { x =>
  (x / compile) := {
    val res = (x / compile).value
    val warnings = res.asInstanceOf[Analysis].infos.allInfos.values.flatMap(i =>
      i.getReportedProblems ++ i.getUnreportedProblems
    ).collect {
      case p if p.severity() == xsbti.Severity.Warn =>
        p
    }.filterNot{ p =>
      // 特定の警告だけ除外
      // 失敗させるかどうか?の判断から除外するだけで、
      // あくまで警告としてはそのまま全て表示される
      // https://github.com/sbt/sbt/blob/f284e809d41f27ceefa/internal/util-interface/src/main/java/xsbti/Problem.java#L17-L24
      p.message().contains("type Stream in package scala is deprecated")
    }.toList
    assert(warnings.isEmpty, s"警告があったので `${x.id}/compile` のtaskを失敗させます")
    res
  }
}

これは scala.Stream の警告だけを警告のままにして、その他の警告があったらcompileを失敗させます。

あくまで結果のエラーメッセージであって、compilerが持ってる情報よりは少ないというか加工済みなので、 -Wconf ほどには柔軟ではないですが、実用的にはそこまで困らないはず・・・?

( -Wconf はsite、origin、since、categoryなどの色々な概念で指定が可能)

messageでやってますが、positionなども取れるので、それを使ったfilterも可能です。

あくまでサンプルで、現状では特に実運用してないので、細かい部分が雑ですが。

場合によってはこれsbt pluginにするか・・・? 🤔