Add --pg-map-output and proguardMapConsumer to L8 command

This will allow consumers to obtain the produced proguard map by L8.

Bug: 182266325
Change-Id: Iae7112ca69e7825942e5de6968d5dd7b0f4448e0
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index f0cb3e8..555713b 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -206,6 +206,7 @@
     private BiPredicate<String, Long> dexClassChecksumFilter = (name, checksum) -> true;
     private List<AssertionsConfiguration> assertionsConfiguration = new ArrayList<>();
     private List<Consumer<Inspector>> outputInspections = new ArrayList<>();
+    protected StringConsumer proguardMapConsumer = null;
 
     abstract CompilationMode defaultCompilationMode();
 
@@ -278,6 +279,33 @@
     }
 
     /**
+     * Set an output destination to which proguard-map content should be written.
+     *
+     * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
+     * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
+     * #setProguardMapConsumer} will override the previous setting.
+     *
+     * @param proguardMapOutput File-system path to write output at.
+     */
+    B setProguardMapOutputPath(Path proguardMapOutput) {
+      assert proguardMapOutput != null;
+      return setProguardMapConsumer(new StringConsumer.FileConsumer(proguardMapOutput));
+    }
+
+    /**
+     * Set a consumer for receiving the proguard-map content.
+     *
+     * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
+     * override the previous setting.
+     *
+     * @param proguardMapConsumer Consumer to receive the content once produced.
+     */
+    B setProguardMapConsumer(StringConsumer proguardMapConsumer) {
+      this.proguardMapConsumer = proguardMapConsumer;
+      return self();
+    }
+
+    /**
      * Get the main dex list consumer that will receive the final complete main dex list.
      */
     public StringConsumer getMainDexListConsumer() {
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 4c235d9..1fc7689 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -253,6 +253,33 @@
       return self();
     }
 
+    /**
+     * Set an output destination to which proguard-map content should be written.
+     *
+     * <p>This is a short-hand for setting a {@link StringConsumer.FileConsumer} using {@link
+     * #setProguardMapConsumer}. Note that any subsequent call to this method or {@link
+     * #setProguardMapConsumer} will override the previous setting.
+     *
+     * @param proguardMapOutput File-system path to write output at.
+     */
+    @Override
+    public L8Command.Builder setProguardMapOutputPath(Path proguardMapOutput) {
+      return super.setProguardMapOutputPath(proguardMapOutput);
+    }
+
+    /**
+     * Set a consumer for receiving the proguard-map content.
+     *
+     * <p>Note that any subsequent call to this method or {@link #setProguardMapOutputPath} will
+     * override the previous setting.
+     *
+     * @param proguardMapConsumer Consumer to receive the content once produced.
+     */
+    @Override
+    public L8Command.Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
+      return super.setProguardMapConsumer(proguardMapConsumer);
+    }
+
     @Override
     void validate() {
       if (isPrintHelp()) {
@@ -273,6 +300,9 @@
       if (isShrinking() && getProgramConsumer() instanceof ClassFileConsumer) {
         reporter.error("L8 does not support shrinking when generating class files");
       }
+      if (!isShrinking() && proguardMapConsumer != null) {
+        reporter.error("L8 does not support defining a map consumer when not shrinking");
+      }
       super.validate();
     }
 
@@ -294,7 +324,7 @@
       D8Command d8Command = null;
 
       AndroidApp inputs = getAppBuilder().build();
-      ProgramConsumer l8CfConsumer = null;
+      ProgramConsumer l8CfConsumer;
       if (isShrinking()) {
         l8CfConsumer = new InMemoryJarContent();
         R8Command.Builder r8Builder =
@@ -314,6 +344,9 @@
         for (Pair<List<String>, Origin> proguardConfig : proguardConfigStrings) {
           r8Builder.addProguardConfiguration(proguardConfig.getFirst(), proguardConfig.getSecond());
         }
+        if (proguardMapConsumer != null) {
+          r8Builder.setProguardMapConsumer(proguardMapConsumer);
+        }
         r8Builder.addProguardConfiguration(
             libraryConfiguration.getExtraKeepRules(), Origin.unknown());
         // TODO(b/180903899): Remove rule when -dontwarn sun.misc.Unsafe is part of config.
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java
index 3dac9dc..402e59a 100644
--- a/src/main/java/com/android/tools/r8/L8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -18,8 +18,15 @@
 
 public class L8CommandParser extends BaseCompilerCommandParser<L8Command, L8Command.Builder> {
 
-  private static final Set<String> OPTIONS_WITH_PARAMETER = ImmutableSet.of(
-      "--output", "--lib", MIN_API_FLAG, "--desugared-lib", THREAD_COUNT_FLAG, "--pg-conf");
+  private static final Set<String> OPTIONS_WITH_PARAMETER =
+      ImmutableSet.of(
+          "--output",
+          "--lib",
+          MIN_API_FLAG,
+          "--desugared-lib",
+          THREAD_COUNT_FLAG,
+          "--pg-conf",
+          "--pg-map-output");
 
   public static void main(String[] args) throws CompilationFailedException {
     L8Command command = parse(args, Origin.root()).build();
@@ -50,6 +57,8 @@
                       + AndroidApiLevel.getDefault().getLevel()
                       + ".",
                   "  --pg-conf <file>        # Proguard configuration <file>.",
+                  "  --pg-map-output <file>  # Output the resulting name and line mapping to"
+                      + " <file>.",
                   "  --desugared-lib <file>  # Specify desugared library configuration.",
                   "                          # <file> is a desugared library configuration"
                       + " (json)."),
@@ -149,6 +158,8 @@
         addLibraryArgument(builder, origin, nextArg);
       } else if (arg.equals("--pg-conf")) {
         builder.addProguardConfigurationFiles(Paths.get(nextArg));
+      } else if (arg.equals("--pg-map-output")) {
+        builder.setProguardMapOutputPath(Paths.get(nextArg));
       } else if (arg.equals("--desugared-lib")) {
         builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg)));
       } else if (arg.equals("--classfile")) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 9663d3f..2b3f988 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -102,7 +102,6 @@
     private boolean disableVerticalClassMerging = false;
     private boolean forceProguardCompatibility = false;
     private Optional<Boolean> includeDataResources = Optional.empty();
-    private StringConsumer proguardMapConsumer = null;
     private StringConsumer proguardUsageConsumer = null;
     private StringConsumer proguardSeedsConsumer = null;
     private StringConsumer proguardConfigurationConsumer = null;
@@ -237,10 +236,9 @@
      *
      * @param proguardMapOutput File-system path to write output at.
      */
+    @Override
     public Builder setProguardMapOutputPath(Path proguardMapOutput) {
-      assert proguardMapOutput != null;
-      this.proguardMapConsumer = new StringConsumer.FileConsumer(proguardMapOutput);
-      return self();
+      return super.setProguardMapOutputPath(proguardMapOutput);
     }
 
     /**
@@ -251,9 +249,9 @@
      *
      * @param proguardMapConsumer Consumer to receive the content once produced.
      */
+    @Override
     public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
-      this.proguardMapConsumer = proguardMapConsumer;
-      return self();
+      return super.setProguardMapConsumer(proguardMapConsumer);
     }
 
     /**