Scalafix Future

(The Scala Center team is dedicated to providing regular and transparent community updates about project plans & progress. In this forum we created a new topic category to allow quicker orientation going forward: “Scala Center Updates”. Even though all feedback is welcome, we keep the right to make executive decisions about projects we lead. Overview of all our activities can always be found at https://scala.epfl.ch/records.html)

Scalafix Release v1.0

Scalafix, which is a refactoring and linting tool for Scala, could be a key factor in the success of Scala 3 migration. For that, the tool needs to evolve and to integrate some necessary features described in this github issue.

The main issue is that Scalafix rules are currently not published against a specific version and are supposed to work with all Scalafix supported versions. In reality, this is not the case, especially for rules that interface directly with the compiler (for example #998).

Next release should contain some important features that will allow us to use Scalafix for Scala migration:

  • Rules will be bound to a specific Scala version. In order to support all Scala versions, rules will need to cross build over all the desired versions.
  • Migrate Scalafix to Scala 2.13. This migration will require fixing some rules that do not work currently with Scala 2.13.

Scalafix Integration in Metals

Scalafix is usually used in batch mode via sbt to fix the entire code base before committing a change. We can reuse it by integrating Scalafix directly in Metals to provide new refactoring possibilities to the IDE. This change will unblock the implementation of some missing features such as “organize imports” or “remove unused”.

One of the challenges with this integration is the user experience which requires special attention when compared to the technical aspects. This is why we plan to first focus on a POC, then gather user feedback and finally implement the Scalafix integration (#1675).

Currently, we see several options:

  • Applying Scalafix rules through metals based on the project’s Scalafix configuration. We could have different commands for: apply all rules on file, apply only remove unused rule, apply only organize imports rule. The first command would be the heaviest, so maybe it will only be available via command and the rest might be made accessible also via Code Actions (remove unused) or shortcuts (organize imports).

  • Applying changes in metals using Scalafix regardless of the project’s configuration, but with limited scope (“organize imports” or “remove unused”). In this case Scalafix usage would be internal and not exposed to the user.

  • A mix of both approaches

28 Likes

I can’t overstate how happy I am about this! :tada: looking forward to it!

5 Likes

Scalafix updates


We are happy to announce the release of Scalafix 0.9.18. Thanks to all contributors and special thanks to bjaglin for his great contributions to this release (release notes: 1, 2).

We are now closer to v1.0.0 which we hope will be our next release.

Highlights of the last releases:

  • Scalafix has been migrated to scala 2.13
  • ExplicitResultTypes can now be run with the sbt plugin on projects using 2.11.12, 2.12.{9,10,11} or 2.13.{1,2,3} (scalafixScalaBinaryVersion needs to be set, for 2.11 or 2.13, see documentation)
  • The sbt plugin has now a scalafixAll command to run Scalafix across configurations
  • Scalafix-testkit can be used with ScalaTest 3.2.x
  • Local rules are now documented and can be written in the same Scala version as the project
13 Likes

Cross publishing rules for scalafix

Towards Scalafix v1.0

Until v0.9.18, Scalafix rules were published only in Scala 2.12. Most of them were able to run on scala projects regardless of the Scala version being fixed, except the rules that interface directly with the compiler. For example ExplicitResultType is bound to one specific Scala version, and cannot run for other scala versions (see this github issue)

Starting v0.9.18, we decided to tackle this limitation by making it possible to specify the scala binary version of rules being used by the scalafix plugin. Now, it is possible to use scalafix-rules_2.12 on 2.12 sources, scalafix-rules_2.13 on 2.13 sources, and scalafix-rules_2.11 on 2.11 sources. For example, to use ExplicitResultType on a 2.13 scala project, you need to set the key scalafixScalaBinaryVersion to 2.13in your build (see the documentation)

In order not to break compatibility, while scalafix is still v0.9.x, the scalafixScalaBinaryVersion is set by default to 2.12. In other words, if this key is not specified, 2.12 rules are still being used. But going further, and starting v1, our goal is to change the default value to follow the target sources version.

What does it change for rules authors?

Already existing custom rules

If your rule is meant only for one scala version, for example, a rule that automates a migration from one scala version to another, you don’t need to cross publish your rule. In fact, your rule should only be run for this specific scala version, and should only be published in this scala version.

Otherwise, if your rule is not specific to a scala version, and in order to make the migration to scalafix v1 smooth for users, we need the rules authors to cross-publish their rules for the scala versions they support. For most rules, this change requires only modifying the build settings as follows:

 // build.sbt
    scalaVersion := V.scala212,
   +crossScalaVersions := List(V.scala213, V.scala212, V.scala211),

The second step is to update your CI to run tests on the different scala versions your rule is being cross-published to. For that, you only need prefix the test action with +. For example:

sbt +test

New rules

The scalafix template has already been updated to automatically cross publish rules (see pull request). Therefore, no change is required if you are writing a new rule.

Projects that already cross-publish

This is a non-exhaustive list of pull requests that have cross-published their rules:

5 Likes