Installation
Support
Scalafix is tested to work with:
- macOS, Linux or Windows
- Java LTS (8, 11, 17, 21 or 25)
- Scala 2.12.20, 2.13.17, 3.3.7 LTS or 3.7.4
Note that other setups may work, but could result in unexpected behavior.
sbt
Start by installing the sbt 1.4+ plugin in project/plugins.sbt:
// project/plugins.sbt addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.14.4") Scalafix is no longer published for Scala 2.11. You can run the final version of Scalafix supporting 2.11, but all features documented below might not be supported:
// project/plugins.sbt addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.4") // final Scala 2.11 version
sbt-scalafix is no longer published for sbt 0.13.x. You should be able to run the latest version of Scalafix with the final sbt-scalafix version published for sbt 0.13.x, but all features documented below might not be supported:
// project/plugins.sbt addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.29") // final sbt 0.13.x version dependencyOverrides += "ch.epfl.scala" % "scalafix-interfaces" % "0.14.4"
From the sbt shell, let's run the rule ProcedureSyntax:
> myproject / scalafix ProcedureSyntax It's normal that the first invocation of scalafix takes a while to download Scalafix artifacts from Maven Central.
If all went well and your project uses the deprecated "procedure syntax", you should have a diff in your sources like this:
- def myProcedure { + def myProcedure: Unit = { Next, if we run another rule like RemoveUnused then we get an error:
> myproject / scalafix RemoveUnused [error] (Compile / scalafix) scalafix.sbt.InvalidArgument: 2 errors [E1] The scalac compiler should produce semanticdb files to run semantic rules like RemoveUnused ... [E2] A Scala compiler option is required to use RemoveUnused. To fix this problem, update your build to add -Ywarn-unused-import (with 2.12) ... The first error message means the SemanticDB compiler output is not enabled for this project. The second error says that RemoveUnused requires the Scala compiler option -Ywarn-unused-import (or -Wunused:imports in 2.13.x or 3.x). To fix both problems, add the following settings to build.sbt:
/* * build.sbt * SemanticDB is enabled for all sub-projects via ThisBuild scope. * https://www.scala-sbt.org/1.x/docs/sbt-1.3-Release-Notes.html#SemanticDB+support */ inThisBuild( List( scalaVersion := "2.12.20", // 2.13.17, 3.3.7 or 3.7.4 + semanticdbEnabled := true, // enable SemanticDB + semanticdbVersion := scalafixSemanticdb.revision // only required for Scala 2.x ) ) lazy val myproject = project.settings( + scalacOptions += { + if (scalaVersion.value.startsWith("2.12")) + "-Ywarn-unused-import" + else + "-Wunused:imports" + } ) /* * build.sbt * SemanticDB is enabled only for a sub-project. * https://www.scala-sbt.org/1.x/docs/sbt-1.3-Release-Notes.html#SemanticDB+support */ lazy val myproject = project.settings( scalaVersion := "2.12.20", // 2.13.17, 3.3.7 or 3.7.4 + semanticdbEnabled := true, // enable SemanticDB + semanticdbVersion := scalafixSemanticdb.revision, // only required for Scala 2.x + scalacOptions += { + if (scalaVersion.value.startsWith("2.12")) + "-Ywarn-unused-import" + else + "-Wunused:imports" + } ) For project/*.scala files, add import scalafix.sbt.ScalafixPlugin.autoImport._ to the top of the file to resolve scalafixSemanticdb.
We run RemoveUnused again and the error is now gone:
> myproject / scalafix RemoveUnused [info] Compiling 15 Scala sources to ... [info] Running scalafix on 15 Scala sources If your project has unused imports, you should see a diff like this:
- import scala.util.{ Success, Failure } + import scala.util.Success See example project for a repository that demonstrates ProcedureSyntax and RemoveUnused.
Great! You are all set to use Scalafix with sbt :)
Beware that the SemanticDB compiler plugin in combination with
-Yrangeposadds overhead to compilation time. The exact compilation overhead depends on the codebase being compiled and compiler options used. It's recommended to provide generous JVM memory and stack settings in the file.jvmopts:-Xss8m -Xms1G -Xmx8GYou can also use project scoped settings if you don't want to mix SemanticDB settings with your sub-projects which don't use it, rather than using ThisBuild scoped settings.
Settings and tasks
| Name | Type | Description |
|---|---|---|
scalafix <args> | InputKey[Unit] | Invoke scalafix command line interface directly. Use tab completion to explore supported arguments or consult --help. |
scalafixAll <args> | InputKey[Unit] | Invoke scalafix across all configurations where scalafix is enabled. |
scalafixCaching | SettingKey[Boolean] | Controls whether 2 successive invocations of the scalafix InputTask with the same arguments & configuration should be incremental. Defaults to true. When enabled, use the --no-cache argument to force an exhaustive run. |
scalafixConfig | SettingKey[Option[File]] | .scalafix.conf file to specify which scalafix rules should run, together with their potential options. Defaults to .scalafix.conf in the root directory, if it exists. |
scalafixDependencies | SettingKey[Seq[ModuleID]] | Dependencies making custom rules available via their simple name. Can be set in ThisBuild or at project-level. Defaults to Nil. |
scalafixOnCompile | SettingKey[Boolean] | When true, Scalafix rule(s) declared in scalafixConfig are run on compilation, applying rewrites and failing on lint errors. Defaults to false. |
scalafixResolvers | SettingKey[Seq[Repository]] | Custom resolvers where scalafixDependencies are resolved from, in addition to the user-defined sbt ThisBuild / resolvers. Must be set in ThisBuild. Defaults to: Ivy2 local, Maven Central, Sonatype releases & Sonatype snapshots. |
Main and test sources
The task myproject / scalafix runs for main sources in the project myproject. To run Scalafix on test sources, execute myproject / Test / scalafix instead. To run on both main and test sources, execute myproject / scalafixAll.
Integration tests
By default, the scalafix command is enabled for the Compile and Test configurations, and scalafixAll will run on both of them. To enable Scalafix for other configuration like IntegrationTest, add the following to your project settings:
lazy val myproject = project .configs(IntegrationTest) .settings( Defaults.itSettings, + scalafixConfigSettings(IntegrationTest) // ... ) Multi-module builds
Both the scalafix & the scalafixAll task aggregate like the compile and test tasks. To run Scalafix on all projects for both main and test sources you can execute scalafixAll.
Enforce in CI
To automatically enforce that Scalafix has been run on all sources, use scalafix --check instead of scalafix. This task fails the build if running scalafix would produce a diff or a linter error message is reported.
Use scalafixAll --check to enforce Scalafix on your entire project.
Cache in CI
To avoid binary compatibility conflicts with the sbt classpath (example issue), the Scalafix plugin uses Coursier to fetch Scalafix artifacts from Maven Central. These artifacts are by default cached inside the home directory. To avoid redundant downloads on every pull request, it's recommended to configure your CI enviroment to cache this directory. The location can be customized with the environment variable COURSIER_CACHE:
export COURSIER_CACHE=$HOME/.custom-cache Run Scalafix automatically on compile
If you set scalafixOnCompile to true, the rules declared in .scalafix.conf (or in the file located by scalafixConfig) will run automatically each time compile is invoked either explicitly or implicitly (for example when executing test or publishLocal). Lint errors will fail that invocation, while rewrites will be applied.
Although this looks like an easy way to use Scalafix as a linter, use this feature with care as it has several shortcomings, for example:
scalafixOnCompile := trueis dangerous on CI as a rewrite might be applied before a call toscalafix[All] --check, causing this one to run on dirty sources and thus pass while it should not. Make sure thatscalafixOnCompileis disabled on CI or, if that is impossible, thatscalafix[All] --checkis the first task executed, without any other at the same time.- Some rules such as
RemoveUnusedcan be counter-productive if applied too often/early, as the work-in-progress code that was just added might disappear after a simpletest. To make such invocations less intrusive, you can change the rules and rules configuration used in that case by defining in.scalafix.confcustom values for them. - If you run many semantic rules by default, the last one(s) to run might see stale information and fail the invocation, which needs to be re-run manually. This is not specific to
scalafixOnCompile, but the problem becomes much more visible with it. - Non-idempotent rewrite rules might get you in an infinite loop where sources never converge - not specific to
scalafixOnCompile, but rather confusing when triggered automatically. - Bugs in rule implementations can prevent you from getting a successful
compile, blocking testing or publishing for example
Run custom rules
It's possible to run custom Scalafix rules that have been published to Maven Central. To install a custom rule, add it to scalafixDependencies (scalafix.sbt.ScalafixPlugin.autoImport.scalafixDependencies):
// at the top of build.sbt ThisBuild / scalafixDependencies += "ch.epfl.scala" %% "example-scalafix-rule" % "4.0.0" Start sbt and type scalafix <TAB>, once the example-scalafix-rule dependency has been downloaded the rules SemanticRule and SyntacticRule should appear as tab completion suggestions.
$ sbt > scalafix Syn<TAB> > scalafix SyntacticRule If all went well, you should see a diff adding the comment // v1 SyntacticRule! to all Scala source files.
+// v1 SyntacticRule! Exclude files from SemanticDB (Scala 2.x only)
By default, the SemanticDB compiler plugin will process all files in a project.
Use -P:semanticdb:exclude:<regex> to exclude files from the SemanticDB compiler plugin:
scalacOptions += "-P:semanticdb:exclude:Macros.scala" Separate multiple patterns with pipe | to exclude multiple files:
scalacOptions += "-P:semanticdb:exclude:Macros.scala|Schema.scala" To learn more about SemanticDB compiler options visit https://scalameta.org/docs/semanticdb/guide.html#scalac-compiler-plugin
Avoid using slashes like
/in-P:semanticdb:excludesince that will not work on Windows. The argument is compiled to a regular expression and gets matched against thejava.io.File.getAbsolutePathrepresentation of each file.
Exclude files from Scalafix
By default, the scalafix task processes all files in a project. If you use Scala 2.x, the scalafix task also respects -P:semanticdb:exclude.
Use Compile / scalafix / unmanagedSources to optionally exclude files from the scalafix task:
Compile / scalafix / unmanagedSources := (Compile / unmanagedSources).value .filterNot(file => file.getName == "Macros.scala") Replace Compile with Test to customize which test sources should be processed.
Customize SemanticDB output directory
The *.semanticdb files are available in the directory referenced by the semanticdbTargetRoot key, which defaults to target/scala-x/meta.
You can override this default to emit *.semanticdb files in a custom location:
semanticdbTargetRoot := target.value / "semanticdb" Alternatively, you can set the semanticdbIncludeInJar key to request the compiler to emit these files into the classDirectory so that they are available in packaged JARs:
semanticdbIncludeInJar := true Disable Scalafix for specific project
Use .disablePlugins(ScalafixPlugin) to disable Scalafix for a particular project:
lazy val myproject = project .settings(...) + .disablePlugins(ScalafixPlugin) When using Scala.js or Scala Native, use .jsConfigure or .nativeConfigure to disable Scalafix for only the Scala.js or Scala Native project:
lazy val myproject = crossProject(JVMPlatform, JSPlatform) .settings(...) + .jsConfigure(_.disablePlugins(ScalafixPlugin)) Enable SemanticDB for current shell session
Instead of permanently enabling SemanticDB in build.sbt, use the scalafixEnable command to enable SemanticDB the current active sbt shell session:
> scalafixEnable ... > scalafix RemoveUnused The scalafixEnable command automatically enables semanticdb output and adds scalacOptions += "-Yrangepos" for all eligible projects in the builds. The change in Scala compiler options means the project may need to be re-built on the next compile.
The
scalafixEnablecommand must be re-executed after everyreloadand when sbt shell is exited.
Example project
For a minimal example project using sbt-scalafix, see the scalacenter/sbt-scalafix-example repository.
git clone https://github.com/scalacenter/sbt-scalafix-example cd sbt-scalafix-example sbt "scalafix RemoveUnused" git diff // should produce a diff Command line
First, install the Coursier command-line interface.
Then, install or launch a Scalafix runner built with the latest version of Scala (3.7.4):
cs install scalafix scalafix --version # Should say 0.14.4 cs install scalafix:0.14.0 scalafix --version # Should say 0.14.0 cs launch scalafix:0.13.0 -- --version # Should say 0.13.0 If you plan to use advanced semantic rules like
ExplicitResultTypes, you must use the version of Scalafix built with a Scala version matching your target source files (major.minor).If your target files are not built with the latest minor version of Scala, use one of the following commands to create a custom runner:
cs bootstrap ch.epfl.scala:scalafix-cli_2.12.20:0.14.4 --main scalafix.cli.Cli -o scalafix_2.12 cs bootstrap ch.epfl.scala:scalafix-cli_2.13.17:0.14.4 --main scalafix.cli.Cli -o scalafix_2.13 cs bootstrap ch.epfl.scala:scalafix-cli_3.3.7:0.14.4 --main scalafix.cli.Cli -o scalafix_3.3-ltsAlternatively, you can run a one-shot command:
cs launch --scala X.Y scalafix -- --version
Help
Scalafix 0.14.4+34-e0a5218a-SNAPSHOT Usage: scalafix [options] [<path> ...] Scalafix is a refactoring and linting tool. Scalafix supports both syntactic and semantic linter and rewrite rules. Syntactic rules can run on source code without compilation. Semantic rules can run on source code that has been compiled with the SemanticDB compiler plugin. Common options: --rules | -r [String ...] (default: []) Scalafix rules to run, for example ExplicitResultTypes. The syntax for rules is documented in https://scalacenter.github.io/scalafix/docs/users/configuration#rules --files | -f [<path> ...] (default: []) Files or directories (recursively visited) to fix. --config <path> (default: null) File path to a .scalafix.conf configuration file. Defaults to .scalafix.conf in the current working directory, if any. --check Check that all files have been fixed with scalafix, exiting with non-zero code on violations. Won't write to files. --stdout Print fixed output to stdout instead of writing in-place. --diff If set, only apply scalafix to added and edited files in git diff against the master branch. --diff-base String (default: null) If set, only apply scalafix to added and edited files in git diff against a provided branch, commit or tag. --scala-version ScalaVersion (default: "2.13.17") The major or binary Scala version that the provided files are targeting, or the full version that was used to compile them when a classpath is provided. --syntactic Run only syntactic rules, ignore semantic rules even if they are explicitly configured in .scalafix.conf or via --rules --triggered Overlay the default rules & rule settings in .scalafix.conf with the `triggered` section --verbose Print out additional diagnostics while running scalafix. --help | -h Print out this help message and exit --version | -v Print out version number and exit Semantic options: --classpath Classpath (default: "<classpath>") Full classpath of the files to fix, required for semantic rules. The source files that should be fixed must be compiled with semanticdb-scalac. Dependencies are required by rules like ExplicitResultTypes, but the dependencies do not need to be compiled with semanticdb-scalac. --sourceroot <path> (default: null) Absolute path passed to semanticdb with -P:semanticdb:sourceroot:<path>. Relative filenames persisted in the Semantic DB are absolutized by the sourceroot. Defaults to current working directory if not provided. --semanticdb-targetroots [<path> ...] (default: []) Absolute paths passed to semanticdb with -P:semanticdb:targetroot:<path>. Used to locate semanticdb files. By default, Scalafix will try to locate semanticdb files in the classpath --auto-classpath If set, automatically infer the --classpath flag by scanning for directories with META-INF/semanticdb --auto-classpath-roots [<path> ...] (default: []) Additional directories to scan for --auto-classpath --scalac-options [String ...] (default: []) The scala compiler options used to compile this --classpath, for example -Ywarn-unused-import Tab completions: --bash Print out bash tab completions. To install: ``` # macOS, requires "brew install bash-completion" scalafix --bash > /usr/local/etc/bash_completion.d/scalafix # Linux scalafix --bash > /etc/bash_completion.d/scalafix ``` --zsh Print out zsh tab completions. To install: ``` scalafix --zsh > /usr/local/share/zsh/site-functions/_scalafix unfunction _scalafix autoload -U _scalafix ``` Less common options: --exclude [<glob> ...] (default: []) Unix-style glob for files to exclude from fixing. The glob syntax is defined by `nio.FileSystem.getPathMatcher`. --tool-classpath URLClassLoader (default: "<classloader>") Additional classpath for compiling and classloading custom rules, as a set of filesystem paths, separated by ':' on Unix or ';' on Windows. --charset Charset (default: "UTF-8") The encoding to use for reading/writing files --no-sys-exit If set, throw exception in the end instead of System.exit --no-stale-semanticdb Don't error on stale semanticdb files. --settings ScalafixConfig (default: {}) Custom settings to override .scalafix.conf --out-from String (default: null) Write fixed output to custom location instead of in-place. Regex is passed as first argument to file.replaceAll(--out-from, --out-to), requires --out-to. --out-to String (default: null) Companion of --out-from, string that is passed as second argument to fileToFix.replaceAll(--out-from, --out-to) --auto-suppress-linter-errors Insert /* scalafix:ok */ suppressions instead of reporting linter errors. --cwd <path> (default: "/home/runner/work/scalafix/scalafix") The current working directory Support in other build tools
Scalafix is supported in other build tools via externally maintained plugins:
- scala-cli: experimental, built-in support
- Mill: mill-scalafix
- Gradle: gradle-scalafix
- Maven: scalafix-maven-plugin
- Mega-Linter (only built-in syntactic rules are supported)
SNAPSHOT
Our CI publishes a snapshot release to Sonatype on every merge into main. Each snapshot release has a unique version number, jars don't get overwritten.
If using the sbt plugin:
// project/plugins.sbt addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.14.4") +resolvers += Resolver.sonatypeCentralSnapshots +dependencyOverrides += "ch.epfl.scala" % "scalafix-interfaces" % "0.14.4+34-e0a5218a-SNAPSHOT" If using the command-line interface:
cs launch ch.epfl.scala:scalafix-cli_2.13.17:0.14.4+34-e0a5218a-SNAPSHOT -r https://central.sonatype.com/repository/maven-snapshots --main scalafix.cli.Cli -- --help 