diff options
-rw-r--r-- | src/reflect/scala/reflect/api/Symbols.scala | 1 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Symbols.scala | 6 | ||||
-rw-r--r-- | src/reflect/scala/reflect/io/NoAbstractFile.scala | 1 | ||||
-rw-r--r-- | src/reflect/scala/reflect/runtime/JavaMirrors.scala | 9 | ||||
-rw-r--r-- | src/reflect/scala/reflect/runtime/ReflectionUtils.scala | 71 | ||||
-rw-r--r-- | test/files/run/t7044.check | 14 | ||||
-rw-r--r-- | test/files/run/t7044/Macros_1.scala | 26 | ||||
-rw-r--r-- | test/files/run/t7044/Test_2.scala | 19 |
8 files changed, 145 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 + } } diff --git a/test/files/run/t7044.check b/test/files/run/t7044.check new file mode 100644 index 0000000000..ab523873bf --- /dev/null +++ b/test/files/run/t7044.check @@ -0,0 +1,14 @@ +compile-time +uninitialized File: <no file> +initialized File: <no file> +uninitialized BitSet: <no file> +initialized BitSet: <no file> +uninitialized C: Test_2.scala +initialized C: Test_2.scala +runtime +autoinitialized File: <no file> true +autoinitialized File: <no file> true +autoinitialized BitSet: <no file> true +autoinitialized BitSet: <no file> true +autoinitialized C: <no file> true +autoinitialized C: <no file> true diff --git a/test/files/run/t7044/Macros_1.scala b/test/files/run/t7044/Macros_1.scala new file mode 100644 index 0000000000..3b3f8c3385 --- /dev/null +++ b/test/files/run/t7044/Macros_1.scala @@ -0,0 +1,26 @@ +import scala.reflect.macros.whitebox._ +import scala.language.experimental.macros + +object Macros { + def impl(c: Context) = { + var messages = List[String]() + def println(msg: String) = messages :+= msg + + import c.universe._ + def test(tpe: Type): Unit = { + val sym = tpe.typeSymbol + println(s"uninitialized ${sym.name}: ${sym.pos.source.file.name}") + internal.initialize(sym) + println(s"initialized ${sym.name}: ${sym.pos.source.file.name}") + } + + println("compile-time") + test(typeOf[java.io.File]) + test(typeOf[scala.collection.BitSet]) + test(c.mirror.staticClass("C").toType) + + q"..${messages.map(msg => q"println($msg)")}" + } + + def foo: Any = macro impl +}
\ No newline at end of file diff --git a/test/files/run/t7044/Test_2.scala b/test/files/run/t7044/Test_2.scala new file mode 100644 index 0000000000..8dfb349086 --- /dev/null +++ b/test/files/run/t7044/Test_2.scala @@ -0,0 +1,19 @@ +import scala.reflect.runtime.universe._ +import scala.reflect.runtime.{currentMirror => cm} + +class C + +object Test extends App { + def test(tpe: Type): Unit = { + val sym = tpe.typeSymbol + println(s"autoinitialized ${sym.name}: ${sym.pos.source.file.name} ${sym.pos.source.file.sizeOption.nonEmpty}") + internal.initialize(sym) + println(s"autoinitialized ${sym.name}: ${sym.pos.source.file.name} ${sym.pos.source.file.sizeOption.nonEmpty}") + } + + Macros.foo + println("runtime") + test(typeOf[java.io.File]) + test(typeOf[scala.collection.BitSet]) + test(typeOf[C]) +} |