diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2014-08-12 10:57:42 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2014-08-12 11:03:40 +0200 |
commit | 0270972b9f70d107dff393081dc48c877be1f161 (patch) | |
tree | 1d1a4021325c600a26e41e1589f99194f3f96d51 /test | |
parent | 50167e3f1df664165a2ad485abace5dbce623996 (diff) | |
download | scala-0270972b9f70d107dff393081dc48c877be1f161.tar.gz scala-0270972b9f70d107dff393081dc48c877be1f161.tar.bz2 scala-0270972b9f70d107dff393081dc48c877be1f161.zip |
test for InnerClass and EnclosingMethod attributes
Some parts of the test assert (current) buggy behavior. This is marked
in the test file with TODO. It will be fixed in later work on the
backend.
Diffstat (limited to 'test')
-rw-r--r-- | test/files/jvm/innerClassAttribute/Classes_1.scala | 99 | ||||
-rw-r--r-- | test/files/jvm/innerClassAttribute/JavaAnnot_1.java | 3 | ||||
-rw-r--r-- | test/files/jvm/innerClassAttribute/Test.scala | 208 |
3 files changed, 310 insertions, 0 deletions
diff --git a/test/files/jvm/innerClassAttribute/Classes_1.scala b/test/files/jvm/innerClassAttribute/Classes_1.scala new file mode 100644 index 0000000000..0875d9160c --- /dev/null +++ b/test/files/jvm/innerClassAttribute/Classes_1.scala @@ -0,0 +1,99 @@ +class A1 { + class B +} + +class A2 { + object B +} + +object A3 { + class B1 + object B2 +} + +class A4 { + def f(l: List[Int]): List[Int] = { + l map (_ + 1) + } +} + +class A5 { + def f(): Object = { + object B + B + } +} + +trait A6 { + def hui = -6 + trait TT +} + +class A7 extends A6 + +abstract class A8 extends A6 { + def fish: TT +} + +class A9 { + class brick extends annotation.StaticAnnotation +} + +class A10 { + val a9 = new A9() + // there's no reference to brick in the bytecode (only in the pickle), so there's no InnerClass attribute for it. + @a9.brick def f = -7 +} + +class A11 { + @JavaAnnot_1.Ann def f = -8 +} + +object A12 { + object B { + class C + } +} + +class A13 { + def oak: A12.B.C = new A12.B.C +} + +class A14 { + def f = { + val x: Object = { + class K + new K + } + x + } + def g = { + val x: Object = new A6 { } + } +} + +object A15 { + def f = { + class B { // static (does not have an outer pointer) + class C // non-static + } + } +} + +class A16 { + val x: A6 = { + class U extends A6 + new A6 { } + } + + { + class V extends A6 + new A6 { } + } +} + +class A17 { + object B { + class C // not static, has an outer pointer. + } +} diff --git a/test/files/jvm/innerClassAttribute/JavaAnnot_1.java b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java new file mode 100644 index 0000000000..27c4d4e5d3 --- /dev/null +++ b/test/files/jvm/innerClassAttribute/JavaAnnot_1.java @@ -0,0 +1,3 @@ +public class JavaAnnot_1 { + public static @interface Ann {} +} diff --git a/test/files/jvm/innerClassAttribute/Test.scala b/test/files/jvm/innerClassAttribute/Test.scala new file mode 100644 index 0000000000..6cf60ab92d --- /dev/null +++ b/test/files/jvm/innerClassAttribute/Test.scala @@ -0,0 +1,208 @@ +import scala.tools.partest.BytecodeTest +import scala.tools.asm +import asm.tree.{ClassNode, InnerClassNode} +import asm.{Opcodes => Flags} +import scala.collection.JavaConverters._ + +object Test extends BytecodeTest { + def assertSame(a: Any, b: Any) = { + assert(a == b, s"\na: $a\nb: $b") + } + + val publicStatic = Flags.ACC_PUBLIC | Flags.ACC_STATIC + val publicAbstractInterface = Flags.ACC_PUBLIC | Flags.ACC_ABSTRACT | Flags.ACC_INTERFACE + + def innerClassNodes(className: String): List[InnerClassNode] = { + loadClassNode(className).innerClasses.asScala.toList.sortBy(_.name) + } + + final case class EnclosingMethod(name: String, descriptor: String, outerClass: String) + def enclosingMethod(className: String) = { + val n = loadClassNode(className) + EnclosingMethod(n.outerMethod, n.outerMethodDesc, n.outerClass) + } + + def assertMember(node: InnerClassNode, outer: String, inner: String, name: Option[String] = None, flags: Int = Flags.ACC_PUBLIC) = { + assertSame(node.name, name.getOrElse(s"$outer$$$inner")) + assertSame(node.outerName, outer) + assertSame(node.innerName, inner) + assertSame(node.access, flags) + } + + def assertAnonymous(node: InnerClassNode, name: String, flags: Int = Flags.ACC_PUBLIC | Flags.ACC_FINAL) = { + assertSame(node.name, name) + assertSame(node.outerName, null) + assertSame(node.innerName, null) + assertSame(node.access, flags) + } + + def assertLocal(node: InnerClassNode, name: String, inner: String, flags: Int = Flags.ACC_PUBLIC) = { + assertSame(node.name, name) + assertSame(node.outerName, null) + assertSame(node.innerName, inner) + assertSame(node.access, flags) + } + + def assertEnclosingMethod(enclosingMethod: EnclosingMethod, outerClass: String, name: String, descriptor: String) = { + assertSame(enclosingMethod.outerClass, outerClass) + assertSame(enclosingMethod.name, name) + assertSame(enclosingMethod.descriptor, descriptor) + } + + def testA1() = { + val List(b1) = innerClassNodes("A1") + assertMember(b1, "A1", "B") + val List(b2) = innerClassNodes("A1$B") + assertMember(b2, "A1", "B") + } + + def testA2() = { + val List(b1) = innerClassNodes("A2") + assertMember(b1, "A2", "B$") + val List(b2) = innerClassNodes("A2$B$") + assertMember(b2, "A2", "B$") + } + + def testA3() = { + def t(c: String) = { + val List(b1, b2) = innerClassNodes(c) + // the outer class for classes nested inside top-level modules is not the module class, but the mirror class. + // this is a hack for java interop, handled in the backend. see BTypes.scala, comment on "Java Compatibility". + assertMember(b1, "A3", "B1", flags = publicStatic) + assertMember(b2, "A3", "B2$", flags = publicStatic) + } + t("A3$") + // the mirror class has the same inner class attributes as the module + // class (added when the mirror is created in the backend) + t("A3") + } + + def testA4() = { + val List(an1) = innerClassNodes("A4") + assertAnonymous(an1, "A4$$anonfun$f$1") + val List(an2) = innerClassNodes("A4$$anonfun$f$1") + assertAnonymous(an2, "A4$$anonfun$f$1") + assertEnclosingMethod( + enclosingMethod("A4$$anonfun$f$1"), + "A4", "f", "(Lscala/collection/immutable/List;)Lscala/collection/immutable/List;") + } + + def testA5() = { + val List(b1) = innerClassNodes("A5") + assertLocal(b1, "A5$B$2$", "B$2$") + val List(b2) = innerClassNodes("A5$B$2$") + assertLocal(b2, "A5$B$2$", "B$2$") + assertEnclosingMethod( + enclosingMethod("A5$B$2$"), + "A5", "f", "()Ljava/lang/Object;") + } + + def testA6() = { + val List(tt1) = innerClassNodes("A6") + assertMember(tt1, "A6", "TT", flags = publicAbstractInterface) + val List() = innerClassNodes("A6$class") + val List(tt2) = innerClassNodes("A6$TT") + assertMember(tt2, "A6", "TT", flags = publicAbstractInterface) + } + + def testA7() = { + val List() = innerClassNodes("A7") + } + + def testA8() = { + val List(tt) = innerClassNodes("A8") + assertMember(tt, "A6", "TT", flags = publicAbstractInterface) + } + + def testA10() = { + val List() = innerClassNodes("A10") + } + + def testA11() = { + val List(ann) = innerClassNodes("A11") + // in the java class file, the INNERCLASS attribute has more flags (public | static | abstract | interface | annotation) + // the scala compiler has its own interpretation of java annotations ant their flags.. it only emits publicStatic. + assertMember(ann, "JavaAnnot_1", "Ann", flags = publicStatic) + } + + def testA13() = { + val List(b, c) = innerClassNodes("A13") + assertMember(b, "A12", "B$", flags = publicStatic) + assertMember(c, "A12$B$", "C", name = Some("A12$B$C"), flags = publicStatic) + } + + def testA14() = { + val List(anon, k) = innerClassNodes("A14") + + assertLocal(k, "A14$K$1", "K$1") + assertEnclosingMethod( + enclosingMethod("A14$K$1"), + "A14", "f", "()Ljava/lang/Object;") + + assertAnonymous(anon, "A14$$anon$1") + assertEnclosingMethod( + enclosingMethod("A14$$anon$1"), + "A14", "g", "()V") + } + + def testA15() = { + val List(b) = innerClassNodes("A15") + assertLocal(b, "A15$B$3", "B$3", flags = publicStatic) + + val List(_, c) = innerClassNodes("A15$B$3") + // TODO this is a bug in the backend, C should be a member. Instead, its outerClass is null + // assertMember(c, "A15$B$3", "C") + assertLocal(c, "A15$B$3$C", "C") + } + + def testA16() = { + val List(anon1, anon2, u, v) = innerClassNodes("A16") + // TODO there's a bug in the backend: anon$2 has outerClass A16, but anonymous classes should have outerClass null + // assertAnonymous(anon1, "A16$$anon$2") + assertMember(anon1, "A16", null, name = Some("A16$$anon$2"), flags = Flags.ACC_PUBLIC | Flags.ACC_FINAL) + assertAnonymous(anon2, "A16$$anon$3") + // TODO this is a bug in the backend, U should not be a member, its outerClass should be null + // assertLocal(u, "A16$U$1", "U$1") + assertMember(u, "A16", "U$1") + assertLocal(v, "A16$V$1", "V$1") + + assertEnclosingMethod( + enclosingMethod("A16$$anon$2"), + "A16", "<init>", "()V") + assertEnclosingMethod( + enclosingMethod("A16$$anon$3"), + "A16", "<init>", "()V") + // TODO this is a bug, there should be an enclosingMethod attribute in U + // assertEnclosingMethod( + // enclosingMethod("A16$U$1"), + // "A16", "<init>", "()V") + assertEnclosingMethod( + enclosingMethod("A16$V$1"), + "A16", "<init>", "()V") + } + + def testA17() = { + val List(b, c) = innerClassNodes("A17$B$") + assertMember(b, "A17", "B$") + // TODO this is a bug, should not be static. + assertMember(c, "A17$B$", "C", name = Some("A17$B$C"), flags = publicStatic) // (should be) not static, has an outer pointer. + } + + def show(): Unit = { + testA1() + testA2() + testA3() + testA4() + testA5() + testA6() + testA7() + testA8() + testA10() + testA11() + testA13() + testA14() + testA15() + testA16() + testA17() + } +} |