diff --git a/build.sbt b/build.sbt
index 054868f1e..6e9d04ae8 100644
--- a/build.sbt
+++ b/build.sbt
@@ -212,8 +212,7 @@ lazy val unit = project
}
put(
"inputClasspath",
- (testsInput / Compile / fullClasspath).value.map(_.data) :+
- (testsInput / Compile / semanticdbTargetRoot).value
+ (testsInput / Compile / fullClasspath).value.map(_.data)
)
put(
"inputSourceDirectories",
@@ -246,7 +245,10 @@ lazy val unit = project
"testsInputResources" ->
(testsInput / Compile / sourceDirectory).value / "resources",
"semanticClasspath" ->
- (testsShared / Compile / semanticdbTargetRoot).value,
+ Seq(
+ (testsInput / Compile / semanticdbTargetRoot).value,
+ (testsShared / Compile / semanticdbTargetRoot).value
+ ),
"sharedSourceroot" ->
(ThisBuild / baseDirectory).value /
"scalafix-tests" / "shared" / "src" / "main",
diff --git a/project/Mima.scala b/project/Mima.scala
index 7ec2cbfe9..e79cef64e 100644
--- a/project/Mima.scala
+++ b/project/Mima.scala
@@ -34,7 +34,7 @@ object Mima {
ProblemFilters.exclude[Problem]("scalafix.testkit.SemanticRuleSuite.*"),
ProblemFilters.exclude[MissingClassProblem]("scalafix.testkit.SyntacticRuleSuite$"),
ProblemFilters.exclude[Problem]("scalafix.testkit.SyntacticRuleSuite"),
- ProblemFilters.exclude[ReversedMissingMethodProblem]("scalafix.interfaces.ScalafixArguments.withSemanticdbTargetroot")
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("scalafix.interfaces.ScalafixArguments.withSemanticdbTargetroots")
)
}
}
diff --git a/scalafix-cli/src/main/scala/scalafix/internal/interfaces/ScalafixArgumentsImpl.scala b/scalafix-cli/src/main/scala/scalafix/internal/interfaces/ScalafixArgumentsImpl.scala
index daf20375d..82ae1ed8f 100644
--- a/scalafix-cli/src/main/scala/scalafix/internal/interfaces/ScalafixArgumentsImpl.scala
+++ b/scalafix-cli/src/main/scala/scalafix/internal/interfaces/ScalafixArgumentsImpl.scala
@@ -160,9 +160,13 @@ final case class ScalafixArgumentsImpl(args: Args = Args.default)
copy(args = args.copy(sourceroot = Some(AbsolutePath(path)(args.cwd))))
}
- override def withSemanticdbTargetroot(path: Path): ScalafixArguments = {
+ override def withSemanticdbTargetroots(
+ paths: util.List[Path]
+ ): ScalafixArguments = {
copy(args =
- args.copy(semanticdbTargetroot = Some(AbsolutePath(path)(args.cwd)))
+ args.copy(semanticdbTargetroots =
+ paths.asScala.toList.map(AbsolutePath(_)(args.cwd))
+ )
)
}
diff --git a/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala b/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala
index fdc1b7041..9e6be8188 100644
--- a/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala
+++ b/scalafix-cli/src/main/scala/scalafix/internal/v1/Args.scala
@@ -110,10 +110,10 @@ case class Args(
)
sourceroot: Option[AbsolutePath] = None,
@Description(
- "Absolute path passed to semanticdb with -P:semanticdb:targetroot:. " +
+ "Absolute paths passed to semanticdb with -P:semanticdb:targetroot:. " +
"Used to locate semanticdb files. By default, Scalafix will try to locate semanticdb files in the classpath"
)
- semanticdbTargetroot: Option[AbsolutePath] = None,
+ semanticdbTargetroots: List[AbsolutePath] = Nil,
@Description(
"If set, automatically infer the --classpath flag by scanning for directories with META-INF/semanticdb"
)
@@ -348,11 +348,12 @@ case class Args(
}
def validatedClasspath: Classpath = {
- val targetrootClasspath = semanticdbTargetroot
- .map(_.toString())
- .orElse(semanticdbOption("targetroot", Some("-semanticdb-target")))
- .map(option => Classpath(option))
- .getOrElse(Classpath(Nil))
+ val targetrootClasspath = semanticdbTargetroots match {
+ case Nil =>
+ semanticdbOption("targetroot", Some("-semanticdb-target")).toList
+ .map(AbsolutePath.apply)
+ case _ => semanticdbTargetroots
+ }
val baseClasspath =
if (autoClasspath && classpath.entries.isEmpty) {
val roots =
@@ -362,7 +363,7 @@ case class Args(
} else {
classpath
}
- targetrootClasspath ++ baseClasspath
+ Classpath(targetrootClasspath) ++ baseClasspath
}
def classLoader: ClassLoader =
diff --git a/scalafix-interfaces/src/main/java/scalafix/interfaces/ScalafixArguments.java b/scalafix-interfaces/src/main/java/scalafix/interfaces/ScalafixArguments.java
index a3a86c824..5715130bd 100644
--- a/scalafix-interfaces/src/main/java/scalafix/interfaces/ScalafixArguments.java
+++ b/scalafix-interfaces/src/main/java/scalafix/interfaces/ScalafixArguments.java
@@ -140,10 +140,10 @@ ScalafixArguments withToolClasspath(
ScalafixArguments withSourceroot(Path path);
/**
- * @param path The SemanticDB targetroot path passed via --targetroot. Must match path
- * in -Xplugin:semanticdb:targetroot:{path}
if used.
+ * @param path The SemanticDB targetroot paths passed via --semanticdb-targetroots. Must match
+ * path
in -Xplugin:semanticdb:targetroot:{path}
if used.
*/
- ScalafixArguments withSemanticdbTargetroot(Path path);
+ ScalafixArguments withSemanticdbTargetroots(List path);
/**
* @param callback Handler for reported linter messages. If not provided, defaults to printing
diff --git a/scalafix-reflect/src/main/scala/scalafix/internal/reflect/ClasspathOps.scala b/scalafix-reflect/src/main/scala/scalafix/internal/reflect/ClasspathOps.scala
index ab2d42644..9af8ee72d 100644
--- a/scalafix-reflect/src/main/scala/scalafix/internal/reflect/ClasspathOps.scala
+++ b/scalafix-reflect/src/main/scala/scalafix/internal/reflect/ClasspathOps.scala
@@ -43,6 +43,11 @@ object ClasspathOps {
new URLClassLoader(url +: getURLs(classLoader), classLoader)
}
+ def thisClassLoaderWith(urls: Seq[URL]): URLClassLoader = {
+ val classLoader = this.getClass.getClassLoader
+ new URLClassLoader(urls.toArray ++ getURLs(classLoader), classLoader)
+ }
+
def thisClasspath: Classpath = {
Classpath(
getURLs(this.getClass().getClassLoader())
diff --git a/scalafix-testkit/src/main/scala/scalafix/testkit/AbstractSemanticRuleSuite.scala b/scalafix-testkit/src/main/scala/scalafix/testkit/AbstractSemanticRuleSuite.scala
index 411ea3c60..47dad840f 100644
--- a/scalafix-testkit/src/main/scala/scalafix/testkit/AbstractSemanticRuleSuite.scala
+++ b/scalafix-testkit/src/main/scala/scalafix/testkit/AbstractSemanticRuleSuite.scala
@@ -10,10 +10,12 @@ import org.scalatest.BeforeAndAfterAll
import org.scalatest.Suite
import org.scalatest.TestRegistration
import org.scalatest.exceptions.TestFailedException
+import scalafix.internal.config.ScalaVersion
import scalafix.internal.patch.PatchInternals
import scalafix.internal.reflect.ClasspathOps
import scalafix.internal.testkit.AssertDiff
import scalafix.internal.testkit.CommentAssertion
+import scalafix.internal.v1.Args
/**
* Construct a test suite for running semantic Scalafix rules.
@@ -98,8 +100,13 @@ abstract class AbstractSemanticRuleSuite(
}
lazy val testsToRun: List[RuleTest] = {
+ val args = Args.default.copy(
+ scalaVersion = ScalaVersion.from(props.scalaVersion).get,
+ scalacOptions = props.scalacOptions,
+ classpath = props.inputClasspath
+ )
val symtab = ClasspathOps.newSymbolTable(props.inputClasspath)
- val classLoader = ClasspathOps.toClassLoader(props.inputClasspath)
+ val classLoader = ClasspathOps.toClassLoader(args.validatedClasspath)
val tests = TestkitPath.fromProperties(props)
tests.map { test =>
RuleTest.fromPath(props, test, classLoader, symtab)
diff --git a/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/BaseCliSuite.scala b/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/BaseCliSuite.scala
index e963a8b02..60f76dacb 100644
--- a/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/BaseCliSuite.scala
+++ b/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/BaseCliSuite.scala
@@ -10,8 +10,6 @@ import java.nio.file.SimpleFileVisitor
import java.nio.file.StandardCopyOption
import java.nio.file.attribute.BasicFileAttributes
-import scala.collection.immutable.Seq
-
import scala.meta.internal.io.FileIO
import scala.meta.io.AbsolutePath
import scala.meta.io.RelativePath
@@ -23,6 +21,7 @@ import scalafix.test.StringFS
import scalafix.testkit.DiffAssertions
import scalafix.testkit.SemanticRuleSuite
import scalafix.testkit.TestkitProperties
+import scalafix.tests.BuildInfo
import scalafix.tests.util.ScalaVersions
import scalafix.v1.Main
@@ -179,6 +178,8 @@ trait BaseCliSuite extends AnyFunSuite with DiffAssertions {
def checkSemantic(
name: String,
args: Array[String],
+ targetroots: Seq[String] =
+ BuildInfo.semanticClasspath.map(_.getAbsolutePath),
expectedExit: ExitStatus,
preprocess: AbsolutePath => Unit = _ => (),
outputAssert: String => Unit = _ => (),
@@ -207,11 +208,13 @@ trait BaseCliSuite extends AnyFunSuite with DiffAssertions {
val sourceroot =
if (args.contains("--sourceroot")) Array[String]()
else Array("--sourceroot", cwd.toString)
+ val targetroots0 =
+ targetroots.flatMap(Seq("--semanticdb-targetroots", _))
val scalaOption =
if (ScalaVersions.isScala213)
"-Wunused:imports"
else "-Ywarn-unused-import"
- val allArguments = args ++ sourceroot ++ Seq(
+ val allArguments = args ++ sourceroot ++ targetroots0 ++ Seq(
"--scalac-options",
scalaOption,
"-r",
diff --git a/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/CliSemanticSuite.scala b/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/CliSemanticSuite.scala
index 280e1acda..c0b97a689 100644
--- a/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/CliSemanticSuite.scala
+++ b/scalafix-tests/unit/src/test/scala/scalafix/tests/cli/CliSemanticSuite.scala
@@ -9,6 +9,7 @@ import scala.meta.io.Classpath
import scala.meta.testkit.StringFS
import scalafix.cli._
+import scalafix.tests.BuildInfo
import scalafix.tests.core.Classpaths
class CliSemanticSuite extends BaseCliSuite {
@@ -50,6 +51,7 @@ class CliSemanticSuite extends BaseCliSuite {
checkSemantic(
name = "missing --classpath",
args = Array(),
+ targetroots = Seq.empty,
expectedExit = ExitStatus.MissingSemanticdbError
)
@@ -170,13 +172,13 @@ class CliSemanticSuite extends BaseCliSuite {
checkSemantic(
name = "-P:semanticdb:targetroot",
args = {
- val (_ :: targetroot :: Nil, jars) =
- props.inputClasspath.entries.partition(_.isDirectory)
+ val jars = props.inputClasspath.entries.filter(_.isDirectory)
+ val targetroot = BuildInfo.semanticClasspath.last.getAbsolutePath
Array(
s"--scalacOptions",
s"-P:semanticdb:targetroot:shouldBeIgnored",
s"--scalacOptions",
- s"-P:semanticdb:targetroot:${targetroot.toString()}",
+ s"-P:semanticdb:targetroot:$targetroot",
"--classpath",
Classpath(jars).syntax
)
diff --git a/scalafix-tests/unit/src/test/scala/scalafix/tests/core/BaseSemanticSuite.scala b/scalafix-tests/unit/src/test/scala/scalafix/tests/core/BaseSemanticSuite.scala
index 5cb0dfed8..0237c8808 100644
--- a/scalafix-tests/unit/src/test/scala/scalafix/tests/core/BaseSemanticSuite.scala
+++ b/scalafix-tests/unit/src/test/scala/scalafix/tests/core/BaseSemanticSuite.scala
@@ -31,7 +31,9 @@ object BaseSemanticSuite {
SemanticDocument.fromPath(
doc,
relpath,
- ClasspathOps.thisClassLoaderWith(BuildInfo.semanticClasspath.toURI.toURL),
+ ClasspathOps.thisClassLoaderWith(
+ BuildInfo.semanticClasspath.map(_.toURI.toURL)
+ ),
symtab
)
}
@@ -50,9 +52,10 @@ abstract class BaseSemanticSuite(filename: String)
}
override def beforeAll(): Unit = {
- val dir = AbsolutePath(scalafix.tests.BuildInfo.semanticClasspath)
+ val dirs =
+ scalafix.tests.BuildInfo.semanticClasspath.map(AbsolutePath.apply)
_db = LegacyInMemorySemanticdbIndex.load(
- Classpaths.withDirectory(dir),
+ Classpaths.withDirectories(dirs.toList),
PathIO.workingDirectory
)
_input = _db.inputs
diff --git a/scalafix-tests/unit/src/test/scala/scalafix/tests/core/PrettyTypeSuite.scala b/scalafix-tests/unit/src/test/scala/scalafix/tests/core/PrettyTypeSuite.scala
index 3b02ec4dc..a518f2e49 100644
--- a/scalafix-tests/unit/src/test/scala/scalafix/tests/core/PrettyTypeSuite.scala
+++ b/scalafix-tests/unit/src/test/scala/scalafix/tests/core/PrettyTypeSuite.scala
@@ -24,11 +24,11 @@ class BasePrettyTypeSuite extends BaseSemanticSuite("TypeToTreeInput") {
super.beforeAll()
val classDir: m.AbsolutePath =
m.AbsolutePath(scalafix.tests.BuildInfo.sharedClasspath)
- val semanticdbTargetRoot: AbsolutePath =
- m.AbsolutePath(scalafix.tests.BuildInfo.semanticClasspath)
+ val semanticdbTargetRoots: List[AbsolutePath] =
+ scalafix.tests.BuildInfo.semanticClasspath.map(m.AbsolutePath.apply).toList
val classpath: Classpath =
- Classpaths.withDirectories(List(semanticdbTargetRoot, classDir))
+ Classpaths.withDirectories(semanticdbTargetRoots :+ classDir)
val table: GlobalSymbolTable = GlobalSymbolTable(classpath, includeJdk = true)
}