Scalafix

Scalafix

  • User guide
  • Developer guide
  • Browse sources
  • GitHub

›Usage

Usage

  • Installation
  • Configuration
  • Suppressing rules

Rules

  • Built-in rules
  • DisableSyntax
  • ExplicitResultTypes
  • LeakingImplicitClassVal
  • NoAutoTupling
  • NoValInForComprehension
  • ProcedureSyntax
  • RedundantSyntax
  • RemoveUnused
  • Using external rules
  • Community rules

Misc

  • Related projects
Edit

Installation

Requirements

macOS, Linux or Windows: Scalafix runs on macOS, Linux and Windows. Every pull request is tested on both Linux and Windows.

Java 8 or Java 11.

Scala 2.12 and 2.13

Scala 3.x: Scala 3 support is experimental and many built-in rules are not supported.

sbt

Start by installing the sbt 1.3+ plugin in project/plugins.sbt

// project/plugins.sbt
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.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.10.4"

Maven Central

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 semanticdb-scalac compiler plugin is required to run semantic
rules like RemoveUnused ...
[E2] The Scala compiler option "-Ywarn-unused" is required to use
RemoveUnused ...

The first error message means the SemanticDB compiler plugin is not enabled for this project. The second error says RemoveUnused requires

the Scala compiler option -Ywarn-unused-import (or -Wunused:imports in 2.13.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.17", // 2.13.10, or 3.x
+    semanticdbEnabled := true, // enable SemanticDB
+    semanticdbVersion := scalafixSemanticdb.revision // only required for Scala 2.x
   )
 )

 lazy val myproject = project.settings(
   scalacOptions += "-Ywarn-unused-import" // required by `RemoveUnused` rule
 )
 /*
  * 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.17", // 2.13.10, or 3.x
+  semanticdbEnabled := true, // enable SemanticDB
+  semanticdbVersion := scalafixSemanticdb.revision, // only required for Scala 2.x
+  scalacOptions += "-Ywarn-unused-import" // Scala 2.x only, required by `RemoveUnused`
 )

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 -Yrangepos adds 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
  -Xmx8G

You 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

NameTypeDescription
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.
scalafixCachingSettingKey[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.
scalafixConfigSettingKey[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.
scalafixDependenciesSettingKey[Seq[ModuleID]]Dependencies making custom rules available via their simple name. Must be set in ThisBuild. Defaults to Nil.
scalafixOnCompileSettingKey[Boolean]When true, Scalafix rule(s) declared in scalafixConfig are run on compilation, applying rewrites and failing on lint errors. Defaults to false.
scalafixResolversSettingKey[Seq[Repository]]Custom resolvers where scalafixDependencies are resolved from. Must be set in ThisBuild. Defaults to: Ivy2 local, Maven Central, Sonatype releases & Sonatype snapshots.
scalafixScalaBinaryVersionSettingKey[String]Scala binary version used for Scalafix execution. Must be set in ThisBuild. Defaults to 2.12. For advanced rules such as ExplicitResultTypes to work, it must match the binary version defined in the build for compiling sources. Note that scalafixDependencies artifacts must be published against that Scala version.

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:

  1. scalafixOnCompile := true is dangerous on CI as a rewrite might be applied before a call to scalafix[All] --check, causing this one to run on dirty sources and thus pass while it should not. Make sure that scalafixOnCompile is disabled on CI or, if that is impossible, that scalafix[All] --check is the first task executed, without any other concurrently.
  2. Some rules such as RemoveUnused can be counter-productive if applied too often/early, as the work-in-progress code that was just added might disappear after a simple test. To make such invocations less intrusive, you can change the rules and rules configuration used in that case by defining in .scalafix.conf custom values for them.
  3. 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.
  4. To keep the overhead minimal, scalafixCaching is automatically enabled when scalafixOnCompile is, which can cause unexpected behaviors if you run into false positive cache hits. scalafixCaching can explicitly be set to false in that case.
  5. Non-idempotent rewrite rules might get you in an infinite loop where sources never converge - not specific to scalafixOnCompile either, but rather confusing when triggered automatically.
  6. 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 +=
  "com.geirsson" %% "example-scalafix-rule" % "1.3.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:exclude since that will not work on Windows. The argument is compiled to a regular expression and gets matched against the java.io.File.getAbsolutePath representation of each file.

Exclude files from Scalafix (Scala 2.x only)

By default, the scalafix task processes all files in a project. If you use SemanticDB, 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. For example:

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. For example:

  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 scalafixEnable command must be re-executed after every reload and when sbt shell is exited.

Verify installation

To verify that the SemanticDB compiler plugin is enabled, check that the settings scalacOptions and allDependencies contain the values below.

> show Compile / scalacOptions
...
[info] * List(..., -Yrangepos, ...)
...
> show allDependencies
...
[info] List(..., org.scalameta:semanticdb-scalac:2.12.17:plugin->default(compile), ...)
...

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.

Next, install a scalafix binary with Coursier

cs install scalafix
./scalafix --version # Should say 0.10.4

Help

Scalafix 0.10.4+96-46b8dfe7-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.

  --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

  --scala-version ScalaVersion (default: "2.13.10")
    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.

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


Plugins for other build tools

Scalafix is supported in other build tools via externally maintained plugins:

  • 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.10.4")
+resolvers += Resolver.sonatypeRepo("snapshots")
+dependencyOverrides += "ch.epfl.scala" % "scalafix-interfaces" % "0.10.4+96-46b8dfe7-SNAPSHOT"

If using the command-line interface

cs launch ch.epfl.scala:scalafix-cli_2.12.17:0.10.4+96-46b8dfe7-SNAPSHOT -r sonatype:snapshots --main scalafix.cli.Cli -- --help
Configuration →
  • Requirements
  • sbt
    • Settings and tasks
    • Main and test sources
    • Integration tests
    • Multi-module builds
    • Enforce in CI
    • Cache in CI
    • Run Scalafix automatically on compile
    • Run custom rules
    • Exclude files from SemanticDB (Scala 2.x only)
    • Exclude files from Scalafix (Scala 2.x only)
    • Customize SemanticDB output directory
    • Disable Scalafix for specific project
    • Enable SemanticDB for current shell session
    • Verify installation
    • Example project
  • Command line
    • Help
  • Plugins for other build tools
  • SNAPSHOT
Scalafix
Docs
Get startedRulesExtend Scalafix
Community
Chat on DiscordDiscuss on Scala Users
More
GitHub
Copyright © 2023 Scala Center