From de34b7285d5ba815302d8e0327dacd6c41887f2a Mon Sep 17 00:00:00 2001 From: Meriam Lachkar Date: Thu, 2 Jul 2020 13:36:02 +0200 Subject: [PATCH] Add support for the 3 last versions of scala for each binary version for rules (#1174) * Add support for the 3 last versions of scala212 and scala213 for the project rules We were failing if the scalaversion is not exactly the same than the one used to compile explicitResultType rule. Now it can work with the 3 last versions, and we have tests to verify that it works as expected * Update project/ScalafixBuild.scala Co-authored-by: Brice Jaglin * Update project/Dependencies.scala Co-authored-by: Brice Jaglin Co-authored-by: Brice Jaglin --- build.sbt | 14 ++++++-- project/Dependencies.scala | 14 ++++++++ project/ScalafixBuild.scala | 27 +++++++++++---- .../internal/rule/ExplicitResultTypes.scala | 33 ++++++++++++++----- 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/build.sbt b/build.sbt index c3eb4bec70..7532c9531c 100644 --- a/build.sbt +++ b/build.sbt @@ -71,6 +71,12 @@ lazy val rules = project .in(file("scalafix-rules")) .settings( moduleName := "scalafix-rules", + buildInfoKeys ++= Seq[BuildInfoKey]( + "supportedScalaVersions" -> (scalaVersion.value +: + testedPreviousScalaVersions + .getOrElse(scalaVersion.value, Nil)) + ), + buildInfoObject := "RulesBuildInfo", description := "Built-in Scalafix rules", libraryDependencies ++= List( "org.scalameta" % "semanticdb-scalac-core" % scalametaV cross CrossVersion.full, @@ -78,6 +84,7 @@ lazy val rules = project ) ) .dependsOn(core) + .enablePlugins(BuildInfoPlugin) lazy val reflect = project .in(file("scalafix-reflect")) @@ -215,8 +222,11 @@ lazy val unit = project "outputSourceDirectories", sourceDirectories.in(testsOutput, Compile).value ) - props.put("scalaVersion", scalaVersion.value) - props.put("scalacOptions", scalacOptions.value.mkString("|")) + props.put("scalaVersion", scalaVersion.in(testsInput, Compile).value) + props.put( + "scalacOptions", + scalacOptions.in(testsInput, Compile).value.mkString("|") + ) val out = managedResourceDirectories.in(Test).value.head / "scalafix-testkit.properties" diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 8b2507b9ce..bbe91f95cd 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -1,4 +1,6 @@ import sbt._ + +import scala.util.{Properties, Try} /* scalafmt: { maxColumn = 120 }*/ object Dependencies { @@ -11,6 +13,9 @@ object Dependencies { def coursierV = "2.0.0-RC5-6" def coursierInterfaceV = "0.0.22" val currentScalaVersion = scala213 + // we support 3 last binary versions of scala212 and scala213 + val testedPreviousScalaVersions = + List(scala213, scala212).map(version => version -> previousVersions(version)).toMap val jgit = "org.eclipse.jgit" % "org.eclipse.jgit" % "5.8.0.202006091008-r" @@ -37,4 +42,13 @@ object Dependencies { "com.chuusai" %% "shapeless" % "2.3.3", scalacheck ) + + private def previousVersions(scalaVersion: String): List[String] = { + val split = scalaVersion.split('.') + val binaryVersion = split.take(2).mkString(".") + val compilerVersion = Try(split.last.toInt).toOption + val previousPatchVersions = + compilerVersion.map(version => List.range(version - 2, version).filter(_ >= 0)).getOrElse(Nil) + previousPatchVersions.map(v => s"$binaryVersion.$v") + } } diff --git a/project/ScalafixBuild.scala b/project/ScalafixBuild.scala index eecd9a294e..4fa3ca8b3c 100644 --- a/project/ScalafixBuild.scala +++ b/project/ScalafixBuild.scala @@ -190,21 +190,21 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys { s }, commands += Command.command("ci-213") { s => - s"++$scala213" :: + s"""set ThisBuild/scalaVersion := "$scala213"""" :: "unit/test" :: "docs/run" :: "interfaces/doc" :: - s + testRulesAgainstPreviousScalaVersions(scala213, s) }, commands += Command.command("ci-212") { s => - s"++$scala212" :: + s"""set ThisBuild/scalaVersion := "$scala212"""" :: "unit/test" :: - s + testRulesAgainstPreviousScalaVersions(scala212, s) }, commands += Command.command("ci-211") { s => - s"++$scala211" :: + s"""set ThisBuild/scalaVersion := "$scala211"""" :: "unit/test" :: - s + testRulesAgainstPreviousScalaVersions(scala211, s) }, commands += Command.command("ci-213-windows") { s => s"++$scala213" :: @@ -342,4 +342,19 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys { } } ) + private def testRulesAgainstPreviousScalaVersions( + scalaVersion: String, + state: State + ): State = { + testedPreviousScalaVersions + .getOrElse(scalaVersion, Nil) + .flatMap { v => + List( + s"""set testsInput/scalaVersion := "$v"""", + "show testsInput/scalaVersion", + s"unit/testOnly scalafix.tests.rule.RuleSuite" + ) + } + .foldRight(state)(_ :: _) + } } diff --git a/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala b/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala index 8d809af71d..67a777bb49 100644 --- a/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala +++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala @@ -1,5 +1,6 @@ package scalafix.internal.rule +import buildinfo.RulesBuildInfo import scala.meta._ import scala.meta.contrib._ import scalafix.patch.Patch @@ -9,7 +10,6 @@ import metaconfig.Configured import scala.meta.internal.pc.ScalafixGlobal import scalafix.internal.v1.LazyValue import scala.util.control.NonFatal -import scala.util.Properties import scalafix.internal.compat.CompilerCompat._ final class ExplicitResultTypes( @@ -18,11 +18,14 @@ final class ExplicitResultTypes( ) extends SemanticRule("ExplicitResultTypes") { def this() = this(ExplicitResultTypesConfig.default, LazyValue.now(None)) + val supportedScalaVersions = RulesBuildInfo.supportedScalaVersions + val compilerScalaVersion = RulesBuildInfo.scalaVersion + + private def toBinaryVersion(v: String) = v.split('.').take(2).mkString(".") - private def supportedScalaVersion = Properties.versionNumberString override def description: String = "Inserts type annotations for inferred public members. " + - s"Only compatible with Scala $supportedScalaVersion." + s"Only compatible with Scala ${supportedScalaVersions.mkString(",")}." override def isRewrite: Boolean = true override def afterComplete(): Unit = { @@ -57,12 +60,24 @@ final class ExplicitResultTypes( ) } } - if (config.scalacClasspath.nonEmpty && config.scalaVersion != supportedScalaVersion) { - Configured.error( - s"The ExplicitResultTypes rule only supports the Scala version '$supportedScalaVersion'. " + - s"To fix this problem, either remove `ExplicitResultTypes` from .scalafix.conf or change the Scala version " + - s"in your build to match exactly '$supportedScalaVersion'." - ) + if (config.scalacClasspath.nonEmpty && !supportedScalaVersions.contains( + config.scalaVersion + )) { + val inputBinaryScalaVersion = + toBinaryVersion(config.scalaVersion) + val runtimeBinaryScalaVersion = + toBinaryVersion(compilerScalaVersion) + if (inputBinaryScalaVersion == runtimeBinaryScalaVersion) + Configured.error( + s"The ExplicitResultTypes rule only supports the exact Scala versions '$supportedScalaVersions' for this binary version. " + + s"To fix this problem, either remove ExplicitResultTypes from .scalafix.conf " + + s"or change the Scala version of your build to match one of the supported versions." + ) + else + Configured.error( + s"The ExplicitResultTypes rule needs to run with the same Scala binary version as the one used to compile target sources ($inputBinaryScalaVersion). " + + s"To fix this problem, either remove ExplicitResultTypes from .scalafix.conf or make sure the scalafixScalaBinaryVersion setting key matches $inputBinaryScalaVersion." + ) } else { config.conf // Support deprecated explicitReturnTypes config .getOrElse("explicitReturnTypes", "ExplicitResultTypes")(