diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala | 41 | ||||
-rw-r--r-- | test/files/jvm/throws-annot.check | 21 | ||||
-rw-r--r-- | test/files/jvm/throws-annot.scala | 74 |
3 files changed, 122 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index b7b2e9c754..570d13188b 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -279,13 +279,10 @@ abstract class GenJVM extends SubComponent { informProgress("wrote BeanInfo " + outfile) } - def addExceptionsAttribute(sym: Symbol) { - val (excs, others) = sym.attributes.partition((a => a match { - case AnnotationInfo(tp, _, _) if tp.typeSymbol == ThrowsAttr => true - case _ => false - })) - if (excs isEmpty) return; - sym.attributes = others + + /** Add the given 'throws' attributes to jmethod */ + def addExceptionsAttribute(jmethod: JMethod, excs: List[AnnotationInfo]) { + if (excs.isEmpty) return val cpool = jmethod.getConstantPool() val buf: ByteBuffer = ByteBuffer.allocate(512) @@ -313,8 +310,8 @@ abstract class GenJVM extends SubComponent { annot.isConstant) - private def emitAttributes(buf: ByteBuffer, attributes: List[AnnotationInfo]): Int = { - val cpool = jclass.getConstantPool() + private def emitAttributes(cpool: JConstantPool, buf: ByteBuffer, attributes: List[AnnotationInfo]): Int = { +// val cpool = jclass.getConstantPool() def emitElement(const: Constant): Unit = const.tag match { case BooleanTag => @@ -394,7 +391,7 @@ abstract class GenJVM extends SubComponent { val buf: ByteBuffer = ByteBuffer.allocate(2048) - emitAttributes(buf, toEmit) + emitAttributes(jmember.getConstantPool, buf, toEmit) addAttribute(jmember, nme.RuntimeAnnotationATTR, buf) } @@ -411,7 +408,7 @@ abstract class GenJVM extends SubComponent { // number of parameters buf.put(attributes.length.toByte) for (attrs <- attributes) - emitAttributes(buf, attrs) + emitAttributes(jmethod.getConstantPool, buf, attrs) addAttribute(jmethod, nme.RuntimeParamAnnotationATTR, buf) } @@ -555,12 +552,24 @@ abstract class GenJVM extends SubComponent { genLocalVariableTable(m); } - addExceptionsAttribute(m.symbol) - addAnnotations(jmethod, m.symbol.attributes) + val (excs, others) = splitAnnotations(m.symbol.attributes, ThrowsAttr) + addExceptionsAttribute(jmethod, excs) + addAnnotations(jmethod, others) addParamAnnotations(m.params.map(_.sym.attributes)) } - def isClosureApply(sym: Symbol): Boolean = { + + /** Return a pair of lists of annotations, first one containing all + * annotations for the given symbol, and the rest. + */ + private def splitAnnotations(annotations: List[AnnotationInfo], annotSym: Symbol): (List[AnnotationInfo], List[AnnotationInfo]) = { + annotations.partition { a => a match { + case AnnotationInfo(tp, _, _) if tp.typeSymbol == annotSym => true + case _ => false + }} + } + + private def isClosureApply(sym: Symbol): Boolean = { (sym.name == nme.apply) && sym.owner.hasFlag(Flags.SYNTHETIC) && sym.owner.tpe.parents.exists { t => @@ -647,6 +656,10 @@ abstract class GenJVM extends SubComponent { mirrorCode.emitINVOKEVIRTUAL(moduleName, mirrorMethod.getName(), mirrorMethod.getType().asInstanceOf[JMethodType]) mirrorCode.emitRETURN(mirrorMethod.getReturnType()) + + val (throws, others) = splitAnnotations(m.attributes, ThrowsAttr) + addExceptionsAttribute(mirrorMethod, throws) + addAnnotations(mirrorMethod, others) } emitClass(mirrorClass, clasz.symbol) } diff --git a/test/files/jvm/throws-annot.check b/test/files/jvm/throws-annot.check new file mode 100644 index 0000000000..a0ed82b106 --- /dev/null +++ b/test/files/jvm/throws-annot.check @@ -0,0 +1,21 @@ +read throws: class java.io.IOException +read annotations: +readWith2 throws: class java.lang.ClassCastException, class java.io.IOException +readWith2 annotations: +readMixed throws: class java.io.IOException, class java.lang.NullPointerException +readMixed annotations: @java.lang.Deprecated() +readMixed2 throws: class java.io.IOException, class java.lang.NullPointerException +readMixed2 annotations: @java.lang.Deprecated() +readNoEx throws: +readNoEx annotations: @java.lang.Deprecated() +Testing mirror class +read throws: class java.io.IOException +read annotations: +readWith2 throws: class java.lang.ClassCastException, class java.io.IOException +readWith2 annotations: +readMixed throws: class java.io.IOException, class java.lang.NullPointerException +readMixed annotations: @java.lang.Deprecated() +readMixed2 throws: class java.io.IOException, class java.lang.NullPointerException +readMixed2 annotations: @java.lang.Deprecated() +readNoEx throws: +readNoEx annotations: @java.lang.Deprecated() diff --git a/test/files/jvm/throws-annot.scala b/test/files/jvm/throws-annot.scala new file mode 100644 index 0000000000..5f4dac07e8 --- /dev/null +++ b/test/files/jvm/throws-annot.scala @@ -0,0 +1,74 @@ +/** Test the @throws annotation */ +import java.io.IOException + +object TestThrows { + + abstract class Foo { + + @throws(classOf[IOException]) + def read(): Int + + @throws(classOf[ClassCastException]) + @throws(classOf[IOException]) + def readWith2(): Int + + @throws(classOf[IOException]) + @Deprecated + @throws(classOf[NullPointerException]) + def readMixed(): Int + + @Deprecated + @throws(classOf[IOException]) + @throws(classOf[NullPointerException]) + def readMixed2(): Int + + @Deprecated + def readNoEx(): Int + } + + def checkMethod(cls: Class[_], name: String) { + val method = cls.getMethod(name, Array()) + println(name + " throws: " + method.getExceptionTypes.mkString("", ", ", "")) + println(name + " annotations: " + method.getDeclaredAnnotations.mkString("", ", ", "")) + } + + def run(cls: Class[_]) { + checkMethod(cls, "read") + checkMethod(cls, "readWith2") + checkMethod(cls, "readMixed") + checkMethod(cls, "readMixed2") + checkMethod(cls, "readNoEx") + } +} + +/** Test the top-level mirror that is has the annotations. */ +object TL { + + @throws(classOf[IOException]) + def read(): Int = 0 + + @throws(classOf[ClassCastException]) + @throws(classOf[IOException]) + def readWith2(): Int = 0 + + @throws(classOf[IOException]) + @Deprecated + @throws(classOf[NullPointerException]) + def readMixed(): Int = 0 + + @Deprecated + @throws(classOf[IOException]) + @throws(classOf[NullPointerException]) + def readMixed2(): Int = 0 + + @Deprecated + def readNoEx(): Int = 0 +} + +object Test { + def main(args: Array[String]) { + TestThrows.run(classOf[TestThrows.Foo]) + println("Testing mirror class") + TestThrows.run(Class.forName("TL")) + } +} |