Reproduce invalid MethodParameters attribute from desugaring
Bug: 189743726
Change-Id: I7f157d1aa7826c6b436f562d04fbd1b4445e9491
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 4c765be..50f5346 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_4_20;
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_5_0_M2;
import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
+import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.isDexFile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -100,6 +101,7 @@
public static final String THIRD_PARTY_DIR = "third_party/";
public static final String TOOLS_DIR = "tools/";
public static final String TESTS_DIR = "src/test/";
+ public static final String TESTS_SOURCE_DIR = "src/test/java";
public static final String EXAMPLES_DIR = TESTS_DIR + "examples/";
public static final String EXAMPLES_ANDROID_N_DIR = TESTS_DIR + "examplesAndroidN/";
public static final String EXAMPLES_ANDROID_O_DIR = TESTS_DIR + "examplesAndroidO/";
@@ -1099,6 +1101,17 @@
.collect(Collectors.toList());
}
+ public static Path getSourceFileForTestClass(Class<?> clazz) {
+ List<String> parts = getNamePartsForTestClass(clazz);
+ String last = parts.get(parts.size() - 1);
+ assert last.endsWith(CLASS_EXTENSION);
+ parts.set(
+ parts.size() - 1,
+ last.substring(0, last.length() - CLASS_EXTENSION.length()) + JAVA_EXTENSION);
+ return Paths.get(TESTS_SOURCE_DIR)
+ .resolve(Paths.get("", parts.toArray(StringUtils.EMPTY_ARRAY)));
+ }
+
public static Path getClassFileForTestClass(Class<?> clazz) {
List<String> parts = getNamePartsForTestClass(clazz);
return getClassPathForTests().resolve(Paths.get("", parts.toArray(StringUtils.EMPTY_ARRAY)));
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
new file mode 100644
index 0000000..8bec281
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MethodParametersTest.java
@@ -0,0 +1,100 @@
+// Copyright (c) 2021, 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.desugar.nestaccesscontrol;
+
+import static com.android.tools.r8.TestRuntime.getCheckedInJdk11;
+import static org.hamcrest.CoreMatchers.anyOf;
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.nestaccesscontrol.methodparameters.Outer;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MethodParametersTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ // java.lang.reflect.Method.getParameters() supported from Android 8.1.
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V8_1_0)
+ .withCfRuntimes()
+ .withAllApiLevelsAlsoForCf()
+ .build();
+ }
+
+ public MethodParametersTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ // Compile with javac from JDK 11 to get a class file using nest access control.
+ Path nestCompiledWithParameters =
+ javac(getCheckedInJdk11())
+ .addSourceFiles(ToolHelper.getSourceFileForTestClass(Outer.class))
+ .addOptions("-parameters")
+ .compile();
+
+ Path nestDesugared =
+ testForD8(Backend.CF)
+ .addProgramFiles(nestCompiledWithParameters)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+
+ Path nestDesugaredTwice =
+ testForD8(Backend.CF)
+ .addProgramFiles(nestDesugared)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ // TODO(b/189743726): These warnings should not be there.
+ .assertAtLeastOneInfoMessage()
+ .assertAllInfoMessagesMatch(
+ anyOf(
+ containsString("Invalid parameter counts in MethodParameter attributes"),
+ containsString("Methods with invalid MethodParameter attributes")))
+ .writeToZip();
+
+ Path programDesugared =
+ testForD8(Backend.CF)
+ .addClasspathClasses(Outer.class)
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+
+ testForD8(parameters.getBackend())
+ .addProgramFiles(nestDesugaredTwice)
+ .addProgramFiles(programDesugared)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ // TODO(b/189743726): These warnings should not be there.
+ .assertAtLeastOneInfoMessage()
+ .assertAllInfoMessagesMatch(
+ anyOf(
+ containsString("Invalid parameter counts in MethodParameter attributes"),
+ containsString("Methods with invalid MethodParameter attributes")))
+ .run(parameters.getRuntime(), TestRunner.class)
+ // TODO(b/189743726): Should not fail at runtime.
+ .assertFailureWithErrorThatMatches(
+ containsString("Wrong number of parameters in MethodParameters attribute"));
+ }
+
+ static class TestRunner {
+
+ public static void main(String[] args) {
+ Outer.callPrivateInnerConstructorZeroArgs();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/methodparameters/Outer.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/methodparameters/Outer.java
new file mode 100644
index 0000000..9c92994
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/methodparameters/Outer.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, 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.desugar.nestaccesscontrol.methodparameters;
+
+import java.lang.reflect.Constructor;
+
+public class Outer {
+ public static class Inner {
+ private Inner() {
+ for (Constructor<?> constructor : getClass().getDeclaredConstructors()) {
+ System.out.println(constructor.getParameters().length);
+ }
+ }
+
+ private Inner(int a) {}
+
+ private Inner(int a, int b) {}
+ }
+
+ public static Inner callPrivateInnerConstructorZeroArgs() {
+ return new Inner();
+ }
+
+ public static Inner callPrivateInnerConstructorOneArg() {
+ return new Inner(0);
+ }
+
+ public static Inner callPrivateInnerConstructorTwoArgs() {
+ return new Inner(0, 0);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
new file mode 100644
index 0000000..02ddfbc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/MethodParametersTest.java
@@ -0,0 +1,122 @@
+// Copyright (c) 2021, 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.desugaring.interfacemethods;
+
+import static com.android.tools.r8.TestRuntime.getCheckedInJdk8;
+import static org.hamcrest.CoreMatchers.anyOf;
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugaring.interfacemethods.methodparameters.I;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MethodParametersTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ // java.lang.reflect.Method.getParameters() supported from Android 8.1.
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V8_1_0)
+ .withCfRuntimes()
+ .withAllApiLevelsAlsoForCf()
+ .build();
+ }
+
+ public MethodParametersTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ Path compiledWithParameters =
+ javac(getCheckedInJdk8())
+ .addSourceFiles(ToolHelper.getSourceFileForTestClass(I.class))
+ .addOptions("-parameters")
+ .compile();
+
+ Path interfaceDesugared =
+ testForD8(Backend.CF)
+ .addProgramFiles(compiledWithParameters)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+
+ Path interfaceDesugaredTwice =
+ testForD8(Backend.CF)
+ .addProgramFiles(interfaceDesugared)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ // TODO(b/189743726): These warnings should not be there.
+ .applyIf(
+ parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring(),
+ TestCompileResult::assertNoInfoMessages,
+ r ->
+ r.assertAtLeastOneInfoMessage()
+ .assertAllInfoMessagesMatch(
+ anyOf(
+ containsString(
+ "Invalid parameter counts in MethodParameter attributes"),
+ containsString("Methods with invalid MethodParameter attributes"))))
+ .writeToZip();
+
+ Path programDesugared =
+ testForD8(Backend.CF)
+ .addClasspathClasses(I.class)
+ .addInnerClasses(getClass())
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .writeToZip();
+
+ testForD8(parameters.getBackend())
+ .addProgramFiles(interfaceDesugaredTwice)
+ .addProgramFiles(programDesugared)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ // TODO(b/189743726): These warnings should not be there.
+ .applyIf(
+ parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring(),
+ TestCompileResult::assertNoInfoMessages,
+ r ->
+ r.assertAtLeastOneInfoMessage()
+ .assertAllInfoMessagesMatch(
+ anyOf(
+ containsString(
+ "Invalid parameter counts in MethodParameter attributes"),
+ containsString("Methods with invalid MethodParameter attributes"))))
+ .run(parameters.getRuntime(), TestRunner.class)
+ .applyIf(
+ parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring(),
+ r -> r.assertSuccessWithOutputLines("0", "1", "2", "0", "1", "2"),
+ // TODO(b/189743726): Should not fail at runtime (but will have different parameter
+ // count for non-static methods when desugared).
+ r ->
+ r.assertFailureWithErrorThatMatches(
+ containsString("Wrong number of parameters in MethodParameters attribute")));
+ }
+
+ static class A implements I {}
+
+ static class TestRunner {
+
+ public static void main(String[] args) {
+ new A().zeroArgsDefault();
+ new A().oneArgDefault(0);
+ new A().twoArgDefault(0, 0);
+ I.zeroArgStatic();
+ I.oneArgStatic(0);
+ I.twoArgsStatic(0, 0);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/methodparameters/I.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/methodparameters/I.java
new file mode 100644
index 0000000..4c7ba69
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/methodparameters/I.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2021, 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.desugaring.interfacemethods.methodparameters;
+
+public interface I {
+
+ default void zeroArgsDefault() {
+ System.out.println(new Object() {}.getClass().getEnclosingMethod().getParameters().length);
+ }
+
+ default void oneArgDefault(int a) {
+ System.out.println(new Object() {}.getClass().getEnclosingMethod().getParameters().length);
+ }
+
+ default void twoArgDefault(int a, int b) {
+ System.out.println(new Object() {}.getClass().getEnclosingMethod().getParameters().length);
+ }
+
+ static void zeroArgStatic() {
+ System.out.println(new Object() {}.getClass().getEnclosingMethod().getParameters().length);
+ }
+
+ static void oneArgStatic(int a) {
+ System.out.println(new Object() {}.getClass().getEnclosingMethod().getParameters().length);
+ }
+
+ static void twoArgsStatic(int a, int b) {
+ System.out.println(new Object() {}.getClass().getEnclosingMethod().getParameters().length);
+ }
+}