9
votes

WartRemover is a scalac plugin. Typically it is configured via an sbt plugin.

I'd like to be able to run WartRemover on my sbt project as a separate configuration or task without affecting the usual run of compile.

After adding Wartremover to my plugins.sbt I tried quite a few variations on the following.

lazy val Lint = config("lint").extend(Compile)

project("foo").
  configs(Lint)
  settings(inConfig(Lint)(Defaults.compileSettings): _*).
  settings(inConfig(Linting)(wartremover.wartremoverSettings):_*).
  settings(inConfig(Linting)(wartremover.wartremoverErrors := wartremover.Warts.all))

Afterward scalacOptions contained roughly what I expected inside my new lint configuration and in the compile configuration. However, when I ran lint:compile and compile with sbt in debug mode so I could see the command line arguments to scalac, either both or neither commands would result in pass the -P:wartremover:... switches. That was surprising because only lint:scalacOptions showed the -P:wartremover:... switches.

How can I create a separate sbt Configuration or Task to compile with WartRemover without affecting compile:compile?

1
Do you mean a custom command? scala-sbt.org/0.12.2/docs/Extending/…Gangstead
@gangstead, I'm not opposed to a custom command. I simply don't understand well enough how to make it execute 'compile' with the necessary configuration.Leif Wickland

1 Answers

11
votes

I think you came really close. Here are some of the details:

  1. sbt downloads library dependencies and compiler plugins all using Compile configuration's update task, which uses libraryDependencies setting. addCompilerPlugin is a shorthand for libraryDependencies with CompilerPlugin configuration.
  2. Compiler plugin requires scalaOptions on the configuration that you're interested in.
  3. You need to grab sources from Compile to use them in Lint.

If you see the implementation of wartremoverSettings it's doing both addCompilerPlugin and scalacOptions. You have two options to disable wartremover on Compile:

  1. Use auto plugin (requires sbt 0.13.5+) to inject wartremoverSettings, then manually remove wartremover compiler plugin from Compile.
  2. Disable auto plugin, then manually add wart remover into libraryDependencies.

Here's the first option.

project/build.properties

sbt.version=0.13.7

project/wart.sbt

addSbtPlugin("org.brianmckenna" % "sbt-wartremover" % "0.11")

build.sbt

lazy val Lint = config("lint") extend Compile

lazy val foo = project.
  configs(Lint).
  settings(inConfig(Lint) {
    Defaults.compileSettings ++ wartremover.wartremoverSettings ++
    Seq(
      sources in Lint := {
        val old = (sources in Lint).value
        old ++ (sources in Compile).value 
      },
      wartremover.wartremoverErrors := wartremover.Warts.all
    ) }: _*).
  settings(
    scalacOptions in Compile := (scalacOptions in Compile).value filterNot { _ contains "wartremover" }
  )

foo/src/main/scala/Foo.scala

package foo

object Foo extends App {
  // Won't compile: Inferred type containing Any
  val any = List(1, true, "three")
  println("hi")
}

sample output

foo> clean
[success] Total time: 0 s, completed Dec 23, 2014 9:43:30 PM
foo> compile
[info] Updating {file:/quick-test/wart/}foo...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Compiling 1 Scala source to /quick-test/wart/foo/target/scala-2.10/classes...
[success] Total time: 1 s, completed Dec 23, 2014 9:43:33 PM
foo> run
[info] Running foo.Foo 
hi
[success] Total time: 0 s, completed Dec 23, 2014 9:43:37 PM
foo> lint:compile
[info] Compiling 1 Scala source to /quick-test/wart/foo/target/scala-2.10/lint-classes...
[error] /quick-test/wart/foo/src/main/scala/Foo.scala:5: Inferred type containing Any
[error]   val any = List(1, true, "three")
[error]       ^
[error] /quick-test/wart/foo/src/main/scala/Foo.scala:5: Inferred type containing Any
[error]   val any = List(1, true, "three")
[error]             ^