diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala | 5 | ||||
-rw-r--r-- | src/library/scala/throws.scala | 6 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/AnnotationInfos.scala | 21 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 2 | ||||
-rw-r--r-- | test/files/run/t6380.check | 7 | ||||
-rw-r--r-- | test/files/run/t6380.scala | 20 |
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 |