From c78d771e6f025e767801f7fe118acc2ea7540acd Mon Sep 17 00:00:00 2001 From: Simon Ochsenreither Date: Mon, 31 Aug 2015 05:03:29 +0200 Subject: SI-9437 Emit and support parameter names in class files JEP 118 added a MethodParameters attribute to the class file spec which holds the parameter names of methods when compiling Java code with `javac -parameters`. We emit parameter names by default now. --- test/files/run/t9437a.check | 10 +++++ test/files/run/t9437a/Test.scala | 20 +++++++++ test/files/run/t9437b.check | 10 +++++ test/files/run/t9437b/Foo_1.scala | 3 ++ test/files/run/t9437b/Test_2.scala | 16 +++++++ test/files/run/t9437c.check | 10 +++++ test/files/run/t9437c/Test.scala | 92 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 161 insertions(+) create mode 100644 test/files/run/t9437a.check create mode 100644 test/files/run/t9437a/Test.scala create mode 100644 test/files/run/t9437b.check create mode 100644 test/files/run/t9437b/Foo_1.scala create mode 100644 test/files/run/t9437b/Test_2.scala create mode 100644 test/files/run/t9437c.check create mode 100644 test/files/run/t9437c/Test.scala (limited to 'test/files/run') diff --git a/test/files/run/t9437a.check b/test/files/run/t9437a.check new file mode 100644 index 0000000000..564213c587 --- /dev/null +++ b/test/files/run/t9437a.check @@ -0,0 +1,10 @@ +name: a; isNamePresent: true; isSynthetic: false +name: _; isNamePresent: true; isSynthetic: false +name: ***; isNamePresent: true; isSynthetic: false +name: unary_!; isNamePresent: true; isSynthetic: false +name: ABC; isNamePresent: true; isSynthetic: false +name: a; isNamePresent: true; isSynthetic: false +name: _; isNamePresent: true; isSynthetic: false +name: ***; isNamePresent: true; isSynthetic: false +name: unary_!; isNamePresent: true; isSynthetic: false +name: ABC; isNamePresent: true; isSynthetic: false diff --git a/test/files/run/t9437a/Test.scala b/test/files/run/t9437a/Test.scala new file mode 100644 index 0000000000..a86c17b646 --- /dev/null +++ b/test/files/run/t9437a/Test.scala @@ -0,0 +1,20 @@ +class Foo(a: Int, `_`: String, *** : Long, `unary_!` : Float, ABC: Double) { + def bar(a: Int, `_`: String, *** : Long, `unary_!` : Float, ABC: Double) = null +} + +object Test extends App { + val constrParams = classOf[Foo].getConstructors.head.getParameters + val methodParams = classOf[Foo].getDeclaredMethods.head.getParameters + + def printParams(params: Array[java.lang.reflect.Parameter]) = { + params.foreach { param => + println(s"name: ${param.getName}; isNamePresent: ${param.isNamePresent}; isSynthetic: ${param.isSynthetic}") + } + } + + printParams(constrParams) + printParams(methodParams) + + val foo = new Foo(a = 1, `_` = "2", *** = 3L, `unary_!` = 4.0f, ABC = 5.0) + foo.bar(a = 1, `_` = "2", *** = 3L, `unary_!` = 4.0f, ABC = 5.0) +} diff --git a/test/files/run/t9437b.check b/test/files/run/t9437b.check new file mode 100644 index 0000000000..564213c587 --- /dev/null +++ b/test/files/run/t9437b.check @@ -0,0 +1,10 @@ +name: a; isNamePresent: true; isSynthetic: false +name: _; isNamePresent: true; isSynthetic: false +name: ***; isNamePresent: true; isSynthetic: false +name: unary_!; isNamePresent: true; isSynthetic: false +name: ABC; isNamePresent: true; isSynthetic: false +name: a; isNamePresent: true; isSynthetic: false +name: _; isNamePresent: true; isSynthetic: false +name: ***; isNamePresent: true; isSynthetic: false +name: unary_!; isNamePresent: true; isSynthetic: false +name: ABC; isNamePresent: true; isSynthetic: false diff --git a/test/files/run/t9437b/Foo_1.scala b/test/files/run/t9437b/Foo_1.scala new file mode 100644 index 0000000000..ca6c9c6156 --- /dev/null +++ b/test/files/run/t9437b/Foo_1.scala @@ -0,0 +1,3 @@ +class Foo(a: Int, `_`: String, *** : Long, `unary_!` : Float, ABC: Double) { + def bar(a: Int, `_`: String, *** : Long, `unary_!` : Float, ABC: Double) = null +} diff --git a/test/files/run/t9437b/Test_2.scala b/test/files/run/t9437b/Test_2.scala new file mode 100644 index 0000000000..521f525f1d --- /dev/null +++ b/test/files/run/t9437b/Test_2.scala @@ -0,0 +1,16 @@ +object Test extends App { + val constrParams = classOf[Foo].getConstructors.head.getParameters + val methodParams = classOf[Foo].getDeclaredMethods.head.getParameters + + def printParams(params: Array[java.lang.reflect.Parameter]) = { + params.foreach { param => + println(s"name: ${param.getName}; isNamePresent: ${param.isNamePresent}; isSynthetic: ${param.isSynthetic}") + } + } + + printParams(constrParams) + printParams(methodParams) + + val foo = new Foo(a = 1, `_` = "2", *** = 3L, `unary_!` = 4.0f, ABC = 5.0) + foo.bar(a = 1, `_` = "2", *** = 3L, `unary_!` = 4.0f, ABC = 5.0) +} diff --git a/test/files/run/t9437c.check b/test/files/run/t9437c.check new file mode 100644 index 0000000000..564213c587 --- /dev/null +++ b/test/files/run/t9437c.check @@ -0,0 +1,10 @@ +name: a; isNamePresent: true; isSynthetic: false +name: _; isNamePresent: true; isSynthetic: false +name: ***; isNamePresent: true; isSynthetic: false +name: unary_!; isNamePresent: true; isSynthetic: false +name: ABC; isNamePresent: true; isSynthetic: false +name: a; isNamePresent: true; isSynthetic: false +name: _; isNamePresent: true; isSynthetic: false +name: ***; isNamePresent: true; isSynthetic: false +name: unary_!; isNamePresent: true; isSynthetic: false +name: ABC; isNamePresent: true; isSynthetic: false diff --git a/test/files/run/t9437c/Test.scala b/test/files/run/t9437c/Test.scala new file mode 100644 index 0000000000..4be233a258 --- /dev/null +++ b/test/files/run/t9437c/Test.scala @@ -0,0 +1,92 @@ +import java.io.{File, FileOutputStream} + +import scala.tools.nsc.settings.ScalaVersion +import scala.tools.partest._ +import scala.tools.asm +import asm.{AnnotationVisitor, ClassWriter, FieldVisitor, Handle, MethodVisitor, Opcodes} +import Opcodes._ + +// This test ensures that we can read JDK 8 (classfile format 52) files with +// parameter names. To do that it first uses ASM to generate a class containing +// these additional attributes. Then it runs a normal compile on Scala source +// that uses the class with named arguments. +// Any failure will be dumped to std out. +object Test extends DirectTest { + override def extraSettings: String = "-usejavacp -d " + testOutput.path + " -cp " + testOutput.path + + def generateCode(): Unit = { + val className = "Foo" + + val cw = new ClassWriter(0) + cw.visit(52, ACC_PUBLIC + ACC_SUPER, className, null, "java/lang/Object", null); + + val mvC = cw.visitMethod(ACC_PUBLIC, "", "(ILjava/lang/String;JFD)V", null, null); + mvC.visitParameter("a", ACC_FINAL); + mvC.visitParameter("_", ACC_FINAL); + mvC.visitParameter("***", ACC_FINAL); + mvC.visitParameter("unary_!", ACC_FINAL); + mvC.visitParameter("ABC", ACC_FINAL); + mvC.visitCode(); + mvC.visitVarInsn(ALOAD, 0); + mvC.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mvC.visitInsn(RETURN); + mvC.visitMaxs(1, 8); + mvC.visitEnd(); + + val mvM = cw.visitMethod(ACC_PUBLIC, "bar", "(ILjava/lang/String;JFD)Lscala/runtime/Null$;", null, null); + mvM.visitParameter("a", ACC_FINAL); + mvM.visitParameter("_", ACC_FINAL); + mvM.visitParameter("***", ACC_FINAL); + mvM.visitParameter("unary_!", ACC_FINAL); + mvM.visitParameter("ABC", ACC_FINAL); + mvM.visitCode(); + mvM.visitInsn(ACONST_NULL); + mvM.visitInsn(ARETURN); + mvM.visitMaxs(1, 8); + mvM.visitEnd(); + + cw.visitEnd(); + + val bytes = cw.toByteArray() + + val fos = new FileOutputStream(new File(s"${testOutput.path}/$className.class")) + try + fos write bytes + finally + fos.close() + + } + + def code = +""" +class Driver { + val constrParams = classOf[Foo].getConstructors.head.getParameters + val methodParams = classOf[Foo].getDeclaredMethods.head.getParameters + + def printParams(params: Array[java.lang.reflect.Parameter]) = { + params.foreach { param => + println(s"name: ${param.getName}; isNamePresent: ${param.isNamePresent}; isSynthetic: ${param.isSynthetic}") + } + } + + printParams(constrParams) + printParams(methodParams) + + val foo = new Foo(a = 1, `_` = "2", *** = 3L, `unary_!` = 4.0f, ABC = 5.0) + foo.bar(a = 1, `_` = "2", *** = 3L, `unary_!` = 4.0f, ABC = 5.0) +} +""" + + override def show(): Unit = { + // redirect err to out, for logging + val prevErr = System.err + System.setErr(System.out) + try { + generateCode() + compile() + Class.forName("Driver").newInstance() + } + finally + System.setErr(prevErr) + } +} -- cgit v1.2.3