Skip to content

Fix #8215 Add ability to detect attempted Tasty inspection of a Java class #8220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions compiler/src/dotty/tools/dotc/fromtasty/JavaCompilationUnit.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dotty.tools.dotc.fromtasty

import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.util.NoSource

/** A marker CompilationUnit to return up the call stack from ReadTasty. This will tell us that we've
* encountered, and attempted to inspect, a Java class file. We can't TASTy-inspect a Java class obviously,
* but we want to return the fact we found it so that higher-up we can take appropriate action if desired.
*/
class JavaCompilationUnit(val className: String) extends CompilationUnit(NoSource) {
override def toString: String = s"Java class file $className"
}
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/fromtasty/ReadTasty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ class ReadTasty extends Phase {
Some(unit)
}
case tree: Tree[?] =>
alreadyLoaded()
cls.denot.infoOrCompleter match {
case _: NoLoader => Some(Scala2CompilationUnit(cls.fullName.toString))
case _ if cls.flags.is(Flags.JavaDefined) => Some(JavaCompilationUnit(cls.fullName.toString))
case _ => alreadyLoaded()
}
case _ =>
cannotUnpickle(s"its class file does not have a TASTY attribute")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dotty.tools.dotc.fromtasty

import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.util.NoSource

/** A marker CompilationUnit to return up the call stack from ReadTasty. This will tell us that we've
* encountered, and attempted to inspect, a Scala2 class file (which has no .tasty file).
* In this case we still want to return the fact we found it so that higher-up we can take appropriate
* action if desired.
*/
class Scala2CompilationUnit(val className: String) extends CompilationUnit(NoSource) {
override def toString: String = s"Scala2 class file $className"
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
def Context_requiredClass(self: Context)(path: String): Symbol = self.requiredClass(path)
def Context_requiredModule(self: Context)(path: String): Symbol = self.requiredModule(path)
def Context_requiredMethod(self: Context)(path: String): Symbol = self.requiredMethod(path)
def Context_isJavaCompilationUnit(self: Context): Boolean = self.compilationUnit.isInstanceOf[fromtasty.JavaCompilationUnit]
def Context_isScala2CompilationUnit(self: Context): Boolean = self.compilationUnit.isInstanceOf[fromtasty.Scala2CompilationUnit]
def Context_compilationUnitClassname(self: Context): String =
self.compilationUnit match {
case cu: fromtasty.JavaCompilationUnit => cu.className
case cu: fromtasty.Scala2CompilationUnit => cu.className
case cu => ""
}


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

/** Returns true if we've tried to reflect on a Java class. */
def isJavaCompilationUnit(): Boolean = internal Context_isJavaCompilationUnit(self)

/** Returns true if we've tried to reflect on a Scala2 (non-Tasty) class. */
def isScala2CompilationUnit(): Boolean = internal Context_isScala2CompilationUnit(self)

/** Class name of the current CompilationUnit */
def compilationUnitClassname(): String = internal.Context_compilationUnitClassname(self)
}


Expand Down
9 changes: 9 additions & 0 deletions library/src/scala/tasty/reflect/CompilerInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ trait CompilerInterface {
/** Get method symbol if method is either defined in current compilation run or present on classpath. Throws if the method has an overload. */
def Context_requiredMethod(self: Context)(path: String): Symbol

/** Returns true if we've tried to reflect on a Java class. */
def Context_isJavaCompilationUnit(self: Context): Boolean

/** Returns true if we've tried to reflect on a Scala2 (non-Tasty) class. */
def Context_isScala2CompilationUnit(self: Context): Boolean

/** Class name of the current CompilationUnit */
def Context_compilationUnitClassname(self: Context): String


///////////////
// REPORTING //
Expand Down
42 changes: 42 additions & 0 deletions tests/run-custom-args/tasty-inspector/i8215.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import scala.tasty.Reflection
import scala.tasty.inspector._

case class I8215(id: String)

object Test {
def main(args: Array[String]): Unit = {

// Tasty Scala Class
val inspect1 = new TestInspector_NonTasty()
inspect1.inspect("", List("I8215"))
assert(inspect1.isJava == false)
assert(inspect1.isScala2 == false)
assert(inspect1.className == "")

// Java Class
val inspect2 = new TestInspector_NonTasty()
inspect2.inspect("", List("java.util.UUID"))
assert(inspect2.isJava == true)
assert(inspect2.isScala2 == false)
assert(inspect2.className == "java.util.UUID")

// Legacy non-Tasty Scala class
val inspect3 = new TestInspector_NonTasty()
inspect3.inspect("", List("scala.collection.immutable.RedBlackTree"))
assert(inspect3.isJava == false)
assert(inspect3.isScala2 == true)
assert(inspect3.className == "scala.collection.immutable.RedBlackTree")
}
}

class TestInspector_NonTasty() extends TastyInspector:

var isJava: Boolean = false
var isScala2: Boolean = false
var className: String = ""

protected def processCompilationUnit(reflect: Reflection)(root: reflect.Tree): Unit =
import reflect.{_, given _}
isJava = reflect.rootContext.isJavaCompilationUnit()
isScala2 = reflect.rootContext.isScala2CompilationUnit()
className = reflect.rootContext.compilationUnitClassname()