diff --git a/scalafix-interfaces/src/main/java/scalafix/interfaces/Scalafix.java b/scalafix-interfaces/src/main/java/scalafix/interfaces/Scalafix.java
index 8ebc23582..a8059e6ed 100644
--- a/scalafix-interfaces/src/main/java/scalafix/interfaces/Scalafix.java
+++ b/scalafix-interfaces/src/main/java/scalafix/interfaces/Scalafix.java
@@ -86,12 +86,13 @@ public interface Scalafix {
*
* The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
* classload external rules must have the classloader of the returned instance as ancestor to share a common
- * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala binary version.
+ * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala version.
*
- * @param requestedScalaVersion The Scala version ("3.3.4" for example) available in the classloader of the
+ * @param requestedScalaVersion A full Scala version (i.e. "3.3.4") or a major.minor one (i.e. "3.3") to infer
+ * the major.minor Scala version that should be available in the classloader of the
* returned instance. To be able to run advanced semantic rules using the Scala
- * Presentation Compiler such as ExplicitResultTypes, this must match the version
- * that the target classpath was built with, as provided with
+ * Presentation Compiler such as ExplicitResultTypes, this must be source-compatible
+ * with the version that the target classpath is built with, as provided with
* {@link ScalafixArguments#withScalaVersion}.
* @return An implementation of the {@link Scalafix} interface.
* @throws ScalafixException in case of errors during artifact resolution/fetching.
@@ -106,12 +107,13 @@ static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion) throws Scal
*
* The custom classloader optionally provided with {@link ScalafixArguments#withToolClasspath} to compile and
* classload external rules must have the classloader of the returned instance as ancestor to share a common
- * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala binary version.
+ * loaded instance of `scalafix-core`, and therefore have been compiled against the requested Scala version.
*
- * @param requestedScalaVersion The Scala version ("3.3.4" for example) available in the classloader of the
+ * @param requestedScalaVersion A full Scala version (i.e. "3.3.4") or a major.minor one (i.e. "3.3") to infer
+ * the major.minor Scala version that should be available in the classloader of the
* returned instance. To be able to run advanced semantic rules using the Scala
- * Presentation Compiler such as ExplicitResultTypes, this must match the version
- * that the target classpath was built with, as provided with
+ * Presentation Compiler such as ExplicitResultTypes, this must be source-compatible
+ * with the version that the target classpath is built with, as provided with
* {@link ScalafixArguments#withScalaVersion}.
* @param repositories Maven/Ivy repositories to fetch the JARs from.
* @return An implementation of the {@link Scalafix} interface.
@@ -120,17 +122,21 @@ static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion) throws Scal
static Scalafix fetchAndClassloadInstance(String requestedScalaVersion, List repositories)
throws ScalafixException {
+ String requestedScalaMajorMinorOrMajorVersion =
+ requestedScalaVersion.replaceAll("^(\\d+\\.\\d+).*", "$1");
+
String scalaVersionKey;
- if (requestedScalaVersion.startsWith("2.12")) {
+ if (requestedScalaMajorMinorOrMajorVersion.equals("2.12")) {
scalaVersionKey = "scala212";
- } else if (requestedScalaVersion.startsWith("2.13")) {
+ } else if (requestedScalaMajorMinorOrMajorVersion.equals("2.13") ||
+ requestedScalaMajorMinorOrMajorVersion.equals("2")) {
scalaVersionKey = "scala213";
- } else if (requestedScalaVersion.startsWith("3.0") ||
- requestedScalaVersion.startsWith("3.1") ||
- requestedScalaVersion.startsWith("3.2") ||
- requestedScalaVersion.startsWith("3.3")) {
+ } else if (requestedScalaMajorMinorOrMajorVersion.equals("3.0") ||
+ requestedScalaMajorMinorOrMajorVersion.equals("3.1") ||
+ requestedScalaMajorMinorOrMajorVersion.equals("3.2") ||
+ requestedScalaMajorMinorOrMajorVersion.equals("3.3")) {
scalaVersionKey = "scala3LTS";
- } else if (requestedScalaVersion.startsWith("3")) {
+ } else if (requestedScalaMajorMinorOrMajorVersion.startsWith("3")) {
scalaVersionKey = "scala3Next";
} else {
throw new IllegalArgumentException("Unsupported scala version " + requestedScalaVersion);
diff --git a/scalafix-tests/integration/src/test/scala/scalafix/tests/interfaces/ScalafixSuite.scala b/scalafix-tests/integration/src/test/scala/scalafix/tests/interfaces/ScalafixSuite.scala
index 4a5f6c4b8..e189de24b 100644
--- a/scalafix-tests/integration/src/test/scala/scalafix/tests/interfaces/ScalafixSuite.scala
+++ b/scalafix-tests/integration/src/test/scala/scalafix/tests/interfaces/ScalafixSuite.scala
@@ -54,16 +54,80 @@ class ScalafixSuite extends AnyFunSuite {
assert(help.contains("Usage: scalafix"))
}
- test("classload Scala 3 LTS as a fallback for pre-LTS versions") {
+ test("fail to classload Scala 2.11 with full version") {
+ assertThrows[IllegalArgumentException](
+ Scalafix.fetchAndClassloadInstance("2.11.0", repositories)
+ )
+ }
+
+ test("fail to classload Scala 2.11 with minor version") {
+ assertThrows[IllegalArgumentException](
+ Scalafix.fetchAndClassloadInstance("2.11", repositories)
+ )
+ }
+
+ test("classload Scala 2.12 with full version") {
+ val scalafixAPI =
+ Scalafix.fetchAndClassloadInstance("2.12.20", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala212)
+ }
+
+ test("classload Scala 2.12 with major.minor version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("2.12", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala212)
+ }
+
+ test("classload Scala 2.13 with full version") {
+ val scalafixAPI =
+ Scalafix.fetchAndClassloadInstance("2.13.15", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala213)
+ }
+
+ test("classload Scala 2.13 with major.minor version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("2.13", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala213)
+ }
+
+ test("classload Scala 2.13 with major version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("2", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala213)
+ }
+
+ test("classload Scala 3 LTS with full pre-LTS version") {
val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.0.0", repositories)
assert(scalafixAPI.scalaVersion() == Versions.scala3LTS)
}
- test("classload Scala 3 Next as a fallback for post-LTS versions") {
+ test("classload Scala 3 LTS with major.minor pre-LTS version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.2", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala3LTS)
+ }
+
+ test("classload Scala 3 LTS with full LTS version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.3.4", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala3LTS)
+ }
+
+ test("classload Scala 3 LTS with major.minor LTS version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.3", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala3LTS)
+ }
+
+ test("classload Scala 3 Next with full post-LTS version") {
val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.4.0", repositories)
assert(scalafixAPI.scalaVersion() == Versions.scala3Next)
}
+ test("classload Scala 3 Next with major.minor post-LTS version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("3.5", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala3Next)
+ }
+
+ test("classload Scala 3 Next with major version") {
+ val scalafixAPI = Scalafix.fetchAndClassloadInstance("3", repositories)
+ assert(scalafixAPI.scalaVersion() == Versions.scala3Next)
+ }
+
test("invalid class loader") {
val cl = new URLClassLoader(Array(), null)
val ex = intercept[ScalafixException] {