Movatterモバイル変換


[0]ホーム

URL:


Scalafix

Scalafix

Edit

Installation

Support

Scalafix is tested to work with:

  • macOS, Linux or Windows
  • Java LTS (8, 11, 17, 21 or 25)
  • Scala 2.12.21, 2.13.18, 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 inproject/plugins.sbt:

// project/plugins.sbtaddSbtPlugin("ch.epfl.scala" %"sbt-scalafix" %"0.14.5")

Scalafix is no longer published for Scala 2.11. You can run the final versionof Scalafix supporting 2.11, but all features documented below might not besupported:

// project/plugins.sbtaddSbtPlugin("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 runthe latest version of Scalafix with the final sbt-scalafix version publishedfor sbt 0.13.x, but all features documented below might not be supported:

// project/plugins.sbtaddSbtPlugin("ch.epfl.scala" %"sbt-scalafix" %"0.9.29")// final sbt 0.13.x versiondependencyOverrides +="ch.epfl.scala" %"scalafix-interfaces" %"0.14.5"

Maven Central

From the sbt shell, let's run the ruleProcedureSyntax:

> myproject / scalafix ProcedureSyntax

It's normal that the first invocation ofscalafix takes a while to downloadScalafix artifacts from Maven Central.

If all went well and your project uses the deprecated "procedure syntax", youshould have a diff in your sources like this:

