Add test for keeping MethodParameters
Bug: 135043314
Change-Id: I4aeb247ba62e96ca23298470a92c954e7e4fdace
diff --git a/src/test/java/com/android/tools/r8/naming/methodparameters/MethodParametersTest.java b/src/test/java/com/android/tools/r8/naming/methodparameters/MethodParametersTest.java
new file mode 100644
index 0000000..2342fd3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/methodparameters/MethodParametersTest.java
@@ -0,0 +1,96 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.naming.methodparameters;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class MethodParametersTest extends TestBase {
+
+ private static String[] EXPECTED = {"hello", "darkness", "my", "old", "friend"};
+
+ private final TestParameters parameters;
+ private final boolean keepMethodParameters;
+
+ @Parameters(name = "{0} methodparameters: {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntimes()
+ .withDexRuntimesStartingFromIncluding(Version.V8_1_0)
+ .build(),
+ BooleanUtils.values());
+ }
+
+ public MethodParametersTest(TestParameters parameters, boolean keepMethodParameters) {
+ this.parameters = parameters;
+ this.keepMethodParameters = keepMethodParameters;
+ }
+
+ @Test
+ @Ignore("b/135043314")
+ public void testKeepingMethodParametersR8()
+ throws ExecutionException, CompilationFailedException, IOException {
+ R8TestRunResult runResult =
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(MethodParametersTestDump.dump())
+ .addKeepClassAndMembersRulesWithAllowObfuscation(MethodParametersTest.class)
+ .addKeepMainRule(MethodParametersTest.class)
+ .addKeepRules(keepMethodParameters ? "-keepattributes MethodParameters" : "")
+ .setMinApi(AndroidApiLevel.L)
+ .run(parameters.getRuntime(), MethodParametersTest.class);
+ checkOutput(runResult);
+ }
+
+ @Test
+ public void testKeepingMethodParameters()
+ throws ExecutionException, CompilationFailedException, IOException {
+ assumeTrue(parameters.getBackend() == Backend.DEX);
+ D8TestRunResult runResult =
+ testForD8()
+ .addProgramClassFileData(MethodParametersTestDump.dump())
+ .setMinApi(keepMethodParameters ? AndroidApiLevel.O : AndroidApiLevel.L)
+ .run(parameters.getRuntime(), MethodParametersTest.class);
+ checkOutput(runResult);
+ }
+
+ private void checkOutput(TestRunResult runResult) {
+ if (keepMethodParameters) {
+ checkOutputContainsAll(runResult.getStdOut());
+ } else {
+ checkOutputNotContainsAll(runResult.getStdOut());
+ }
+ }
+
+ private void checkOutputContainsAll(String stdOut) {
+ Arrays.asList(EXPECTED).forEach(expected -> assertThat(stdOut, containsString(expected)));
+ }
+
+ private void checkOutputNotContainsAll(String stdOut) {
+ Arrays.asList(EXPECTED).forEach(expected -> assertThat(stdOut, not(containsString(expected))));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/methodparameters/MethodParametersTestDump.java b/src/test/java/com/android/tools/r8/naming/methodparameters/MethodParametersTestDump.java
new file mode 100644
index 0000000..f5ab8a6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/methodparameters/MethodParametersTestDump.java
@@ -0,0 +1,220 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.naming.methodparameters;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class MethodParametersTestDump implements Opcodes {
+
+ /* The below dump was produced by the asmifier on following java code:
+
+ import java.lang.reflect.Method;
+ import java.lang.reflect.Parameter;
+
+ public class MethodParametersTest {
+
+ public static void main(String... hello) {
+ for (Method method : MethodParametersTest.class.getMethods()) {
+ for (Parameter parameter : method.getParameters()) {
+ System.out.println(method.getName() + ": " + parameter.getName());
+ }
+ }
+ }
+
+ public void other(int darkness, String my, Object old, boolean friend) {
+
+ }
+ }
+ */
+
+ public static byte[] dump() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ MethodVisitor methodVisitor;
+
+ classWriter.visit(
+ V1_8,
+ ACC_PUBLIC | ACC_SUPER,
+ "com/android/tools/r8/naming/methodparameters/MethodParametersTest",
+ null,
+ "java/lang/Object",
+ null);
+
+ classWriter.visitSource("MethodParametersTest.java", null);
+
+ {
+ methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ methodVisitor.visitCode();
+ Label label0 = new Label();
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitLineNumber(4, label0);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(1, 1);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC | ACC_VARARGS, "main", "([Ljava/lang/String;)V", null, null);
+ methodVisitor.visitParameter("hello", 0);
+ methodVisitor.visitCode();
+ Label label0 = new Label();
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitLineNumber(7, label0);
+ methodVisitor.visitLdcInsn(
+ Type.getType("Lcom/android/tools/r8/naming/methodparameters/MethodParametersTest;"));
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;", false);
+ methodVisitor.visitVarInsn(ASTORE, 1);
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ methodVisitor.visitInsn(ARRAYLENGTH);
+ methodVisitor.visitVarInsn(ISTORE, 2);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 3);
+ Label label1 = new Label();
+ methodVisitor.visitLabel(label1);
+ methodVisitor.visitFrame(
+ Opcodes.F_APPEND,
+ 3,
+ new Object[] {"[Ljava/lang/reflect/Method;", Opcodes.INTEGER, Opcodes.INTEGER},
+ 0,
+ null);
+ methodVisitor.visitVarInsn(ILOAD, 3);
+ methodVisitor.visitVarInsn(ILOAD, 2);
+ Label label2 = new Label();
+ methodVisitor.visitJumpInsn(IF_ICMPGE, label2);
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ methodVisitor.visitVarInsn(ILOAD, 3);
+ methodVisitor.visitInsn(AALOAD);
+ methodVisitor.visitVarInsn(ASTORE, 4);
+ Label label3 = new Label();
+ methodVisitor.visitLabel(label3);
+ methodVisitor.visitLineNumber(8, label3);
+ methodVisitor.visitVarInsn(ALOAD, 4);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "java/lang/reflect/Method",
+ "getParameters",
+ "()[Ljava/lang/reflect/Parameter;",
+ false);
+ methodVisitor.visitVarInsn(ASTORE, 5);
+ methodVisitor.visitVarInsn(ALOAD, 5);
+ methodVisitor.visitInsn(ARRAYLENGTH);
+ methodVisitor.visitVarInsn(ISTORE, 6);
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 7);
+ Label label4 = new Label();
+ methodVisitor.visitLabel(label4);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 8,
+ new Object[] {
+ "[Ljava/lang/String;",
+ "[Ljava/lang/reflect/Method;",
+ Opcodes.INTEGER,
+ Opcodes.INTEGER,
+ "java/lang/reflect/Method",
+ "[Ljava/lang/reflect/Parameter;",
+ Opcodes.INTEGER,
+ Opcodes.INTEGER
+ },
+ 0,
+ new Object[] {});
+ methodVisitor.visitVarInsn(ILOAD, 7);
+ methodVisitor.visitVarInsn(ILOAD, 6);
+ Label label5 = new Label();
+ methodVisitor.visitJumpInsn(IF_ICMPGE, label5);
+ methodVisitor.visitVarInsn(ALOAD, 5);
+ methodVisitor.visitVarInsn(ILOAD, 7);
+ methodVisitor.visitInsn(AALOAD);
+ methodVisitor.visitVarInsn(ASTORE, 8);
+ Label label6 = new Label();
+ methodVisitor.visitLabel(label6);
+ methodVisitor.visitLineNumber(9, label6);
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
+ methodVisitor.visitVarInsn(ALOAD, 4);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/reflect/Method", "getName", "()Ljava/lang/String;", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "java/lang/StringBuilder",
+ "append",
+ "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+ false);
+ methodVisitor.visitLdcInsn(": ");
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "java/lang/StringBuilder",
+ "append",
+ "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+ false);
+ methodVisitor.visitVarInsn(ALOAD, 8);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/reflect/Parameter", "getName", "()Ljava/lang/String;", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "java/lang/StringBuilder",
+ "append",
+ "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+ false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+ Label label7 = new Label();
+ methodVisitor.visitLabel(label7);
+ methodVisitor.visitLineNumber(8, label7);
+ methodVisitor.visitIincInsn(7, 1);
+ methodVisitor.visitJumpInsn(GOTO, label4);
+ methodVisitor.visitLabel(label5);
+ methodVisitor.visitLineNumber(7, label5);
+ methodVisitor.visitFrame(
+ Opcodes.F_FULL,
+ 4,
+ new Object[] {
+ "[Ljava/lang/String;", "[Ljava/lang/reflect/Method;", Opcodes.INTEGER, Opcodes.INTEGER
+ },
+ 0,
+ new Object[] {});
+ methodVisitor.visitIincInsn(3, 1);
+ methodVisitor.visitJumpInsn(GOTO, label1);
+ methodVisitor.visitLabel(label2);
+ methodVisitor.visitLineNumber(12, label2);
+ methodVisitor.visitFrame(Opcodes.F_CHOP, 3, null, 0, null);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(3, 9);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC, "other", "(ILjava/lang/String;Ljava/lang/Object;Z)V", null, null);
+ methodVisitor.visitParameter("darkness", 0);
+ methodVisitor.visitParameter("my", 0);
+ methodVisitor.visitParameter("old", 0);
+ methodVisitor.visitParameter("friend", 0);
+ methodVisitor.visitCode();
+ Label label0 = new Label();
+ methodVisitor.visitLabel(label0);
+ methodVisitor.visitLineNumber(16, label0);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(0, 5);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+}