Scalafix

Scalafix

  • User guide
  • Developer guide
  • Browse sources
  • GitHub

›Misc

Usage

  • Installation
  • Configuration
  • Suppressing rules

Rules

  • All rules
  • RemoveUnused
  • DisableSyntax
  • NoAutoTupling
  • LeakingImplicitClassVal
  • NoValInForComprehension
  • ProcedureSyntax

Misc

  • Related projects
Edit

Related projects

There are several alternative tools to Scalafix that each make different tradeoffs with regards to Scala 2.x fidelity, ease of writing custom analyses, interactivity, performance, integrations and feature support. The table below provides a rough comparison, below are more detailed explanations.

Syntax modelTypecheckerLintingRefactoringRun on compile
ScalafixScalametaScala compilerYesYesNo
WartRemoverScala compilerScala compilerYesNoYes
IntelliJ ScalaIntelliJ ScalaIntelliJ ScalaYesYesNo
ScalaStyleScalariformn/aYesNoYes
Scala RefactoringScala compilerScala compilerYesYesNo

WartRemover

WartRemover is a flexible scala linter. Scalafix and WartRemover can be used together as linters. The primary difference between Scalafix and WartRemover is that Scalafix runs after compilation as a separate tool and WartRemover runs during compilation as a compiler plugin. There are no plans to support lint-on-compile in Scalafix since this use-case is already served well by WartRemover. See Lessons from Building Static Analysis Tools at Google for an in-depth write-up about lint-on-compile vs. lint-after-compile.

  • WartRemover has more linter rules out of the box than Scalafix.
  • It is easier to write/test/share/run new/custom rules with Scalafix. The Scalafix API does not require familiarity with scalac compiler internals.
  • Scalafix is a linter and refactoring tool, which means Scalafix rules can automatically fix some discovered problems. WartRemover is only a linter, it does not support automatic fixing.
  • Scalafix supports syntactic rules without going through the compiler, this means that WartRemover rules like Null, Throw, FinalVal, asInstanceOf, ExplicitImplicitTypes, Var, While can run faster outside of compilation if implemented with Scalafix.

IntelliJ Scala

The IntelliJ Scala Plugin is probably the most used IDE for Scala development, supporting a wide range of features to browse/edit/refactor Scala code.

  • Scalafix is primarily aimed to be used in batch-mode through a console interface while IntelliJ is primarily aimed for interactive use in the IntelliJ IDE.
  • IntelliJ Scala contains a lot more rules ("inspections" in IntelliJ terms), including sophisticated refactorings such as "Organize imports" and "Move class" that Scalafix does not currently support.
  • Scalafix uses the Scala 2.x compiler to resolve symbols/types while the IntelliJ Scala plugin uses its own typechecker.

Scalastyle

Scalastyle is a Scala style checker.

  • Scalastyle has a lot more rules than Scalafix out of the box.
  • Scalafix supports semantic and syntactic rules while Scalastyle supports only syntactic rules. Semantic Scalafix rules know more about the types/symbols in your source code. For example, a semantic rules can tell if get in x.get comes from Option[T].get or from another class that happens to also have a .get method. Scalastyle is purely syntactic, which means it does not support rules that need information about types/symbols.
  • Scalastyle runs as a separate tool outside of compilation, just like Scalafix.

Scala Refactoring

Scala Refactoring is a library providing automated refactoring support for Scala.

  • Scalafix rules uses the Scalameta AST while Scala Refactoring uses the Scala 2.x compiler AST. The Scalameta AST encodes more syntactic details from the original source file, including for-comprehensions, infix operators and primary constructors. Example:
// scalameta AST
case class A(b: Int, c: String) {
  for {
    char <- c
    if char == 'a'
    i <- (1 to char.toInt)
  } yield i
  val d, List(e: Int) = List(1)
}
// Scala Compiler AST
package <empty> {
  case class A extends scala.Product with scala.Serializable {
    <caseaccessor> <paramaccessor> val b: Int = _;
    <caseaccessor> <paramaccessor> val c: String = _;
    def <init>(b: Int, c: String) = {
      super.<init>();
      ()
    };
    c.withFilter(((char) => char.$eq$eq('a'))).flatMap(((char) => 1.to(char.toInt).map(((i) => i))));
    val d = List(1);
    val e: Int = List(1): @scala.unchecked match {
      case List((e @ (_: Int))) => e
    }
  }
}
  • Scala Refactoring requires a live instance of scala-compiler while scalafix-core does not depend on scala-compiler. Scalafix only depends on SemanticDB. This has positive and negative implications, for example
    • Scala Refactoring has always access to the full compiler APIs, while changes to the Scalafix semantic API may require changing the Scalameta SemanticDB schema.
    • scalafix-core cross-builds to Scala.js, you can interactively explore the Scalameta ASTs in the browser on astexplorer.net.
    • The edit/run/debug cycle when developing Scalafix rules can be very fast if you have a pre-built SemanticDB. For example, in olafur/scala-experiments you can run semantic analysis on a corpus of 2.5M LOC in under 5 seconds (more complicated analyses can take 1-2 minutes). You can use that corpus to fuzz your Scalafix rules. In Scala Refactoring, you must always re-compile sources to test new changes in the rule you are developing.
    • scala-compiler APIs expose internals of the Scala compiler, which requires a certain level of expertise to accomplish even fairly simple tasks. It is easy to get cryptic compiler errors in scala-compiler if you accidentally break some assumed invariants. SemanticDB on the other hand is a plain data schema, essentially a small hierarchy of case classes. The entire schema is defined in a single file of protobuf.
← Previous
  • WartRemover
  • IntelliJ Scala
  • Scalastyle
  • Scala Refactoring
Scalafix
Docs
Get startedRulesExtend Scalafix
Community
Chat on GitterDiscuss on Scala Users
More
GitHub
Copyright © 2018 Scala Center