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")(