Installation
Requirements
macOS, Linux and Windows: Scalafix runs on macOS, Linux and Windows. Every pull request is tested on both Linux and Windows.
Java 8. Scalafix supports only Java 8 at the moment. Running Scalafix on
Java 9+ results in error: unable to load symbol table
errors. See
#880 for updates on adding
support for Java 11.
Scala 2.11 and 2.12: Scalafix works only with the latest version of Scala 2.11 and Scala 2.12. See scalameta/scalameta#1695 for updates on adding support for Scala 2.13 once it's out.
Scalafix | Scala Compiler | Scalameta |
---|---|---|
0.9.0-RC1 | 2.11.12 / 2.12.6 | 4.0.0 |
0.5.10 | 2.11.12 / 2.12.4 | 2.1.7 |
sbt
Start by installing the sbt plugin in project/plugins.sbt
// project/plugins.sbt
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.0-RC1")
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
. To fix both problems, add the
following settings to build.sbt
// build.sbt
lazy val myproject = project.settings(
scalaVersion := "2.12.6", // or 2.11.12
+ addCompilerPlugin(scalafixSemanticdb), // enable SemanticDB
scalacOptions ++= List(
+ "-Yrangepos", // required by SemanticDB compiler plugin
+ "-Ywarn-unused-import" // required by `RemoveUnused` rule
)
)
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
Settings and tasks
Name | Type | Description |
---|---|---|
scalafix <args> | InputTaskKey[Unit] | Invoke scalafix command line interface directly. Use tab completion to explore supported arguments or consult --help |
scalafixConfig | SettingKey[Option[File]] | .scalafix.conf file to specify which scalafix rules should run. Defaults to .scalafix.conf in the root directory, if it exists. |
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/scalafix ; myproject/test:scalafix
Integration tests
By default, the scalafix
command is enabled for the Compile
and Test
configurations. To enable Scalafix for other configuration like
IntegrationTest
, add the following to your project settings
lazy val myproject = project
.configs(IntegrationTest)
.settings(
Defaults.itSettings,
+ inConfig(IntegrationTest)(scalafixConfigSettings(IntegrationTest))
// ...
)
Multi-module builds
The scalafix
task aggregates like the compile
and test
tasks. To run
Scalafix on all projects for both main and test sources you can execute
all scalafix test:scalafix
.
Optionally, add a command alias to your build to run Scalafix on your entire
project with the shorthand fix
// top of build.sbt
addCommandAlias("fix", "all compile:scalafix test:scalafix")
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.
Optionally, add a command alias to enforce Scalafix on your entire project with
the shorthand fixCheck
// top of build.sbt
addCommandAlias(
"fixCheck",
"; compile:scalafix --check ; test:scalafix --check"
)
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 in the directory $HOME/.coursier/cache
. 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 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
scalafixDependencies in ThisBuild +=
"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
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 thejava.io.File.getAbsolutePath
representation of each file.
Exclude files from Scalafix
By default, the scalafix
task processes all files in a project. If you use
SemanticDB, the scalafix
task also respects
-P:semanticdb:exclude
.
Use unmanagedSources.in(Compile, scalafix)
to optionally exclude files from
the scalafix
task.
unmanagedSources.in(Compile, scalafix) :=
unmanagedSources.in(Compile).value
.filterNot(file => file.getName == "Macros.scala")
Replace Compile
with Test
to customize which test sources should be
processed.
Customize SemanticDB output directory
By default, the SemanticDB compiler plugin emits *.semanticdb
files in the
classDirectory
.
Use -P:semanticdb:targetroot:path
to configure SemanticDB to emit
*.semanticdb
files in a custom location. For example:
scalacOptions += {
val targetroot = target.value / "semanticdb"
s"-P:semanticdb:targetroot:$targetroot"
}
To learn more about SemanticDB compiler options visit https://scalameta.org/docs/semanticdb/guide.html#scalac-compiler-plugin
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 ExplicitResultTypes
The scalafixEnable
command automatically runs
addCompilerPlugin(scalafixSemanticdb)
and scalacOptions += "-Yrangepos"
for
all eligible projects in the builds. The change in Scala compiler options means
the project needs to be re-built on the next compile
.
The
scalafixEnable
command must be re-executed after everyreload
and when sbt shell is exited.
Optionally enable SemanticDB
It's possible to optionally enable the SemanticDB compiler plugin by updating build.sbt like this:
// build.sbt
- addCompilerPlugin(scalafixSemanticdb)
- scalacOptions += "-Yrangepos"
+ def shouldEnableSemanticdb: Boolean = ??? // fill this part
+ libraryDependencies ++= {
+ if (shouldEnableSemanticdb) List(compilerPlugin(scalafixSemanticdb))
+ else List()
+ }
+ scalacOptions ++= {
+ if (shouldEnableSemanticdb) List("-Yrangepos")
+ else List()
+ }
Verify installation
To verify that the SemanticDB compiler plugin is enabled, check that the
settings scalacOptions
and libraryDependencies
contain the values below.
> show scalacOptions
[info] * -Yrangepos
> show libraryDependencies
[info] * org.scalameta:semanticdb-scalac:2.12.6:plugin->default(compile)
Example project
For a minimal example project using sbt-scalafix, see the scalacenter/scalafix-sbt-example repository.
git clone https://github.com/scalacenter/sbt-scalafix-example
cd scalafix-sbt-example
sbt "scalafix RemoveUnused"
git diff // should produce a diff
Command line
First, install the Coursier command-line interface.
Next, bootstrap a scalafix
binary with Coursier
coursier bootstrap ch.epfl.scala:scalafix-cli_2.12.6:0.9.0-RC1 -f --main scalafix.cli.Cli -o scalafix
./scalafix --version # Should say 0.9.0-RC1
Help
Scalafix 0.9.0-RC1+15-c9b6cb3b-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
--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.
--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 String (default: "2.12.6")
The Scala compiler version that was used to compile this
project.
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.
--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: "/Users/ollie/dev/scalafix")
The current working directory
SNAPSHOT
Our CI publishes a snapshot release to Sonatype on every merge into master. Each snapshot release has a unique version number, jars don't get overwritten. To find the latest snapshot version number, go to https://oss.sonatype.org/content/repositories/snapshots/ch/epfl/scala/scalafix-core_2.12/ and select the largest version number (the one with the newest "Last Modified" timestamp). Once you have found the version number, adapt the version number in the instructions below
If using the sbt plugin
// project/plugins.sbt
resolvers += Resolver.sonatypeRepo("snapshots")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.0-RC1+15-c9b6cb3b-SNAPSHOT-SNAPSHOT")
If using the command-line interface
coursier launch ch.epfl.scala:scalafix-cli_2.12.6:0.9.0-RC1+15-c9b6cb3b-SNAPSHOT-SNAPSHOT -r sonatype:snapshots --main scalafix.cli.Cli -- --help