There is such a premise.
organization: "com.xxx"
project A
com.xxx.a.aa
com.xxx.a.mm
project B dependsOn A
com.xxx.b.bb
com.xxx.b.nn
com.xxx.b.runtime
Extractor.scala
project C dependsOn B
com.xxx.c.cc
com.xxx.c.oo
com.xxx.c
Main.scala
Extractor.scala loads the classpath under the package _root_
and tries type checking.
def run(): Vector[universe.Symbol] = {
recursivePackageExplore(
Vector(rootPackage)
)
}
private final def rootPackage: universe.Symbol = universe.runtimeMirror(getClass.getClassLoader).RootPackage.info.typeSymbol
@tailrec
private final def recursivePackageExplore(selfPackages: Vector[universe.Symbol],
result: Vector[universe.Symbol] = Vector.empty): Vector[universe.Symbol] = {
selfPackages match {
case x if x.isEmpty => result
case _ =>
val (packages, modules) = selfPackages.flatMap(_.typeSignature.members).distinct.collect {
case x if selfPackages.contains(x) =>
None -> None
case x if x.isPackage =>
Some(x) -> None
case x if x.isModule && !x.toString.startsWith("package object") && !x.isAbstract =>
None -> Some(x)
} match {
case x => x.flatMap(_._1) -> x.flatMap(_._2)
}
recursivePackageExplore(
packages,
result ++ recursiveModuleExplore(modules)
)
}
}
@tailrec
private final def recursiveModuleExplore(n: Vector[universe.Symbol],
result: Vector[universe.Symbol] = Vector.empty): Vector[universe.Symbol] = {
n match {
case accessibleSymbol if accessibleSymbol.isEmpty => result
case accessibleSymbol =>
recursiveModuleExplore(
accessibleSymbol.withFilter(_.isModule).flatMap(_.typeSignature.members).collect {
case x if x.isModule => x
},
result ++ accessibleSymbol.filter(_.accepted))
}
}
When I ran the Extractor from Main, I expected that most classes under project A, B and C would be returned in result. However, it seems that only classes of some packages under project B could actually be detected.
This works as expected if you set the run
function to macro. In the case of runtime reflection, Symbol(package).typeSignature.members
was considered to load the classpath. Did I make a mistake?