Add reproduction of removed fields in kotlin.Metadata

Bug: 161230424
Change-Id: I666ca2f39f230c82e53608f2af7bb45b4773bec3
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
new file mode 100644
index 0000000..41a60a4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
@@ -0,0 +1,103 @@
+// Copyright (c) 2020, 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.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.kotlin.metadata.metadata_pruned_fields.Main;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/** This is a reproduction of b/161230424. */
+@RunWith(Parameterized.class)
+public class MetadataPrunedFieldsTest extends KotlinMetadataTestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0} target: {1}")
+  public static Collection<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+  }
+
+  public MetadataPrunedFieldsTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
+    super(targetVersion);
+    this.parameters = parameters;
+  }
+
+  private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+
+  @BeforeClass
+  public static void createLibJar() throws Exception {
+    String baseLibFolder = PKG_PREFIX + "/metadata_pruned_fields";
+    for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+      Path baseLibJar =
+          kotlinc(KOTLINC, targetVersion)
+              .addSourceFiles(getKotlinFileInTest(baseLibFolder, "Methods"))
+              .compile();
+      libJars.put(targetVersion, baseLibJar);
+    }
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    final R8TestRunResult runResult =
+        testForR8(parameters.getBackend())
+            .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+            .addProgramFiles(libJars.get(targetVersion))
+            .addProgramClassFileData(Main.dump())
+            .addKeepRules("-keep class " + PKG + ".metadata_pruned_fields.MethodsKt { *; }")
+            .addKeepRules("-keep class kotlin.Metadata { *** pn(); }")
+            .addKeepMainRule(Main.class)
+            .allowDiagnosticWarningMessages()
+            .setMinApi(parameters.getApiLevel())
+            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+            .compile()
+            .inspect(
+                codeInspector -> {
+                  final ClassSubject clazz = codeInspector.clazz("kotlin.Metadata");
+                  assertThat(clazz, isPresent());
+                  assertThat(clazz.uniqueMethodWithName("pn"), isPresent());
+                  assertThat(clazz.uniqueMethodWithName("d1"), not(isPresent()));
+                  assertThat(clazz.uniqueMethodWithName("d2"), not(isPresent()));
+                  assertThat(clazz.uniqueMethodWithName("bv"), not(isPresent()));
+                })
+            .assertAllWarningMessagesMatch(
+                equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+            .run(parameters.getRuntime(), Main.class);
+    if (parameters.getRuntime().isCf()) {
+      runResult.assertSuccessWithOutputLines("", "Hello World!");
+      return;
+    }
+    final DexVm vm = parameters.getRuntime().asDex().getVm();
+    if (vm.isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
+      runResult.assertFailureWithErrorThatMatches(
+          containsString("java.lang.RuntimeException: failure in processEncodedAnnotation"));
+    } else if (vm.isOlderThanOrEqual(DexVm.ART_6_0_1_HOST)) {
+      runResult.assertFailureWithErrorThatMatches(
+          containsString("java.lang.IncompatibleClassChangeError: Couldn't find kotlin.Metadata."));
+    } else {
+      runResult.assertFailureWithErrorThatMatches(containsString("java.lang.NullPointerException"));
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main.java b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main.java
new file mode 100644
index 0000000..10ebf6b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2020, 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.kotlin.metadata.metadata_pruned_fields;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class Main implements Opcodes {
+
+  // The dump is generated from the code below, which cannot compile because of a missing
+  // reference to MethodsKt.
+  //
+  // public static void main(String[] args) {
+  //   final kotlin.Metadata annotation = MethodsKt.class.getAnnotation(kotlin.Metadata.class);
+  //   System.out.println(annotation.pn());
+  //   MethodsKt.staticMethod();
+  // }
+
+  public static byte[] dump() {
+
+    ClassWriter classWriter = new ClassWriter(0);
+    MethodVisitor methodVisitor;
+
+    classWriter.visit(
+        V1_8,
+        ACC_PUBLIC | ACC_SUPER,
+        "com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main",
+        null,
+        "java/lang/Object",
+        new String[] {});
+
+    {
+      methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+      methodVisitor.visitCode();
+      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, "main", "([Ljava/lang/String;)V", null, null);
+      methodVisitor.visitCode();
+      methodVisitor.visitLdcInsn(
+          Type.getType("Lcom/android/tools/r8/kotlin/metadata/metadata_pruned_fields/MethodsKt;"));
+      methodVisitor.visitLdcInsn(Type.getType("Lkotlin/Metadata;"));
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL,
+          "java/lang/Class",
+          "getAnnotation",
+          "(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;",
+          false);
+      methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/Metadata");
+      methodVisitor.visitVarInsn(ASTORE, 1);
+      methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+      methodVisitor.visitVarInsn(ALOAD, 1);
+      methodVisitor.visitMethodInsn(
+          INVOKEINTERFACE, "kotlin/Metadata", "pn", "()Ljava/lang/String;", true);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      methodVisitor.visitMethodInsn(
+          INVOKESTATIC,
+          "com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/MethodsKt",
+          "staticMethod",
+          "()V",
+          false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(2, 2);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Methods.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Methods.kt
new file mode 100644
index 0000000..5f67164
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Methods.kt
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, 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.kotlin.metadata.metadata_pruned_fields
+
+fun staticMethod() {
+  println("Hello World!")
+}
\ No newline at end of file