[Metadata] Add support for keepkotlinmetadata

Bug: b/234559869
Bug: b/234558357
Change-Id: I09f87a72a61199fba58b7ad6ad51034851e3ffe5
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index c4af05f..84ce118 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
+import static com.android.tools.r8.shaking.ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS;
 import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptor;
 
 import com.android.tools.r8.InputDependencyGraphConsumer;
@@ -65,20 +66,22 @@
   private static final List<String> IGNORED_OPTIONAL_SINGLE_ARG_OPTIONS =
       ImmutableList.of("runtype", "laststageoutput");
 
-  private static final List<String> IGNORED_FLAG_OPTIONS = ImmutableList.of(
-      "forceprocessing",
-      "dontpreverify",
-      "experimentalshrinkunusedprotofields",
-      "filterlibraryjarswithorginalprogramjars",
-      "dontskipnonpubliclibraryclasses",
-      "dontskipnonpubliclibraryclassmembers",
-      "invokebasemethod",
-      // TODO(b/62524562): we may support this later.
-      "mergeinterfacesaggressively",
-      "android",
-      "allowruntypeandignoreoptimizationpasses",
-      "dontshrinkduringoptimization",
-      "convert_proto_enum_to_string");
+  private static final List<String> IGNORED_FLAG_OPTIONS =
+      ImmutableList.of(
+          "forceprocessing",
+          "dontpreverify",
+          "experimentalshrinkunusedprotofields",
+          "filterlibraryjarswithorginalprogramjars",
+          "dontskipnonpubliclibraryclasses",
+          "dontskipnonpubliclibraryclassmembers",
+          "invokebasemethod",
+          // TODO(b/62524562): we may support this later.
+          "mergeinterfacesaggressively",
+          "android",
+          "allowruntypeandignoreoptimizationpasses",
+          "dontshrinkduringoptimization",
+          "convert_proto_enum_to_string",
+          "adaptkotlinmetadata");
 
   private static final List<String> IGNORED_CLASS_DESCRIPTOR_OPTIONS =
       ImmutableList.of(
@@ -275,12 +278,23 @@
           || parseTestingOption(optionStart)
           || parseUnsupportedOptionAndErr(optionStart)) {
         // Intentionally left empty.
-      } else if (acceptString("adaptkotlinmetadata")) {
-        reporter.info(
-            new StringDiagnostic(
-                "Ignoring -adaptkotlinmetadata because R8 always process kotlin.Metadata",
-                origin,
-                getPosition(optionStart)));
+      } else if (acceptString("keepkotlinmetadata")) {
+        configurationBuilder.addRule(
+            ProguardKeepRule.builder()
+                .setType(ProguardKeepRuleType.KEEP)
+                .setClassType(ProguardClassType.CLASS)
+                .setOrigin(origin)
+                .setStart(optionStart)
+                .setClassNames(
+                    ProguardClassNameList.builder()
+                        .addClassName(
+                            false, ProguardTypeMatcher.create(dexItemFactory.kotlinMetadataType))
+                        .build())
+                .setMemberRules(Collections.singletonList(ProguardMemberRule.defaultKeepAllRule()))
+                .setSource("-keepkotlinmetadata")
+                .build());
+        configurationBuilder.addKeepAttributePatterns(
+            Collections.singletonList(RUNTIME_VISIBLE_ANNOTATIONS));
       } else if (acceptString("renamesourcefileattribute")) {
         skipWhitespace();
         if (isOptionalArgumentGiven()) {
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 5445d03..2f78421 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -176,7 +176,7 @@
   }
 
   public T addKeepKotlinMetadata() {
-    return addKeepRules("-keep class kotlin.Metadata { *; }");
+    return addKeepRules("-keepkotlinmetadata");
   }
 
   public T addKeepAllClassesRule() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
index 8230cef..ee16233 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -47,7 +46,6 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepKotlinMetadata()
         .addKeepRules(StringUtils.joinLines("-if class *.Metadata", "-keep class <1>.io.** { *; }"))
-        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .allowDiagnosticWarningMessages()
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
index 1acdcf2..7a7aec4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
@@ -11,7 +11,6 @@
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.graph.DexAnnotationElement;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -49,7 +48,6 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepAllClassesRuleWithAllowObfuscation()
         .addKeepKotlinMetadata()
-        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .allowDiagnosticWarningMessages()
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
index 8bcbc9e..1c93e08 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
@@ -90,7 +90,6 @@
         .addKeepRules(OBFUSCATE_RENAMED, KEEP_KEPT)
         .addKeepRules("-keep class **.Anno")
         .addKeepKotlinMetadata()
-        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .allowDiagnosticWarningMessages()
         .compile()
         .assertWarningMessageThatMatches(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
index 68731b5..16fc35d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
@@ -42,7 +42,6 @@
         .setMinApi(parameters.getApiLevel())
         .addKeepKotlinMetadata()
         .addKeepRules("-keep class kotlin.io.** { *; }")
-        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
         .allowDiagnosticWarningMessages()
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 64e7bd8..ceb7d56 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -50,7 +50,6 @@
         .addKeepAllClassesRule()
         .addKeepKotlinMetadata()
         .addKeepAttributes(
-            ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
             ProguardKeepAttributes.INNER_CLASSES,
             ProguardKeepAttributes.ENCLOSING_METHOD)
         .allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
index 07e22c5..5d13395 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteUnitPrimitiveTest.java
@@ -101,7 +101,6 @@
                 kotlinc.getKotlinStdlibJar())
             .addKeepClassAndMembersRules(PKG_LIB + ".*")
             .addKeepAttributes(
-                ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
index 5d715f1..baf09cc 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -55,7 +54,6 @@
             .addProgramFiles(kotlinc.getKotlinReflectJar(), kotlinc.getKotlinAnnotationJar())
             .addKeepMainRule(mainClassName)
             .addKeepKotlinMetadata()
-            .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
             .allowDiagnosticWarningMessages()
             .setMinApi(parameters.getApiLevel())
             .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.isNot(KOTLINC_1_3_72))
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 6c05cb7..dede54c 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -92,6 +92,8 @@
       VALID_PROGUARD_DIR + "assume-values-with-return-value.flags";
   private static final String ADAPT_KOTLIN_METADATA =
       VALID_PROGUARD_DIR + "adapt-kotlin-metadata.flags";
+  private static final String KEEP_KOTLIN_METADATA =
+      VALID_PROGUARD_DIR + "keep-kotlin-metadata.flags";
   private static final String INCLUDING =
       VALID_PROGUARD_DIR + "including.flags";
   private static final String INVALID_INCLUDING_1 =
@@ -846,7 +848,22 @@
         new ProguardConfigurationParser(new DexItemFactory(), reporter);
     Path path = Paths.get(ADAPT_KOTLIN_METADATA);
     parser.parse(path);
-    checkDiagnostics(handler.infos, path, 1, 1, "Ignoring", "-adaptkotlinmetadata");
+    verifyParserEndsCleanly();
+  }
+
+  @Test
+  public void parseKeepKotlinMetadata() {
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    Path path = Paths.get(KEEP_KOTLIN_METADATA);
+    parser.parse(path);
+    verifyParserEndsCleanly();
+    ProguardConfiguration config = parser.getConfig();
+    assertEquals(
+        "-keepattributes RuntimeVisibleAnnotations", config.getKeepAttributes().toString());
+    assertEquals(
+        StringUtils.joinLines("-keep class kotlin.Metadata {", "  *;", "}"),
+        config.getRules().get(0).toString());
   }
 
   @Test