Add markers to proguard map output.

The following markers are added to the end of the Proguard-map as a comment:
compiler, compiler_version, compiler_hash, min_api.

Bug: 70040153
Change-Id: I9b3e5befc9b64a55e42f7161d4d29b2397f26183
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 901c490..525645a 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -437,9 +437,11 @@
                 namingLens,
                 options.lineNumberOptimization == LineNumberOptimization.IDENTITY_MAPPING);
         timing.end();
-        proguardMapSupplier = ProguardMapSupplier.fromClassNameMapper(classNameMapper);
+        proguardMapSupplier =
+            ProguardMapSupplier.fromClassNameMapper(classNameMapper, options.minApiLevel);
       } else {
-        proguardMapSupplier = ProguardMapSupplier.fromNamingLens(namingLens, application);
+        proguardMapSupplier =
+            ProguardMapSupplier.fromNamingLens(namingLens, application, options.minApiLevel);
       }
 
       // If a method filter is present don't produce output since the application is likely partial.
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
index 3863c14..495738d 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapSupplier.java
@@ -3,42 +3,80 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import com.android.tools.r8.Version;
 import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.utils.VersionProperties;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
 
 public class ProguardMapSupplier {
-  public static ProguardMapSupplier fromClassNameMapper(ClassNameMapper classNameMapper) {
-    return new ProguardMapSupplier(classNameMapper);
+
+  public static final String MARKER_KEY_COMPILER = "compiler";
+  public static final String MARKER_VALUE_COMPILER = "R8";
+  public static final String MARKER_KEY_COMPILER_VERSION = "compiler_version";
+  public static final String MARKER_KEY_COMPILER_HASH = "compiler_hash";
+  public static final String MARKER_KEY_MIN_API = "min_api";
+
+  public static ProguardMapSupplier fromClassNameMapper(
+      ClassNameMapper classNameMapper, int minApiLevel) {
+    return new ProguardMapSupplier(classNameMapper, minApiLevel);
   }
 
   public static ProguardMapSupplier fromNamingLens(
-      NamingLens namingLens, DexApplication dexApplication) {
-    return new ProguardMapSupplier(namingLens, dexApplication);
+      NamingLens namingLens, DexApplication dexApplication, int minApiLevel) {
+    return new ProguardMapSupplier(namingLens, dexApplication, minApiLevel);
   }
 
-  private ProguardMapSupplier(ClassNameMapper classNameMapper) {
+  private ProguardMapSupplier(ClassNameMapper classNameMapper, int minApiLevel) {
     this.useClassNameMapper = true;
     this.classNameMapper = classNameMapper;
     this.namingLens = null;
     this.application = null;
+    this.minApiLevel = minApiLevel;
   }
 
-  private ProguardMapSupplier(NamingLens namingLens, DexApplication dexApplication) {
+  private ProguardMapSupplier(
+      NamingLens namingLens, DexApplication dexApplication, int minApiLevel) {
     this.useClassNameMapper = false;
     this.classNameMapper = null;
     this.namingLens = namingLens;
     this.application = dexApplication;
+    this.minApiLevel = minApiLevel;
   }
 
   private final boolean useClassNameMapper;
   private final ClassNameMapper classNameMapper;
   private final NamingLens namingLens;
   private final DexApplication application;
+  private final int minApiLevel;
 
   public String get() {
+    String shaLine = "";
+    if (Version.isDev()) {
+      shaLine = "# " + MARKER_KEY_COMPILER_HASH + ": " + VersionProperties.INSTANCE.getSha() + "\n";
+    }
+    return "# "
+        + MARKER_KEY_COMPILER
+        + ": "
+        + MARKER_VALUE_COMPILER
+        + "\n"
+        + "# "
+        + MARKER_KEY_COMPILER_VERSION
+        + ": "
+        + Version.LABEL
+        + "\n"
+        + "# "
+        + MARKER_KEY_MIN_API
+        + ": "
+        + minApiLevel
+        + "\n"
+        + shaLine
+        + getBody();
+  }
+
+  private String getBody() {
     if (useClassNameMapper) {
       assert classNameMapper != null;
       return classNameMapper.toString();
diff --git a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
new file mode 100644
index 0000000..8e8ca36
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
@@ -0,0 +1,83 @@
+// Copyright (c) 2018, 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.naming.ProguardMapSupplier;
+import com.android.tools.r8.utils.VersionProperties;
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+
+public class ProguardMapMarkerTest {
+  @Test
+  public void proguardMapMarkerTest24() throws CompilationFailedException {
+    proguardMapMarkerTest(24);
+  }
+
+  @Test
+  public void proguardMapMarkerTest26() throws CompilationFailedException {
+    proguardMapMarkerTest(26);
+  }
+
+  private void proguardMapMarkerTest(int minApiLevel) throws CompilationFailedException {
+    String classFile = ToolHelper.EXAMPLES_BUILD_DIR + "classes/trivial/Trivial.class";
+    R8.run(
+        R8Command.builder()
+            .addProgramFiles(Paths.get(classFile))
+            .setProgramConsumer(
+                new DexIndexedConsumer() {
+                  @Override
+                  public void accept(
+                      int fileIndex,
+                      byte[] data,
+                      Set<String> descriptors,
+                      DiagnosticsHandler handler) {}
+
+                  @Override
+                  public void finished(DiagnosticsHandler handler) {}
+                })
+            .addLibraryFiles(ToolHelper.getAndroidJar(minApiLevel))
+            .setMinApiLevel(minApiLevel)
+            .setProguardMapConsumer(
+                (proguardMap, handler) -> {
+                  verifyMarkers(proguardMap, minApiLevel);
+                })
+            .build());
+  }
+
+  private static void verifyMarkers(String proguardMap, int minApiLevel) {
+    String[] lines = proguardMap.split("\n");
+    Set<String> keysFound = new HashSet<>();
+    for (String line : lines) {
+      if (!line.startsWith("#")) {
+        continue;
+      }
+      String comment = line.substring(1).trim();
+      int colonIndex = comment.indexOf(":");
+      if (colonIndex < 0) {
+        continue;
+      }
+      String key = comment.substring(0, colonIndex).trim();
+      String value = comment.substring(colonIndex + 1).trim();
+      if (key.equals(ProguardMapSupplier.MARKER_KEY_COMPILER)) {
+        assertEquals(ProguardMapSupplier.MARKER_VALUE_COMPILER, value);
+      } else if (key.equals(ProguardMapSupplier.MARKER_KEY_COMPILER_VERSION)) {
+        assertEquals(Version.LABEL, value);
+      } else if (key.equals(ProguardMapSupplier.MARKER_KEY_MIN_API)) {
+        assertEquals(minApiLevel, Integer.parseInt(value));
+      } else if (key.equals(ProguardMapSupplier.MARKER_KEY_COMPILER_HASH)) {
+        assertEquals(VersionProperties.INSTANCE.getSha(), value);
+      } else {
+        continue;
+      }
+      assertFalse(keysFound.contains(key));
+      keysFound.add(key);
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
index f8a3cc9..fdb35fb 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
@@ -21,6 +21,7 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
@@ -96,8 +97,11 @@
     ToolHelper.runR8(builder.build(), options -> options.inlineAccessors = false);
 
     Path outputmapping = out.resolve("mapping.txt");
-    String actualMapping;
-    actualMapping = new String(Files.readAllBytes(outputmapping), StandardCharsets.UTF_8);
+    // Remove comments.
+    String actualMapping =
+        Stream.of(new String(Files.readAllBytes(outputmapping), StandardCharsets.UTF_8).split("\n"))
+            .filter(line -> !line.startsWith("#"))
+            .collect(Collectors.joining("\n"));
     String refMapping = new String(Files.readAllBytes(
         Paths.get(EXAMPLES_DIR, "shaking1", "print-mapping.ref")), StandardCharsets.UTF_8);
     Assert.assertEquals(sorted(refMapping), sorted(actualMapping));