scalafix
scalafix copied to clipboard
Unclear errors when running semantic rules with a minimal set of scalafix-cli flags
When using scala-cli, from the root of my sbt project, as mentioned in the documentation:
cs launch ch.epfl.scala:scalafix-cli_2.12.19:0.12.0+5-49b95fc4-SNAPSHOT -r sonatype:snapshots --main scalafix.cli.Cli -- --check
I get the following error:
error: 2 errors
[E0] A Scala compiler option is required to use RemoveUnused. To fix this problem,
update your build to add -Ywarn-unused (with 2.12), -Wunused (with 2.13), or
-Wunused:all (with 3.4+)
[E1] A Scala compiler option is required to use OrganizeImports with "OrganizeImports.removeUnused" set to true. To fix this problem, update your build to add `-Ywarn-unused` (2.12), `-Wunused:imports` (2.13), or `-Wunused:import` (3.4+).
I am using Scala 3.4.0. But adding the mentioned Scala compiler options does not seem to do the trick either. However, when using the sbt plugin for scalafix, sbt "scalafix --check" (0.12.0), I have no issues at all.
I also tried to use the scalafix-cli retrieved with cs install scalafix but I get the exact same error as above.
Some semantic rules such as RemoveUnused and OrganizeImports double-check that you used the right compiler options, but the only way for Scalafix to know about them is to pass them through --scalac-options flag when using scalafix-cli. Your CLI invocation is also missing --classpath (required for semantic rules to find semanticdb information), as well as --scala-version since you will likely run into failures when Scalafix will try to parse your Scala 3 sources with the default Scala 2.13 dialect.
As you can already tell, it can be tricky to get all the scalafix-cli options right, and compilation must be triggered beforehand. All this complexity is abstracted by sbt-scalafix, so I recommend using it whenever possible, especially for semantic rules. If you don't use sbt, support for other build tools is available.
I am keeping this issue open, since documentation could be improved, and the error message more actionable (--scalac-options, even empty, could be made compulsory when executing semantic rules). PRs are welcome!
Yeah I definitely see why you would recommend sbt-scalafix as this is not completely straightforward for someone new to the scalafix-cli. I tried to do this:
scalafix --rules=RemoveUnused --scalac-options=-Wunused:all --scala-version=3.4.0
which gives the repeated error:
error: SemanticDB not found: src/main/scala/someFile_1.scala
error: SemanticDB not found: src/main/scala/someFile_2.scala
. . .
error: SemanticDB not found: src/main/scala/someFile_n.scala
I am not entirely sure how to set the --classpath to find the semanticdb information. It would be very helpful if you could provide a working example of using the scalafix-cli correctly.
It would be very helpful if you could provide a working example of using the scalafix-cli correctly.
The thing is that it really depends on how your build is setup: where class files are generated, semanticdb options, etc. That's why it makes sense to use the integration for your build tool. Maybe you can tell more about your use-case?
Anyway, here is how it should look like with the simplest sbt build I can come up with:
brice@t14:/tmp/test$ cat build.sbt
scalaVersion := "3.4.0"
semanticdbEnabled := true
scalacOptions += "-Wunused:all"
brice@t14:/tmp/test$ cat src/main/scala/Foo.scala
import java.util._
object Foo
brice@t14:/tmp/test$ sbt compile
[info] welcome to sbt 1.9.8 (Eclipse Adoptium Java 17.0.9)
[info] loading global plugins from /home/brice/.sbt/1.0/plugins
[info] loading project definition from /tmp/test/project
[info] loading settings for project test from build.sbt ...
[info] set current project to test (in build file:/tmp/test/)
[info] Executing in batch mode. For better performance use sbt's shell
[info] compiling 1 Scala source to /tmp/test/target/scala-3.4.0/classes ...
[warn] -- Warning: /tmp/test/src/main/scala/Foo.scala:1:17 ----------------------------
[warn] 1 |import java.util._
[warn] | ^
[warn] | unused import
[warn] one warning found
[success] Total time: 3 s, completed Mar 11, 2024, 10:35:20 PM
brice@t14:/tmp/test$ scalafix --rules=RemoveUnused --scalac-options=-Wunused:all --scala-version=3.4.0 --classpath target/scala-3.4.0/meta src/main/scala/Foo.scala --check
--- /tmp/test/src/main/scala/Foo.scala
+++ <expected fix>
@@ -1,3 +1,3 @@
-import java.util._
+
object Foo
Thanks for providing a minimal example @bjaglin.
The potential use-case of the scalafix-cli that I am looking into is whether it can run as part of pre-commit locally in a reasonable amount of time (less than 10 seconds). I used to have sbt-scalafix as part of my pre-commit hook locally, however it simply took too long to run so I had to remove it. I actually had a similar issue with sbt-scalafmt but when using a slim version scalafmt slim of scalafmt it works really fast (1-2 seconds to format all .scala files). And I can easily run it like this: ./scalafmt -c .scalafmt.conf. So basically I was looking into whether the scala-cli could be used in a similar way as I use the slim scalafmt tool.
The potential use-case of the scalafix-cli that I am looking into is whether it can run as part of pre-commit locally in a reasonable amount of time (less than 10 seconds).
I see. You should definitely be able to get scalafix to run in ~10s, as long as your code is compiled ahead of time with semanticdb information, and you capture the build structure as CLI args. Also, you won't benefit from incremental features from sbt-scalafix though, so runtime will be directly proportional to the number of source files you have.
I used to have sbt-scalafix as part of my pre-commit hook locally, however it simply took too long to run so I had to remove it.
Did you consider using sbtn for your pre-commit hook? If you have a sbt server running locally, the startup time should be minimal, and you would benefit from sbt-scalafix incrementality, so the run could take only a couple of seconds.