Allow ProguardMapPartititioner to ignore empty ranges.

ProguardMapReader won't throw exception if ProguardMapPartititioner explicitly allow to ignore empty ranges and experimental mapping.

Change-Id: I9ad7d754284ae8ceada0031b19a80708d1038a7e
diff --git a/src/main/java/com/android/tools/r8/retrace/ProguardMapPartitionerBuilder.java b/src/main/java/com/android/tools/r8/retrace/ProguardMapPartitionerBuilder.java
index 42fd546..a7d9df8 100644
--- a/src/main/java/com/android/tools/r8/retrace/ProguardMapPartitionerBuilder.java
+++ b/src/main/java/com/android/tools/r8/retrace/ProguardMapPartitionerBuilder.java
@@ -15,5 +15,9 @@
 
   B setPartitionConsumer(Consumer<MappingPartition> consumer);
 
+  B setAllowEmptyMappedRanges(boolean allowEmptyMappedRanges);
+
+  B setAllowExperimentalMapping(boolean allowExperimentalMapping);
+
   P build();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
index 9770a0b..5bbea17 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/ProguardMapPartitionerOnClassNameToText.java
@@ -40,14 +40,20 @@
   private final ProguardMapProducer proguardMapProducer;
   private final Consumer<MappingPartition> mappingPartitionConsumer;
   private final DiagnosticsHandler diagnosticsHandler;
+  private final boolean allowEmptyMappedRanges;
+  private final boolean allowExperimentalMapping;
 
   private ProguardMapPartitionerOnClassNameToText(
       ProguardMapProducer proguardMapProducer,
       Consumer<MappingPartition> mappingPartitionConsumer,
-      DiagnosticsHandler diagnosticsHandler) {
+      DiagnosticsHandler diagnosticsHandler,
+      boolean allowEmptyMappedRanges,
+      boolean allowExperimentalMapping) {
     this.proguardMapProducer = proguardMapProducer;
     this.mappingPartitionConsumer = mappingPartitionConsumer;
     this.diagnosticsHandler = diagnosticsHandler;
+    this.allowEmptyMappedRanges = allowEmptyMappedRanges;
+    this.allowExperimentalMapping = allowExperimentalMapping;
   }
 
   @Override
@@ -69,7 +75,9 @@
         (classMapping, entries) -> {
           try {
             String payload = StringUtils.join("\n", entries);
-            ClassNameMapper classNameMapper = ClassNameMapper.mapperFromString(payload);
+            ClassNameMapper classNameMapper =
+                ClassNameMapper.mapperFromString(
+                    payload, null, allowEmptyMappedRanges, allowExperimentalMapping, false);
             if (classNameMapper.getClassNameMappings().size() != 1) {
               diagnosticsHandler.error(
                   new StringDiagnostic("Multiple class names in payload\n: " + payload));
@@ -161,6 +169,8 @@
     private ProguardMapProducer proguardMapProducer;
     private Consumer<MappingPartition> mappingPartitionConsumer;
     private final DiagnosticsHandler diagnosticsHandler;
+    private boolean allowEmptyMappedRanges = false;
+    private boolean allowExperimentalMapping = false;
 
     public ProguardMapPartitionerBuilderImpl(DiagnosticsHandler diagnosticsHandler) {
       this.diagnosticsHandler = diagnosticsHandler;
@@ -181,9 +191,27 @@
     }
 
     @Override
+    public ProguardMapPartitionerBuilderImpl setAllowEmptyMappedRanges(
+        boolean allowEmptyMappedRanges) {
+      this.allowEmptyMappedRanges = allowEmptyMappedRanges;
+      return this;
+    }
+
+    @Override
+    public ProguardMapPartitionerBuilderImpl setAllowExperimentalMapping(
+        boolean allowExperimental) {
+      this.allowExperimentalMapping = allowExperimentalMapping;
+      return this;
+    }
+
+    @Override
     public ProguardMapPartitionerOnClassNameToText build() {
       return new ProguardMapPartitionerOnClassNameToText(
-          proguardMapProducer, mappingPartitionConsumer, diagnosticsHandler);
+          proguardMapProducer,
+          mappingPartitionConsumer,
+          diagnosticsHandler,
+          allowEmptyMappedRanges,
+          allowExperimentalMapping);
     }
   }
 }
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
index e665c12..a16e5d3 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestCollection.java
@@ -45,7 +45,9 @@
           RetraceApiTypeResultTest.ApiTest.class);
 
   public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
-      ImmutableList.of(RetraceApiResidualSignatureTest.ApiTest.class);
+      ImmutableList.of(
+          RetraceApiResidualSignatureTest.ApiTest.class,
+          RetracePartitionEmptyMappingTest.ApiTest.class);
 
   private final TemporaryFolder temp;
 
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionEmptyMappingTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionEmptyMappingTest.java
new file mode 100644
index 0000000..a7d13a6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetracePartitionEmptyMappingTest.java
@@ -0,0 +1,74 @@
+// Copyright (c) 2023, 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.retrace.MappingPartitionMetadata;
+import com.android.tools.r8.retrace.ProguardMapPartitioner;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetracePartitionEmptyMappingTest extends RetraceApiTestBase {
+
+  public RetracePartitionEmptyMappingTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+    return ApiTest.class;
+  }
+
+  public static class ApiTest implements RetraceApiBinaryTest {
+
+    private final String aMapping =
+        "com.foo.bar.baz -> a:\n"
+            + "# someCommentHere\n"
+            + "  int field -> c\n"
+            + "  void method() -> d";
+
+    private final String bMapping =
+        "com.android.google.r8 -> b:\n"
+            + " boolean otherField -> e\n"
+            + "  int otherMethod():1:1 -> f\n"
+            + "# otherCommentHere";
+
+    private final String header = "# { id: 'com.android.tools.r8.mapping', version: '2.0' }";
+
+    private final String originalMapping = header + "\n" + aMapping + "\n" + bMapping;
+
+    @Test
+    public void test() throws IOException {
+      ProguardMapProducer proguardMapProducer = ProguardMapProducer.fromString(originalMapping);
+      Map<String, String> partitions = new HashMap<>();
+      MappingPartitionMetadata metadataData =
+          ProguardMapPartitioner.builder(new DiagnosticsHandler() {})
+              .setProguardMapProducer(proguardMapProducer)
+              .setPartitionConsumer(
+                  partition ->
+                      partitions.put(
+                          partition.getKey(),
+                          new String(partition.getPayload(), StandardCharsets.UTF_8)))
+              .setAllowEmptyMappedRanges(true)
+              .build()
+              .run();
+      assertNotNull(metadataData);
+      assertEquals(2, partitions.size());
+      assertEquals(aMapping, partitions.get("a"));
+      assertEquals(bMapping, partitions.get("b"));
+    }
+  }
+}