API for desugared lib keep rules

Bug:134732760
Change-Id: If0d1b8b3b19bff6e379fce598957f7e6679c87bd
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 4925c20..06d743e 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -65,6 +65,7 @@
 
     private boolean intermediate = false;
     private DesugarGraphConsumer desugarGraphConsumer = null;
+    private StringConsumer desugaredLibraryKeepRuleConsumer = null;
 
     private Builder() {
       this(new DefaultD8DiagnosticsHandler());
@@ -113,6 +114,17 @@
       return self();
     }
 
+    /**
+     * Set a consumer for receiving the keep rules to use when compiling the desugared library for
+     * the program being compiled in this compilation.
+     *
+     * @param keepRuleConsumer Consumer to receive the content once produced.
+     */
+    public Builder setDesugaredLibraryKeepRuleConsumer(StringConsumer keepRuleConsumer) {
+      this.desugaredLibraryKeepRuleConsumer = keepRuleConsumer;
+      return self();
+    }
+
     /** Get the consumer that will receive dependency information for desugaring. */
     public DesugarGraphConsumer getDesugarGraphConsumer() {
       return desugarGraphConsumer;
@@ -190,7 +202,8 @@
           getSpecialLibraryConfiguration(),
           getIncludeClassesChecksum(),
           getDexClassChecksumFilter(),
-          getDesugarGraphConsumer());
+          getDesugarGraphConsumer(),
+          desugaredLibraryKeepRuleConsumer);
     }
   }
 
@@ -198,6 +211,7 @@
 
   private final boolean intermediate;
   private final DesugarGraphConsumer desugarGraphConsumer;
+  private final StringConsumer desugaredLibraryKeepRuleConsumer;
 
   public static Builder builder() {
     return new Builder();
@@ -252,7 +266,8 @@
       String specialLibraryConfiguration,
       boolean encodeChecksum,
       BiPredicate<String, Long> dexClassChecksumFilter,
-      DesugarGraphConsumer desugarGraphConsumer) {
+      DesugarGraphConsumer desugarGraphConsumer,
+      StringConsumer desugaredLibraryKeepRuleConsumer) {
     super(
         inputApp,
         mode,
@@ -267,12 +282,14 @@
         dexClassChecksumFilter);
     this.intermediate = intermediate;
     this.desugarGraphConsumer = desugarGraphConsumer;
+    this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
   }
 
   private D8Command(boolean printHelp, boolean printVersion) {
     super(printHelp, printVersion);
     intermediate = false;
     desugarGraphConsumer = null;
+    desugaredLibraryKeepRuleConsumer = null;
   }
 
   private void configureLibraryDesugaring(InternalOptions options) {
@@ -330,6 +347,8 @@
       configureLibraryDesugaring(internal);
     }
 
+    internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
+
     return internal;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 2032bec..7866c41 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -82,6 +82,7 @@
     private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
     private Consumer<ProguardConfiguration.Builder> proguardConfigurationConsumerForTesting = null;
     private Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer = null;
+    private StringConsumer desugaredLibraryKeepRuleConsumer = null;
     private final List<ProguardConfigurationSource> proguardConfigs = new ArrayList<>();
     private boolean disableTreeShaking = false;
     private boolean disableMinification = false;