-  def myProcedure {+  def myProcedure: Unit = {

Next, if we run another rule likeRemoveUnused then we get an error:

> myproject / scalafix RemoveUnused[error] (Compile / scalafix) scalafix.sbt.InvalidArgument: 2 errors[E1] The scalac compiler should produce semanticdb filestorun semanticrules like RemoveUnused...[E2] A Scala compiler option is requiredto use RemoveUnused.To fix thisproblem, update your buildtoadd -Ywarn-unused-import (with 2.12)...

The first error message means theSemanticDB compiler outputis not enabled for this project. The second error says thatRemoveUnusedrequires the Scala compiler option-Ywarn-unused-import (or-Wunused:importsin 2.13.x or 3.x). To fix both problems, add the following settings tobuild.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.21", // 2.13.18, 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.21", // 2.13.18, 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"+  } )

Forproject/*.scala files, addimport scalafix.sbt.ScalafixPlugin.autoImport._ to the top of the file toresolvescalafixSemanticdb.

We runRemoveUnused again and the error is now gone:

> myproject / scalafix RemoveUnused[info] Compiling 15 Scala sourcesto...[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

Seeexample project for a repository that demonstratesProcedureSyntax andRemoveUnused.

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 onthe codebase being compiled and compiler options used. It's recommended toprovide 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 mixSemanticDB 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]Invokescalafix across all configurations where scalafix isenabled.
scalafixCachingSettingKey[Boolean]Controls whether 2 successive invocations of thescalafixInputTask with the same arguments & configuration should be incremental. Defaults totrue. 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 makingcustom rules available via their simple name. Can be set inThisBuild or at project-level. Defaults toNil.
scalafixOnCompileSettingKey[Boolean]Whentrue, Scalafix rule(s) declared inscalafixConfig are run on compilation, applying rewrites and failing on lint errors. Defaults tofalse.
scalafixResolversSettingKey[Seq[Repository]]Custom resolvers wherescalafixDependencies are resolved from, in addition to the user-defined sbtThisBuild / resolvers. Must be set inThisBuild. Defaults to: Ivy2 local, Maven Central, Sonatype releases & Sonatype snapshots.

Main and test sources

The taskmyproject / scalafix runs formain sources in the projectmyproject. To run Scalafix ontest sources, executemyproject / Test / scalafix instead. To run on both main and test sources, executemyproject / scalafixAll.

Integration tests

By default, thescalafix command is enabled for theCompile andTestconfigurations, andscalafixAll will run on both of them. To enableScalafix for other configuration likeIntegrationTest, add the followingto your project settings:

 lazy val myproject = project   .configs(IntegrationTest)   .settings(     Defaults.itSettings,+    scalafixConfigSettings(IntegrationTest)     // ...   )

Multi-module builds

Both thescalafix & thescalafixAll task aggregate like thecompileandtest tasks. To run Scalafix on all projects for both main and testsources you can executescalafixAll.

Enforce in CI

To automatically enforce that Scalafix has been run on all sources, usescalafix --check instead ofscalafix. This task fails the build if runningscalafix would produce a diff or a linter error message is reported.

UsescalafixAll --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 usesCoursier tofetch Scalafix artifacts from Maven Central. These artifacts are by defaultcachedinside the home directory.To avoid redundant downloads on every pull request, it's recommended to configureyour CI enviroment to cache this directory. The location can be customized withthe environment variableCOURSIER_CACHE:

export COURSIER_CACHE=$HOME/.custom-cache

Run Scalafix automatically on compile

If you setscalafixOnCompile totrue, the rules declared in.scalafix.conf(or in the file located byscalafixConfig) will run automatically each timecompile is invoked either explicitly or implicitly (for example whenexecutingtest orpublishLocal). 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 thisfeature with care as it has several shortcomings, for example:

  1. scalafixOnCompile := true is dangerous on CI as a rewrite might be appliedbefore a call toscalafix[All] --check, causing this one to run on dirtysources 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.
  2. Some rules such asRemoveUnused can be counter-productive if applied toooften/early, as the work-in-progress code that was just added might disappearafter a simpletest.To make such invocations less intrusive, you can change the rules and rulesconfiguration used in that case by defining in.scalafix.confcustom values for them.
  3. If you run many semantic rules by default, the last one(s) to run might seestale information and fail the invocation, which needs to be re-run manually.This isnot specific toscalafixOnCompile,but the problem becomes much more visible with it.
  4. Non-idempotent rewrite rules might get you in an infinite loop where sourcesnever converge - not specific toscalafixOnCompile, but rather confusingwhen triggered automatically.
  5. Bugs in rule implementations can prevent you from getting a successfulcompile, blocking testing or publishing for example

Run custom rules

It's possible to run custom Scalafix rules that have been published to MavenCentral. To install a custom rule, add it toscalafixDependencies(scalafix.sbt.ScalafixPlugin.autoImport.scalafixDependencies):

// at the top of build.sbtThisBuild / scalafixDependencies +="ch.epfl.scala" %%"example-scalafix-rule" %"4.0.0"

Start sbt and typescalafix <TAB>, once theexample-scalafix-rule dependencyhas been downloaded the rulesSemanticRule andSyntacticRule should appearas 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 SemanticDBcompiler 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 visithttps://scalameta.org/docs/semanticdb/guide.html#scalac-compiler-plugin

Avoid using slashes like/ in-P:semanticdb:exclude since that will notwork on Windows. The argument is compiled to a regular expression and getsmatched against thejava.io.File.getAbsolutePath representation of eachfile.

Exclude files from Scalafix

By default, thescalafix task processes all files in a project. If you useScala 2.x, thescalafix task also respects-P:semanticdb:exclude.

UseCompile / scalafix / unmanagedSources to optionally exclude files fromthescalafix task:

Compile / scalafix / unmanagedSources :=  (Compile / unmanagedSources).value    .filterNot(file => file.getName =="Macros.scala")

ReplaceCompile withTest to customize which test sources should beprocessed.

Customize SemanticDB output directory

The*.semanticdb files are available in the directory referenced by thesemanticdbTargetRoot key, which defaults totarget/scala-x/meta.

You can override this default to emit*.semanticdb files in a customlocation:

semanticdbTargetRoot := target.value /"semanticdb"

Alternatively, you can set thesemanticdbIncludeInJar key to requestthe compiler to emit these files into theclassDirectory so that theyare available in packaged JARs:

semanticdbIncludeInJar :=true

Disable Scalafix for specific project

Use.disablePlugins(ScalafixPlugin) to disable Scalafix for a particularproject:

  lazy val myproject = project    .settings(...)+   .disablePlugins(ScalafixPlugin)

When using Scala.js or Scala Native, use.jsConfigure or.nativeConfigure todisable 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 thescalafixEnable command to enable SemanticDB the current active sbt shellsession:

> scalafixEnable...> scalafix RemoveUnused

ThescalafixEnable command automatically enables semanticdb output and addsscalacOptions += "-Yrangepos" for all eligible projects in the builds. Thechange in Scala compiler options means the project may need to be re-built onthe nextcompile.

ThescalafixEnable command must be re-executed after everyreload and whensbt shell is exited.

Example project

For a minimal example project using sbt-scalafix, see thescalacenter/sbt-scalafix-examplerepository.

gitclone https://github.com/scalacenter/sbt-scalafix-examplecd sbt-scalafix-examplesbt"scalafix RemoveUnused"git diff // should produce a diff

Command line

First, install theCoursiercommand-line interface.

Then, install or launch a Scalafix runner built with the latest version of Scala(3.7.4):

cs install scalafixscalafix --version# Should say 0.14.5cs install scalafix:0.14.0scalafix --version# Should say 0.14.0cs launch scalafix:0.13.0 -- --version# Should say 0.13.0

If you plan to use advanced semantic rules likeExplicitResultTypes, youmust use the version of Scalafix built with a Scala version matching yourtarget 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.21:0.14.5 --main scalafix.cli.Cli -o scalafix_2.12cs bootstrap ch.epfl.scala:scalafix-cli_2.13.18:0.14.5 --main scalafix.cli.Cli -o scalafix_2.13cs bootstrap ch.epfl.scala:scalafix-cli_3.3.7:0.14.5 --main scalafix.cli.Cli -o scalafix_3.3-lts

Alternatively, you can run a one-shot command:

cs launch --scala X.Y scalafix -- --version

Help

Scalafix0.14.5+8-03ba0674-SNAPSHOTUsage: scalafix [options] [<path> ...]Scalafixis a refactoringand linting tool. Scalafixsupports both syntacticand semantic linterand rewriterules. Syntactic rules can runon source code withoutcompilation. Semantic rules can runon source code that hasbeen compiledwith the SemanticDB compiler plugin. Common options:--rules | -r [String ...] (default: [])    Scalafix rulesto run,for example ExplicitResultTypes. The    syntaxfor rulesis documentedin    https://scalacenter.github.io/scalafix/docs/users/configuration#rules--files | -f [<path> ...] (default: [])    Filesor directories (recursively visited)to fix.--config <path> (default: null)File pathto a .scalafix.confconfigurationfile. Defaultsto .scalafix.confin the current working directory,if    any.--check    Check thatall files have been fixedwith scalafix, exitingwith non-zero codeon violations. Won't writeto files.--stdout    Print fixed outputto stdout insteadof writingin-place.--diffIf set, only apply scalafixto addedand edited filesin git    diff against the master branch.--diff-base String (default: null)If set, only apply scalafixto addedand edited filesin git    diff against a provided branch, commitor tag.--scala-version ScalaVersion (default: "2.13.18")    The majoror binary Scala version that the provided files    are targeting,or the full version that was usedto    compile themwhen a classpathis provided.--syntactic    Run only syntactic rules, ignore semantic rules evenif they    are explicitly configuredin .scalafix.confor via--rules--triggered    Overlay thedefault rules & rule settingsin .scalafix.confwith the `triggered` section--verbose    Printout additional diagnosticswhile running scalafix.--help | -h    Printout this help messageandexit--version | -v    Printout version numberandexitSemantic options:--classpath Classpath (default: "<classpath>")    Full classpathof the filesto fix, requiredfor semantic    rules. The source files that should be fixed must be    compiledwith semanticdb-scalac. Dependencies are    required by rules like ExplicitResultTypes, but the    dependencies donot needto be compiledwith    semanticdb-scalac.--sourceroot <path> (default: null)    Absolute path passedto semanticdbwith    -P:semanticdb:sourceroot:<path>. Relative filenames    persistedin the Semantic DB are absolutized by the    sourceroot. Defaultsto current working directoryifnot    provided.--semanticdb-targetroots [<path> ...] (default: [])    Absolute paths passedto semanticdbwith    -P:semanticdb:targetroot:<path>. Usedto locate    semanticdb files. Bydefault, Scalafix will tryto    locate semanticdb filesin the classpath--auto-classpathIf set, automatically infer the--classpath flag by scanningfor directorieswith META-INF/semanticdb--auto-classpath-roots [<path> ...] (default: [])    Additional directoriesto scanfor--auto-classpath--scalac-options [String ...] (default: [])    The scala compiler options usedto compile this--classpath,for example -Ywarn-unused-importTab completions:--bash    Printout 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    Printout 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 globfor filesto exclude from fixing. The glob    syntaxis defined by `nio.FileSystem.getPathMatcher`.--tool-classpath URLClassLoader (default: "<classloader>")    Additional classpathfor compilingand classloading custom    rules, as a setof filesystem paths, separated by ':'on    Unixor ';'on Windows.--charset Charset (default: "UTF-8")    The encodingtousefor reading/writing files--no-sys-exitIf set, throw exceptionin theend insteadof System.exit--no-stale-semanticdb    Don'terroron stale semanticdb files.--settings ScalafixConfig (default: {})    Custom settingsto override .scalafix.conf--out-from String (default: null)    Write fixed outputto custom location insteadofin-place.    Regexis passed as first argumenttofile.replaceAll(--out-from, --out-to), requires--out-to.--out-to String (default: null)    Companionof--out-from, string that is passed as second    argumentto fileToFix.replaceAll(--out-from, --out-to)--auto-suppress-linter-errors    Insert/* scalafix:ok */ suppressions insteadof reporting    linter errors.--cwd <path> (default: "/home/runner/work/scalafix/scalafix")    The current working directory

Multiple values for CLI flags

Some Scalafix CLI flags accept more than one value (for example--rules,--files, or compiler options). Pass each value by repeating the flag insteadof trying to comma-separate or space-separate them. For instance, when you needto forward several scalac options you would write:

scalafix\  --rules RemoveUnused \  --scalac-options-Wunused:imports \  --scalac-options-Wvalue-discard

The CLI treats those repeated occurrences as a list, so both compiler optionsare forwarded to each Scalafix invocation.

Support in other build tools

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

SNAPSHOT

Our CI publishes a snapshot release to Sonatype on every merge into main. Eachsnapshot 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.5")+resolvers += Resolver.sonatypeCentralSnapshots+dependencyOverrides += "ch.epfl.scala" % "scalafix-interfaces" % "0.14.5+8-03ba0674-SNAPSHOT"

If using the command-line interface:

cs launch ch.epfl.scala:scalafix-cli_2.13.18:0.14.5+8-03ba0674-SNAPSHOT -r https://central.sonatype.com/repository/maven-snapshots --main scalafix.cli.Cli -- --help
Configuration

[8]ページ先頭

©2009-2025 Movatter.jp