Skip to content

Commit 8fa5c5c

Browse files
Merge pull request #8220 from gzoller/i8215_java_inspector
Fix #8215 Add ability to detect attempted Tasty inspection of a Java class
2 parents 0dc07b0 + 22d56f3 commit 8fa5c5c

File tree

7 files changed

+97
-1
lines changed

7 files changed

+97
-1
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dotty.tools.dotc.fromtasty
2+
3+
import dotty.tools.dotc.CompilationUnit
4+
import dotty.tools.dotc.util.NoSource
5+
6+
/** A marker CompilationUnit to return up the call stack from ReadTasty. This will tell us that we've
7+
* encountered, and attempted to inspect, a Java class file. We can't TASTy-inspect a Java class obviously,
8+
* but we want to return the fact we found it so that higher-up we can take appropriate action if desired.
9+
*/
10+
class JavaCompilationUnit(val className: String) extends CompilationUnit(NoSource) {
11+
override def toString: String = s"Java class file $className"
12+
}

compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ class ReadTasty extends Phase {
4848
Some(unit)
4949
}
5050
case tree: Tree[?] =>
51-
alreadyLoaded()
51+
cls.denot.infoOrCompleter match {
52+
case _: NoLoader => Some(Scala2CompilationUnit(cls.fullName.toString))
53+
case _ if cls.flags.is(Flags.JavaDefined) => Some(JavaCompilationUnit(cls.fullName.toString))
54+
case _ => alreadyLoaded()
55+
}
5256
case _ =>
5357
cannotUnpickle(s"its class file does not have a TASTY attribute")
5458
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package dotty.tools.dotc.fromtasty
2+
3+
import dotty.tools.dotc.CompilationUnit
4+
import dotty.tools.dotc.util.NoSource
5+
6+
/** A marker CompilationUnit to return up the call stack from ReadTasty. This will tell us that we've
7+
* encountered, and attempted to inspect, a Scala2 class file (which has no .tasty file).
8+
* In this case we still want to return the fact we found it so that higher-up we can take appropriate
9+
* action if desired.
10+
*/
11+
class Scala2CompilationUnit(val className: String) extends CompilationUnit(NoSource) {
12+
override def toString: String = s"Scala2 class file $className"
13+
}

compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
6565
def Context_requiredClass(self: Context)(path: String): Symbol = self.requiredClass(path)
6666
def Context_requiredModule(self: Context)(path: String): Symbol = self.requiredModule(path)
6767
def Context_requiredMethod(self: Context)(path: String): Symbol = self.requiredMethod(path)
68+
def Context_isJavaCompilationUnit(self: Context): Boolean = self.compilationUnit.isInstanceOf[fromtasty.JavaCompilationUnit]
69+
def Context_isScala2CompilationUnit(self: Context): Boolean = self.compilationUnit.isInstanceOf[fromtasty.Scala2CompilationUnit]
70+
def Context_compilationUnitClassname(self: Context): String =
71+
self.compilationUnit match {
72+
case cu: fromtasty.JavaCompilationUnit => cu.className
73+
case cu: fromtasty.Scala2CompilationUnit => cu.className
74+
case cu => ""
75+
}
6876

6977

7078
///////////////

library/src/scala/tasty/Reflection.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,14 @@ class Reflection(private[scala] val internal: CompilerInterface) { self =>
473473
/** Get method symbol if method is either defined in current compilation run or present on classpath. Throws if the method has an overload. */
474474
def requiredMethod(path: String): Symbol = internal.Context_requiredMethod(self)(path)
475475

476+
/** Returns true if we've tried to reflect on a Java class. */
477+
def isJavaCompilationUnit(): Boolean = internal Context_isJavaCompilationUnit(self)
478+
479+
/** Returns true if we've tried to reflect on a Scala2 (non-Tasty) class. */
480+
def isScala2CompilationUnit(): Boolean = internal Context_isScala2CompilationUnit(self)
481+
482+
/** Class name of the current CompilationUnit */
483+
def compilationUnitClassname(): String = internal.Context_compilationUnitClassname(self)
476484
}
477485

478486

library/src/scala/tasty/reflect/CompilerInterface.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ trait CompilerInterface {
162162
/** Get method symbol if method is either defined in current compilation run or present on classpath. Throws if the method has an overload. */
163163
def Context_requiredMethod(self: Context)(path: String): Symbol
164164

165+
/** Returns true if we've tried to reflect on a Java class. */
166+
def Context_isJavaCompilationUnit(self: Context): Boolean
167+
168+
/** Returns true if we've tried to reflect on a Scala2 (non-Tasty) class. */
169+
def Context_isScala2CompilationUnit(self: Context): Boolean
170+
171+
/** Class name of the current CompilationUnit */
172+
def Context_compilationUnitClassname(self: Context): String
173+
165174

166175
///////////////
167176
// REPORTING //
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import scala.tasty.Reflection
2+
import scala.tasty.inspector._
3+
4+
case class I8215(id: String)
5+
6+
object Test {
7+
def main(args: Array[String]): Unit = {
8+
9+
// Tasty Scala Class
10+
val inspect1 = new TestInspector_NonTasty()
11+
inspect1.inspect("", List("I8215"))
12+
assert(inspect1.isJava == false)
13+
assert(inspect1.isScala2 == false)
14+
assert(inspect1.className == "")
15+
16+
// Java Class
17+
val inspect2 = new TestInspector_NonTasty()
18+
inspect2.inspect("", List("java.util.UUID"))
19+
assert(inspect2.isJava == true)
20+
assert(inspect2.isScala2 == false)
21+
assert(inspect2.className == "java.util.UUID")
22+
23+
// Legacy non-Tasty Scala class
24+
val inspect3 = new TestInspector_NonTasty()
25+
inspect3.inspect("", List("scala.collection.immutable.RedBlackTree"))
26+
assert(inspect3.isJava == false)
27+
assert(inspect3.isScala2 == true)
28+
assert(inspect3.className == "scala.collection.immutable.RedBlackTree")
29+
}
30+
}
31+
32+
class TestInspector_NonTasty() extends TastyInspector:
33+
34+
var isJava: Boolean = false
35+
var isScala2: Boolean = false
36+
var className: String = ""
37+
38+
protected def processCompilationUnit(reflect: Reflection)(root: reflect.Tree): Unit =
39+
import reflect.{_, given _}
40+
isJava = reflect.rootContext.isJavaCompilationUnit()
41+
isScala2 = reflect.rootContext.isScala2CompilationUnit()
42+
className = reflect.rootContext.compilationUnitClassname()

0 commit comments

Comments
 (0)