@@ -243,6 +244,17 @@
     }
 
     /**
+     * Set a consumer for receiving the keep rules to use when compiling the desugared library for
+     * the program being compiled in this compilation.
+     *
+     * @param keepRuleConsumer Consumer to receive the content once produced.
+     */
+    public Builder setDesugaredLibraryKeepRuleConsumer(StringConsumer keepRuleConsumer) {
+      this.desugaredLibraryKeepRuleConsumer = keepRuleConsumer;
+      return self();
+    }
+
+    /**
      * Set a consumer for receiving the proguard usage information.
      *
      * <p>Note that any subsequent calls to this method will replace the previous setting.
@@ -512,7 +524,8 @@
               isOptimizeMultidexForLinearAlloc(),
               getSpecialLibraryConfiguration(),
               getIncludeClassesChecksum(),
-              getDexClassChecksumFilter());
+              getDexClassChecksumFilter(),
+              desugaredLibraryKeepRuleConsumer);
 
       return command;
     }
@@ -592,6 +605,7 @@
   private final GraphConsumer keptGraphConsumer;
   private final GraphConsumer mainDexKeptGraphConsumer;
   private final Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer;
+  private final StringConsumer desugaredLibraryKeepRuleConsumer;
 
   /** Get a new {@link R8Command.Builder}. */
   public static Builder builder() {
@@ -665,7 +679,8 @@
       boolean optimizeMultidexForLinearAlloc,
       String specialLibraryConfiguration,
       boolean encodeChecksum,
-      BiPredicate<String, Long> dexClassChecksumFilter) {
+      BiPredicate<String, Long> dexClassChecksumFilter,
+      StringConsumer desugaredLibraryKeepRuleConsumer) {
     super(
         inputApp,
         mode,
@@ -694,6 +709,7 @@
     this.keptGraphConsumer = keptGraphConsumer;
     this.mainDexKeptGraphConsumer = mainDexKeptGraphConsumer;
     this.syntheticProguardRulesConsumer = syntheticProguardRulesConsumer;
+    this.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
   }
 
   private R8Command(boolean printHelp, boolean printVersion) {
@@ -712,6 +728,7 @@
     keptGraphConsumer = null;
     mainDexKeptGraphConsumer = null;
     syntheticProguardRulesConsumer = null;
+    desugaredLibraryKeepRuleConsumer = null;
   }
 
   /** Get the enable-tree-shaking state. */
@@ -835,6 +852,8 @@
       configureLibraryDesugaring(internal);
     }
 
+    internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
+
     return internal;
   }
 
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index 8aa69a3..355d32d 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -150,7 +150,7 @@
         }
         sb.append("}").append(cr);
       }
-      options.testing.desugaredLibraryKeepRuleConsumer.accept(sb.toString(), options.reporter);
+      options.desugaredLibraryKeepRuleConsumer.accept(sb.toString(), options.reporter);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 6920e83..0dac6a9 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -220,9 +220,8 @@
     writeSignature(layout);
     writeChecksum(layout);
 
-    // A consumer can manage the generated keep rules (testing only).
-    if (options.testing.desugaredLibraryKeepRuleConsumer != null
-        && !desugaredLibraryCodeToKeep.isNop()) {
+    // A consumer can manage the generated keep rules.
+    if (options.desugaredLibraryKeepRuleConsumer != null && !desugaredLibraryCodeToKeep.isNop()) {
       assert !options.coreLibraryCompilation;
       desugaredLibraryCodeToKeep.generateKeepRules(options);
     }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index f867f31..2b170ba 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -626,6 +626,10 @@
   // If non-null, configuration must be passed to the consumer.
   public StringConsumer configurationConsumer = null;
 
+  // If null, no keep rules are recorded.
+  // If non null it records desugared library APIs used by the program.
+  public StringConsumer desugaredLibraryKeepRuleConsumer = null;
+
   // If null, no graph information needs to be provided for the keep/inclusion of classes
   // in the output. If non-null, each edge pertaining to kept parts of the resulting program
   // must be reported to the consumer.
@@ -990,7 +994,6 @@
     public boolean disallowLoadStoreOptimization = false;
     public boolean enableNarrowingChecksInD8 = false;
     public Consumer<IRCode> irModifier = null;
-    public StringConsumer desugaredLibraryKeepRuleConsumer = null;
     // TODO(b/129458850) When fixed, remove this and change all usages to "true".
     public boolean enableStatefulLambdaCreateInstanceMethod = false;
     public int basicBlockMuncherIterationLimit = NO_LIMIT;
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index 5900c6b..870d7c8 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import com.android.sdklib.AndroidVersion;
@@ -20,6 +21,7 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.ZipUtils;
 import com.google.common.collect.ImmutableList;
@@ -84,6 +86,18 @@
   }
 
   @Test
