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);
+  }
+}