From f7adc0ebe7a1ed9a6ae1cd85d1d83a55fb775f35 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 c3eb4bec7..7532c9531 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 8b2507b9c..bbe91f95c 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 eecd9a294..4fa3ca8b3 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 8d809af71..67a777bb4 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")(