+  public void desugaredLibraryKeepRuleConsumer() throws Exception {
+    Box<String> holder = new Box<>("");
+    StringConsumer stringConsumer = (string, handler) -> holder.set(holder.get() + string);
+    D8Command command =
+        D8Command.builder()
+            .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+            .setDesugaredLibraryKeepRuleConsumer(stringConsumer)
+            .build();
+    assertSame(command.getInternalOptions().desugaredLibraryKeepRuleConsumer, stringConsumer);
+  }
+
+  @Test
   public void defaultOutIsCwd() throws Throwable {
     Path working = temp.getRoot().toPath();
     Path input = Paths.get(EXAMPLES_BUILD_DIR + "/arithmetic.jar").toAbsolutePath();
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index aa29a22..68aea3d 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -7,6 +7,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ProgramResource.Kind;
@@ -16,6 +17,7 @@
 import com.android.tools.r8.origin.EmbeddedOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.ZipUtils;
 import com.google.common.collect.ImmutableList;
@@ -86,6 +88,18 @@
   }
 
   @Test
+  public void desugaredLibraryKeepRuleConsumer() throws Exception {
+    Box<String> holder = new Box<>("");
+    StringConsumer stringConsumer = (string, handler) -> holder.set(holder.get() + string);
+    D8Command command =
+        D8Command.builder()
+            .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+            .setDesugaredLibraryKeepRuleConsumer(stringConsumer)
+            .build();
+    assertSame(command.getInternalOptions().desugaredLibraryKeepRuleConsumer, stringConsumer);
+  }
+
+  @Test
   public void defaultOutIsCwd() throws Throwable {
     Path working = temp.getRoot().toPath();
     Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar").toAbsolutePath();
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
index 099c560..1ce8d7b 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
@@ -55,7 +55,7 @@
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(
                 options ->
-                    options.testing.desugaredLibraryKeepRuleConsumer =
+                    options.desugaredLibraryKeepRuleConsumer =
                         (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
             .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .compile()
@@ -90,7 +90,7 @@
             .addKeepClassAndMembersRules(Executor.class)
             .addOptionsModification(
                 options ->
-                    options.testing.desugaredLibraryKeepRuleConsumer =
+                    options.desugaredLibraryKeepRuleConsumer =
                         (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
             .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .compile()
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java
index fb1c722..7504eb1 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java
@@ -62,7 +62,7 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
         .addOptionsModification(
             options ->
-                options.testing.desugaredLibraryKeepRuleConsumer =
+                options.desugaredLibraryKeepRuleConsumer =
                     (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
         .compile()
         .inspect(this::checkRewrittenInvokes)
@@ -85,7 +85,7 @@
         .enableCoreLibraryDesugaring(parameters.getApiLevel())
         .addOptionsModification(
             options ->
-                options.testing.desugaredLibraryKeepRuleConsumer =
+                options.desugaredLibraryKeepRuleConsumer =
                     (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
         .compile()
         .inspect(this::checkRewrittenInvokes)
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
index 8aeddab..229c67c 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
@@ -64,7 +64,7 @@
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(
                 options ->
-                    options.testing.desugaredLibraryKeepRuleConsumer =
+                    options.desugaredLibraryKeepRuleConsumer =
                         (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
             .enableCoreLibraryDesugaring()
             .compile()
@@ -101,7 +101,7 @@
               .setMinApi(parameters.getApiLevel())
               .addOptionsModification(
                   options ->
-                      options.testing.desugaredLibraryKeepRuleConsumer =
+                      options.desugaredLibraryKeepRuleConsumer =
                           (string, handler) -> keepRulesHolder.set(keepRulesHolder.get() + string))
               .enableCoreLibraryDesugaring()
               .compile()