summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-27 17:25:16 +0300
committerEugene Burmako <xeno.by@gmail.com>2014-02-15 09:23:58 +0100
commit1dda1760113f782ffbcf10f0ca7b9e4f8817a62a (patch)
treebe926837dc9b6afd0c02ca3d536b1051e3e810d2 /src/reflect
parentd7b6662ddd346d0a4dc12ea62a3392ac176bf271 (diff)
downloadscala-1dda1760113f782ffbcf10f0ca7b9e4f8817a62a.tar.gz
scala-1dda1760113f782ffbcf10f0ca7b9e4f8817a62a.tar.bz2
scala-1dda1760113f782ffbcf10f0ca7b9e4f8817a62a.zip
SI-7044 deprecates Symbol.associatedFile
Before this commit, Symbol.associatedFile used to be broken in two ways. Firstly, it was never autoloaded (just like we used to have flags, privateWithin and annotations). Secondly, it was never filled in by runtime reflection. My first attempt at fixing those problems was, well, just fixing them. However, its runtime implementation was based on a hacky function that we were not very much excited about supported (see comments), whereas its compile-time usefulness was somewhat questionable. Therefore the second attempt at fixing this bug is deprecating the API altogether, replacing it with `Symbol.pos.source`. Since `Symbol.pos` isn't retained for runtime consumption, `Symbol.pos.source` is still going to return `NoAbstractFile` as before this commit, but that's left for future work, and suggested approach is documented in SI-8259.
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/scala/reflect/api/Symbols.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala6
-rw-r--r--src/reflect/scala/reflect/io/NoAbstractFile.scala1
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala9
-rw-r--r--src/reflect/scala/reflect/runtime/ReflectionUtils.scala71
5 files changed, 86 insertions, 2 deletions
diff --git a/src/reflect/scala/reflect/api/Symbols.scala b/src/reflect/scala/reflect/api/Symbols.scala
index 22039d22b6..ff7ac3f574 100644
--- a/src/reflect/scala/reflect/api/Symbols.scala
+++ b/src/reflect/scala/reflect/api/Symbols.scala
@@ -280,6 +280,7 @@ trait Symbols { self: Universe =>
*
* @group Basics
*/
+ @deprecated("Use `pos.source.file` instead", "2.11.0")
def associatedFile: scala.reflect.io.AbstractFile
/** A list of annotations attached to this Symbol.
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 35c7a59683..5e81badfad 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -3166,8 +3166,10 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def associatedFile = (
if (!isTopLevel) super.associatedFile
- else if (_associatedFile eq null) NoAbstractFile // guarantee not null, but save cost of initializing the var
- else _associatedFile
+ else {
+ if (_associatedFile eq null) NoAbstractFile // guarantee not null, but save cost of initializing the var
+ else _associatedFile
+ }
)
override def associatedFile_=(f: AbstractFile) { _associatedFile = f }
diff --git a/src/reflect/scala/reflect/io/NoAbstractFile.scala b/src/reflect/scala/reflect/io/NoAbstractFile.scala
index a4e869ed41..18eca7698d 100644
--- a/src/reflect/scala/reflect/io/NoAbstractFile.scala
+++ b/src/reflect/scala/reflect/io/NoAbstractFile.scala
@@ -31,4 +31,5 @@ object NoAbstractFile extends AbstractFile {
def output: java.io.OutputStream = null
def path: String = ""
override def toByteArray = Array[Byte]()
+ override def toString = "<no file>"
}
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index 1c942e8858..de0ad7161b 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -614,6 +614,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
info(s"unpickling Scala $clazz and $module, owner = ${clazz.owner}")
val bytes = ssig.getBytes
val len = ByteCodecs.decode(bytes)
+ assignAssociatedFile(clazz, module, jclazz)
unpickler.unpickle(bytes take len, 0, clazz, module, jclazz.getName)
markAllCompleted(clazz, module)
case None =>
@@ -623,6 +624,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
val encoded = slsig flatMap (_.getBytes)
val len = ByteCodecs.decode(encoded)
val decoded = encoded.take(len)
+ assignAssociatedFile(clazz, module, jclazz)
unpickler.unpickle(decoded, 0, clazz, module, jclazz.getName)
markAllCompleted(clazz, module)
case None =>
@@ -664,6 +666,12 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
}
}
+ private def assignAssociatedFile(clazz: Symbol, module: Symbol, jclazz: jClass[_]): Unit = {
+ val associatedFile = ReflectionUtils.associatedFile(jclazz)
+ clazz.associatedFile = associatedFile
+ if (module != NoSymbol) module.associatedFile = associatedFile
+ }
+
/**
* Copy all annotations of Java annotated element `jann` over to Scala symbol `sym`.
* Also creates `@throws` annotations if necessary.
@@ -719,6 +727,7 @@ private[scala] trait JavaMirrors extends internal.SymbolTable with api.JavaUnive
debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug
assert(sym == clazz || (module != NoSymbol && (sym == module || sym == module.moduleClass)), sym)
+ assignAssociatedFile(clazz, module, jclazz)
propagatePackageBoundary(jclazz, relatedSymbols: _*)
copyAnnotations(clazz, jclazz)
// to do: annotations to set also for module?
diff --git a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
index d642b25127..a4bd698068 100644
--- a/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
+++ b/src/reflect/scala/reflect/runtime/ReflectionUtils.scala
@@ -9,6 +9,8 @@ package reflect.runtime
import java.lang.{Class => jClass}
import java.lang.reflect.{ Method, InvocationTargetException, UndeclaredThrowableException }
import scala.reflect.internal.util.AbstractFileClassLoader
+import scala.reflect.io._
+import java.io.{File => JFile}
/** A few java-reflection oriented utility functions useful during reflection bootstrapping.
*/
@@ -97,5 +99,74 @@ object ReflectionUtils {
object EnclosedInConstructor extends EnclosedIn(_.getEnclosingConstructor)
object EnclosedInClass extends EnclosedIn(_.getEnclosingClass)
object EnclosedInPackage extends EnclosedIn(_.getPackage)
+
+ def associatedFile(clazz: Class[_]): AbstractFile = {
+ // TODO: I agree with Jason - this implementation isn't something that we'd like to support
+ // therefore I'm having it commented out and this function will now return NoAbstractFile
+ // I think we can keep the source code though, because it can be useful to the others
+ //
+ // def inferAssociatedFile(clazz: Class[_]): AbstractFile = {
+ // // http://stackoverflow.com/questions/227486/find-where-java-class-is-loaded-from
+ // try {
+ // var cl = clazz.getClassLoader()
+ // if (cl == null) {
+ // cl = ClassLoader.getSystemClassLoader()
+ // while (cl != null && cl.getParent != null) cl = cl.getParent
+ // }
+ // var result: AbstractFile = null
+ // if (cl != null) {
+ // val name = clazz.getCanonicalName()
+ // val resource = cl.getResource(name.replace(".", "/") + ".class")
+ // if (resource != null) {
+ // def fromFile(file: String) = AbstractFile.getFile(file)
+ // def fromJarEntry(jarfile: String, entrypath: String) = {
+ // val jar = fromFile(jarfile)
+ // new VirtualFile(clazz.getName, entrypath) {
+ // lazy val impl: AbstractFile = {
+ // def loop(root: AbstractFile, path: List[String]): AbstractFile = {
+ // def find(name: String) = root.iterator.find(_.name == name).getOrElse(NoAbstractFile)
+ // path match {
+ // case step :: Nil => find(step)
+ // case step :: rest => loop(find(step), rest)
+ // case Nil => NoAbstractFile
+ // }
+ // }
+ // loop(ZipArchive.fromFile(new JFile(jarfile)), entrypath.split("/").toList)
+ // }
+ // override def container = impl.container
+ // override def lastModified = impl.lastModified
+ // override def input = impl.input
+ // override def sizeOption = impl.sizeOption
+ // override def underlyingSource = Some(jar)
+ // override def toString = jarfile + "(" + entrypath + ")"
+ // }
+ // }
+ // def fallback() = new VirtualFile(clazz.getName, resource.toString)
+ // result = resource.getProtocol match {
+ // case "file" =>
+ // fromFile(resource.getFile)
+ // case "jar" =>
+ // val intrajarUrl = new java.net.URL(resource.getFile)
+ // intrajarUrl.getProtocol match {
+ // case "file" =>
+ // val file = intrajarUrl.getFile()
+ // val expectedSuffix = "!/" + name.replace(".", "/") + ".class"
+ // if (file.endsWith(expectedSuffix)) fromJarEntry(file.stripSuffix(expectedSuffix), expectedSuffix.substring(2))
+ // else fallback()
+ // case _ => fallback()
+ // }
+ // case _ =>
+ // fallback()
+ // }
+ // }
+ // }
+ // if (result != null) result else NoAbstractFile
+ // } catch {
+ // case _: Exception => NoAbstractFile
+ // }
+ // }
+ // inferAssociatedFile(clazz)
+ NoAbstractFile
+ }
}