Skip to content

Commit

Permalink
scalafix-interfaces: improve docs & be more liberal in parsing
Browse files Browse the repository at this point in the history
Even though not documented, but since "major.minor" / source-compatibility is
non-standard (we need more than "binary" as all Scala 3 versions are binary-
compatible) and can be confusing, this supports using just a major version.
  • Loading branch information
bjaglin committed Sep 29, 2024
1 parent f2818e5 commit ba5f810
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 13 deletions.
28 changes: 17 additions & 11 deletions scalafix-interfaces/src/main/java/scalafix/interfaces/Scalafix.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ public interface Scalafix {
* <p>
* 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
Expand All @@ -106,9 +107,10 @@ static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion) throws Scal
* <p>
* 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
Expand All @@ -120,17 +122,21 @@ static Scalafix fetchAndClassloadInstance(String scalaBinaryVersion) throws Scal
static Scalafix fetchAndClassloadInstance(String requestedScalaVersion, List<Repository> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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] {
Expand Down

0 comments on commit ba5f810

Please sign in to comment.