diff --git a/OPAL/ba/src/test/scala/org/opalj/ba/FieldBuilderTest.scala b/OPAL/ba/src/test/scala/org/opalj/ba/FieldBuilderTest.scala index 78e1b05c0f..e878a1c760 100644 --- a/OPAL/ba/src/test/scala/org/opalj/ba/FieldBuilderTest.scala +++ b/OPAL/ba/src/test/scala/org/opalj/ba/FieldBuilderTest.scala @@ -3,8 +3,6 @@ package org.opalj package ba import scala.language.postfixOps -import scala.reflect.classTag -import scala.reflect.runtime.universe.* import java.io.ByteArrayInputStream @@ -88,8 +86,8 @@ class FieldBuilderTest extends AnyFlatSpec { this.getClass.getClassLoader ) - val fieldInstance = loader.loadClass(javaClassName).getDeclaredConstructor().newInstance() - val mirror = runtimeMirror(loader).reflect(fieldInstance)(using classTag[AnyRef]) + val clazz = loader.loadClass(javaClassName) + val fieldInstance = clazz.getDeclaredConstructor().newInstance() val brClassFile = Java8Framework.ClassFile(() => new ByteArrayInputStream(rawClassFile)).head @@ -101,13 +99,14 @@ class FieldBuilderTest extends AnyFlatSpec { } "the field `FieldClass.privateField`" should "be initialized as true" in { - val field = mirror.symbol.typeSignature.member(TermName("privateField")).asTerm - assert(mirror.reflectField(field).get == true) + val field = clazz.getDeclaredField("privateField") + field.setAccessible(true) + assert(field.get(fieldInstance) == true) } "FieldClass.publicField" should "be initialized as 3" in { - val field = mirror.symbol.typeSignature.member(TermName("publicField")).asTerm - assert(mirror.reflectField(field).get == 3) + val field = clazz.getDeclaredField("publicField") + assert(field.get(fieldInstance) == 3) } } diff --git a/OPAL/ba/src/test/scala/org/opalj/ba/JumpLabelsTest.scala b/OPAL/ba/src/test/scala/org/opalj/ba/JumpLabelsTest.scala index 66990ce5ae..4cda94b6a7 100644 --- a/OPAL/ba/src/test/scala/org/opalj/ba/JumpLabelsTest.scala +++ b/OPAL/ba/src/test/scala/org/opalj/ba/JumpLabelsTest.scala @@ -3,8 +3,6 @@ package org.opalj package ba import scala.language.postfixOps -import scala.reflect.classTag -import scala.reflect.runtime.universe.* import java.io.ByteArrayInputStream @@ -83,13 +81,12 @@ class JumpLabelsTest extends AnyFlatSpec { def testClass(clazz: Class[?]): Unit = { val testJumpInstance = clazz.getDeclaredConstructor().newInstance() - val mirror = runtimeMirror(loader).reflect(testJumpInstance)(using classTag[AnyRef]) - val method = mirror.symbol.typeSignature.member(TermName("returnInt")).asMethod + val method = clazz.getMethod("returnInt", classOf[Int]) - assert(mirror.reflectMethod(method)(0) == 0) - assert(mirror.reflectMethod(method)(1) == 1) - assert(mirror.reflectMethod(method)(2) == 2) - assert(mirror.reflectMethod(method)(10) == 10) + assert(method.invoke(testJumpInstance, 0) == 0) + assert(method.invoke(testJumpInstance, 1) == 1) + assert(method.invoke(testJumpInstance, 2) == 2) + assert(method.invoke(testJumpInstance, 10) == 10) } testClass(loader.loadClass("TestJumpJava5")) diff --git a/OPAL/ba/src/test/scala/org/opalj/ba/MethodBuilderTest.scala b/OPAL/ba/src/test/scala/org/opalj/ba/MethodBuilderTest.scala index 6e7e0d7b7d..b4c6263fb5 100644 --- a/OPAL/ba/src/test/scala/org/opalj/ba/MethodBuilderTest.scala +++ b/OPAL/ba/src/test/scala/org/opalj/ba/MethodBuilderTest.scala @@ -3,8 +3,6 @@ package org.opalj package ba import scala.language.postfixOps -import scala.reflect.classTag -import scala.reflect.runtime.universe.* import java.io.ByteArrayInputStream import scala.collection.immutable.ArraySeq @@ -59,10 +57,9 @@ class MethodBuilderTest extends AnyFlatSpec { val simpleMethodClazz = loader.loadClass("SimpleMethodClass") val simpleMethodInstance = simpleMethodClazz.getDeclaredConstructor().newInstance() - val mirror = runtimeMirror(loader).reflect(simpleMethodInstance)(using classTag[AnyRef]) - val method = mirror.symbol.typeSignature.member(TermName("testMethod")).asMethod + val method = simpleMethodClazz.getMethod("testMethod", classOf[String]) - assert(mirror.reflectMethod(method)("test") == null) + assert(method.invoke(simpleMethodInstance, "test") == null) } val brClassFile = J8ClassFile(() => new java.io.ByteArrayInputStream(rawClassFile)).head @@ -205,11 +202,10 @@ class MethodBuilderTest extends AnyFlatSpec { try { val attributeMethodClass = loader.loadClass("AttributeMethodClass") val attributeTestInstance = attributeMethodClass.getDeclaredConstructor().newInstance() - val mirror = runtimeMirror(loader).reflect(attributeTestInstance)(using classTag[AnyRef]) - val method = mirror.symbol.typeSignature.member(TermName("tryCatchFinallyTest")).asMethod - assert(mirror.reflectMethod(method)(-1) == 0) - assert(mirror.reflectMethod(method)(0) == 1) - assert(mirror.reflectMethod(method)(1) == 2) + val method = attributeMethodClass.getDeclaredMethod("tryCatchFinallyTest", classOf[Int]) + assert(method.invoke(attributeTestInstance, -1) == 0) + assert(method.invoke(attributeTestInstance, 0) == 1) + assert(method.invoke(attributeTestInstance, 1) == 2) } catch { case t: Throwable => info( diff --git a/OPAL/br/src/main/scala/org/opalj/br/fpcf/cli/ProjectBasedCommandLineConfig.scala b/OPAL/br/src/main/scala/org/opalj/br/fpcf/cli/ProjectBasedCommandLineConfig.scala index 75fbf51304..46dafad0e7 100644 --- a/OPAL/br/src/main/scala/org/opalj/br/fpcf/cli/ProjectBasedCommandLineConfig.scala +++ b/OPAL/br/src/main/scala/org/opalj/br/fpcf/cli/ProjectBasedCommandLineConfig.scala @@ -5,7 +5,6 @@ package fpcf package cli import scala.language.postfixOps -import scala.reflect.internal.util.NoPosition.showError import java.io.File import java.net.URL @@ -102,7 +101,7 @@ trait ProjectBasedCommandLineConfig extends OPALCommandLineConfig { val cpFiles = resolveDirToCP(get(ProjectDirectoryArg), cp, cp) if (cpFiles.isEmpty) { - showError("Nothing to analyze.") + error("fatal", "Nothing to analyze.") printHelp() sys.exit(1) } diff --git a/OPAL/common/src/main/scala/org/opalj/util/package.scala b/OPAL/common/src/main/scala/org/opalj/util/package.scala index 4f7d8e9b5b..a14afa0c21 100644 --- a/OPAL/common/src/main/scala/org/opalj/util/package.scala +++ b/OPAL/common/src/main/scala/org/opalj/util/package.scala @@ -124,14 +124,27 @@ package object util { def getObjectReflectively[A](fqn: String, source: AnyRef, category: String = "configuration")(implicit logContext: LogContext = GlobalLogContext ): Option[A] = { - import scala.reflect.runtime.universe._ + // Ensure fully qualified name of singleton object ends with dollar symbol + val fqnObject = if (fqn.endsWith("$")) fqn else fqn + "$" + try { - val mirror = runtimeMirror(source.getClass.getClassLoader) - val module = mirror.staticModule(fqn) - Some(mirror.reflectModule(module).instance.asInstanceOf[A]) + // Get the class loader from the source object + val classLoader = source.getClass.getClassLoader + + // Get class from class loader + val clazz = Class.forName(fqnObject, true, classLoader) + + // Access the singleton instance field + val moduleField = clazz.getField("MODULE$") + + // Read the static field (passing null because it is a static field) + Some(moduleField.get(null).asInstanceOf[A]) } catch { - case sre: ScalaReflectionException => - error(category, s"Cannot find object $fqn", sre) + case sre: ClassNotFoundException => + error(category, s"Cannot find object $fqnObject", sre) + None + case nsfe: NoSuchFieldException => + error(category, "Singleton instance field not found", nsfe) None case cce: ClassCastException => error(category, "Reflected object is invalid", cce) diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/escape/ConfigurationBasedConstructorEscapeAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/escape/ConfigurationBasedConstructorEscapeAnalysis.scala index f9de58a452..2b1aa937f6 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/escape/ConfigurationBasedConstructorEscapeAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/escape/ConfigurationBasedConstructorEscapeAnalysis.scala @@ -35,10 +35,17 @@ trait ConfigurationBasedConstructorEscapeAnalysis extends AbstractEscapeAnalysis */ private val predefinedConstructors: Map[ClassType, EscapeProperty] = { ConfigSource.fromConfig(project.config).at(ConfigKey).loadOrThrow[Seq[PredefinedResult]].map { r => - import scala.reflect.runtime.* - val rootMirror = universe.runtimeMirror(getClass.getClassLoader) - val module = rootMirror.staticModule(r.escapeOfThis) - val property = rootMirror.reflectModule(module).instance.asInstanceOf[EscapeProperty] + // 1. Get the ClassLoader + val classLoader = this.getClass.getClassLoader + + // 2. Load the companion object or module class + // Note: Scala modules (object) compiled to Java have a '$' suffix + val moduleClass = classLoader.loadClass(r.escapeOfThis + "$") + + // 3. Access the singleton instance via the MODULE$ field + val moduleField = moduleClass.getField("MODULE$") + val property = moduleField.get(null).asInstanceOf[EscapeProperty] + (ClassType(r.classType), property) }.toMap } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index de7b446be9..65875f6236 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -42,8 +42,6 @@ object Dependencies { case _ => throw new Exception("Unknown platform!") } - def reflect(scalaVersion: String): ModuleID = "org.scala-lang" % "scala-reflect" % "2.13.16" // scalaVersion No scala-reflect available for Scala 3 - val scalaxml = "org.scala-lang.modules" %% "scala-xml" % version.scalaxml val scalaparallelcollections = "org.scala-lang.modules" %% "scala-parallel-collections" % version.scalaparallelcollections @@ -72,7 +70,7 @@ object Dependencies { val testlibs: Seq[ModuleID] = Seq(junit, scalatest, scalatestjunit, scalacheck) def common(scalaVersion: String) = - Seq(reflect(scalaVersion), scalaparallelcollections, scalaxml, playjson, ficus, pureconfig, fastutil, scallop) + Seq(scalaparallelcollections, scalaxml, playjson, ficus, pureconfig, fastutil, scallop) val si = Seq(scalagraphcore, scalagraphdot) val bi = Seq(commonstext)