diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala | 5 | ||||
-rw-r--r-- | test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala | 104 | ||||
-rw-r--r-- | test/junit/scala/tools/testing/AssertUtil.scala | 17 |
3 files changed, 119 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala index e6b2136be2..9aedc7f8b4 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala @@ -256,7 +256,10 @@ abstract class BTypes[G <: Global](val __global_dont_use: G) { * * @param s A class name of the form "java/lang/String", without the surrounding 'L' and ';'. */ - def this(s: String) = this(createNewName(s)) + def this(s: String) = this({ + assert(!(s.head == 'L' && s.last == ';'), s"Descriptor instead of internal name: $s") + createNewName(s) + }) /** * The internal name of a class is the string returned by java.lang.Class.getName, with all '.' diff --git a/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala new file mode 100644 index 0000000000..b592d06501 --- /dev/null +++ b/test/junit/scala/tools/nsc/backend/jvm/BTypesTest.scala @@ -0,0 +1,104 @@ +package scala.tools.nsc +package backend.jvm + +import scala.tools.testing.AssertUtil._ +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test +import scala.tools.asm.Opcodes +import org.junit.Assert._ + +@RunWith(classOf[JUnit4]) +class BTypesTest { + val g: Global = new Global(new Settings()) + + val btypes = new BTypes[g.type](g) { + def chrs = g.chrs + override type BTypeName = g.TypeName + override def createNewName(s: String) = g.newTypeName(s) + } + + import btypes._ + + val jls = "java/lang/String" + val jlo = "java/lang/Object" + + val o = ClassBType(jlo) + val s = ClassBType(jls) + val oArr = ArrayBType(o) + val method = MethodBType(List(oArr, INT, DOUBLE, s), UNIT) + + @Test + def classBTypesEquality() { + val s1 = ClassBType(jls) + val s2 = ClassBType(jls) + val o = ClassBType(jlo) + assertEquals(s1, s2) + assertEquals(s1.hashCode, s2.hashCode) + assert(s1 != o) + assert(s2 != o) + } + + @Test + def classBTypeRequiresInternalName() { + assertThrows[AssertionError](ClassBType(s"L$jls;"), _ contains "Descriptor instead of internal name") + } + + @Test + def typedOpcodes() { + assert(UNIT.typedOpcode(Opcodes.IALOAD) == Opcodes.IALOAD) + assert(INT.typedOpcode(Opcodes.IALOAD) == Opcodes.IALOAD) + assert(BOOL.typedOpcode(Opcodes.IALOAD) == Opcodes.BALOAD) + assert(BYTE.typedOpcode(Opcodes.IALOAD) == Opcodes.BALOAD) + assert(CHAR.typedOpcode(Opcodes.IALOAD) == Opcodes.CALOAD) + assert(SHORT.typedOpcode(Opcodes.IALOAD) == Opcodes.SALOAD) + assert(FLOAT.typedOpcode(Opcodes.IALOAD) == Opcodes.FALOAD) + assert(LONG.typedOpcode(Opcodes.IALOAD) == Opcodes.LALOAD) + assert(DOUBLE.typedOpcode(Opcodes.IALOAD) == Opcodes.DALOAD) + assert(ClassBType(jls).typedOpcode(Opcodes.IALOAD) == Opcodes.AALOAD) + + assert(UNIT.typedOpcode(Opcodes.IRETURN) == Opcodes.RETURN) + assert(BOOL.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN) + assert(CHAR.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN) + assert(BYTE.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN) + assert(SHORT.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN) + assert(INT.typedOpcode(Opcodes.IRETURN) == Opcodes.IRETURN) + assert(FLOAT.typedOpcode(Opcodes.IRETURN) == Opcodes.FRETURN) + assert(LONG.typedOpcode(Opcodes.IRETURN) == Opcodes.LRETURN) + assert(DOUBLE.typedOpcode(Opcodes.IRETURN) == Opcodes.DRETURN) + assert(ClassBType(jls).typedOpcode(Opcodes.IRETURN) == Opcodes.ARETURN) + } + + @Test + def descriptors() { + assert(o.descriptor == "Ljava/lang/Object;") + assert(s.descriptor == "Ljava/lang/String;") + assert(oArr.descriptor == "[Ljava/lang/Object;") + assert(method.descriptor == "([Ljava/lang/Object;IDLjava/lang/String;)V") + } + + @Test + def toAsmTypeTest() { + for (t <- List(o, s, oArr, method, INT, UNIT, DOUBLE)) { + assertEquals(o.descriptor, o.toASMType.getDescriptor) + } + } + + @Test + def parseMethodDescriptorTest() { + val descriptors = List( + "()V", + "(ID)I", + "([[I[D)[D", + s"(L$jls;[L$jlo;)[[L$jls;", + s"(IL$jlo;)L$jls;" + ) + for (d <- descriptors) { + assertEquals(d, MethodBType(d).descriptor) + } + + // class types in method descriptor need surrounding 'L' and ';' + assertThrows[MatchError](MethodBType("(java/lang/String)V"), _ == "j (of class java.lang.Character)") + assertThrows[AssertionError](MethodBType("I"), _ contains "Not a valid method descriptor") + } +} diff --git a/test/junit/scala/tools/testing/AssertUtil.scala b/test/junit/scala/tools/testing/AssertUtil.scala index 9efac64a97..9a97c5114f 100644 --- a/test/junit/scala/tools/testing/AssertUtil.scala +++ b/test/junit/scala/tools/testing/AssertUtil.scala @@ -5,15 +5,20 @@ package testing * that are ultimately based on junit.Assert primitives. */ object AssertUtil { - /** Check if exception T (or a subclass) was thrown during evaluation of f. - * If any other exception or throwable is found instead it will be re-thrown. + /** + * Check if throwable T (or a subclass) was thrown during evaluation of f, and that its message + * satisfies the `checkMessage` predicate. + * If any other exception will be re-thrown. */ - def assertThrows[T <: Exception](f: => Any)(implicit manifest: Manifest[T]): Unit = + def assertThrows[T <: Throwable](f: => Any, + checkMessage: String => Boolean = s => true) + (implicit manifest: Manifest[T]): Unit = { try f catch { - case e: Exception => - val clazz = manifest.erasure.asInstanceOf[Class[T]] + case e: Throwable if checkMessage(e.getMessage) => + val clazz = manifest.runtimeClass if (!clazz.isAssignableFrom(e.getClass)) throw e } -}
\ No newline at end of file + } +} |