summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala11
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala5
-rw-r--r--src/library/scala/throws.scala6
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala21
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala2
-rw-r--r--test/files/run/t6380.check7
-rw-r--r--test/files/run/t6380.scala20
7 files changed, 57 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index 4738ad8a38..f9eeb41e6d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -832,15 +832,10 @@ abstract class GenASM extends SubComponent with BytecodeWriters {
*
* The contents of that attribute are determined by the `String[] exceptions` argument to ASM's ClassVisitor.visitMethod()
* This method returns such list of internal names.
- *
*/
- def getExceptions(excs: List[AnnotationInfo]): List[String] = {
- for (AnnotationInfo(tp, List(exc), _) <- excs.distinct if tp.typeSymbol == ThrowsClass)
- yield {
- val Literal(const) = exc
- javaName(const.typeValue.typeSymbol)
- }
- }
+ def getExceptions(excs: List[AnnotationInfo]): List[String] =
+ for (ThrownException(exc) <- excs.distinct)
+ yield javaName(exc)
/** Whether an annotation should be emitted as a Java annotation
* .initialize: if 'annot' is read from pickle, atp might be un-initialized
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 62c281b82f..cb6156c59c 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -606,11 +606,10 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
// put some random value; the actual number is determined at the end
buf putShort 0xbaba.toShort
- for (AnnotationInfo(tp, List(exc), _) <- excs.distinct if tp.typeSymbol == ThrowsClass) {
- val Literal(const) = exc
+ for (ThrownException(exc) <- excs.distinct) {
buf.putShort(
cpool.addClass(
- javaName(const.typeValue.typeSymbol)).shortValue)
+ javaName(exc)).shortValue)
nattr += 1
}
diff --git a/src/library/scala/throws.scala b/src/library/scala/throws.scala
index 0aa0d31c9f..02dffb00b0 100644
--- a/src/library/scala/throws.scala
+++ b/src/library/scala/throws.scala
@@ -14,7 +14,7 @@ package scala
* {{{
* class Reader(fname: String) {
* private val in = new BufferedReader(new FileReader(fname))
- * @throws(classOf[IOException])
+ * @throws[IOException]("if the file doesn't exist")
* def read() = in.read()
* }
* }}}
@@ -23,4 +23,6 @@ package scala
* @version 1.0, 19/05/2006
* @since 2.1
*/
-class throws(clazz: Class[_]) extends scala.annotation.StaticAnnotation
+class throws[T <: Throwable](cause: String = "") extends scala.annotation.StaticAnnotation {
+ def this(clazz: Class[T]) = this()
+}
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 3bd7f4f4fa..46e4329b2e 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -30,7 +30,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
/** Symbols of any @throws annotations on this symbol.
*/
def throwsAnnotations(): List[Symbol] = annotations collect {
- case AnnotationInfo(tp, Literal(Constant(tpe: Type)) :: Nil, _) if tp.typeSymbol == ThrowsClass => tpe.typeSymbol
+ case ThrownException(exc) => exc
}
/** Tests for, get, or remove an annotation */
@@ -325,4 +325,23 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
implicit val AnnotationTag = ClassTag[AnnotationInfo](classOf[AnnotationInfo])
object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil)
+
+ /** Extracts symbol of thrown exception from AnnotationInfo.
+ *
+ * Supports both “old-style” `@throws(classOf[Exception])`
+ * as well as “new-stye” `@throws[Exception]("cause")` annotations.
+ */
+ object ThrownException {
+ def unapply(ann: AnnotationInfo): Option[Symbol] =
+ ann match {
+ case AnnotationInfo(tpe, _, _) if tpe.typeSymbol != ThrowsClass =>
+ None
+ // old-style: @throws(classOf[Exception]) (which is throws[T](classOf[Exception]))
+ case AnnotationInfo(_, List(Literal(Constant(tpe: Type))), _) =>
+ Some(tpe.typeSymbol)
+ // new-style: @throws[Exception], @throws[Exception]("cause")
+ case AnnotationInfo(TypeRef(_, _, args), _, _) =>
+ Some(args.head.typeSymbol)
+ }
+ }
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 6cdca3d7f8..2bc9f02758 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -954,7 +954,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val ScalaNoInlineClass = requiredClass[scala.noinline]
lazy val SerialVersionUIDAttr = requiredClass[scala.SerialVersionUID]
lazy val SpecializedClass = requiredClass[scala.specialized]
- lazy val ThrowsClass = requiredClass[scala.throws]
+ lazy val ThrowsClass = requiredClass[scala.throws[_]]
lazy val TransientAttr = requiredClass[scala.transient]
lazy val UncheckedClass = requiredClass[scala.unchecked]
lazy val UnspecializedClass = requiredClass[scala.annotation.unspecialized]
diff --git a/test/files/run/t6380.check b/test/files/run/t6380.check
new file mode 100644
index 0000000000..912525ed66
--- /dev/null
+++ b/test/files/run/t6380.check
@@ -0,0 +1,7 @@
+List(class java.lang.Exception)
+List(class java.lang.Throwable)
+List(class java.lang.RuntimeException)
+List(class java.lang.IllegalArgumentException, class java.util.NoSuchElementException)
+List(class java.lang.IndexOutOfBoundsException, class java.lang.IndexOutOfBoundsException)
+List(class java.lang.IllegalStateException, class java.lang.IllegalStateException)
+List(class java.lang.NullPointerException, class java.lang.NullPointerException)
diff --git a/test/files/run/t6380.scala b/test/files/run/t6380.scala
new file mode 100644
index 0000000000..0e264d9175
--- /dev/null
+++ b/test/files/run/t6380.scala
@@ -0,0 +1,20 @@
+object Test extends App {
+ classOf[Foo].getDeclaredMethods().sortBy(_.getName).map(_.getExceptionTypes.sortBy(_.getName).toList).toList.foreach(println)
+}
+
+class Foo {
+ @throws[Exception]
+ def bar1 = ???
+ @throws[Throwable]("always")
+ def bar2 = ???
+ @throws(classOf[RuntimeException])
+ def bar3 = ???
+ @throws[IllegalArgumentException] @throws[NoSuchElementException]
+ def bar4 = ???
+ @throws(classOf[IndexOutOfBoundsException]) @throws(classOf[IndexOutOfBoundsException])
+ def bar5 = ???
+ @throws[IllegalStateException]("Cause") @throws[IllegalStateException]
+ def bar6 = ???
+ @throws[NullPointerException]("Cause A") @throws[NullPointerException]("Cause B")
+ def bar7 = ???
+} \ No newline at end of file