[Retrace] Add api for getting mapping information

Bug: 195161786
Change-Id: I7d33182a619b4def25674473d7e0800477539f96
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
index 1dcd902..6dd1fa3 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -8,7 +8,6 @@
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.naming.MemberNaming.Signature;
-import com.android.tools.r8.naming.ProguardMap.Builder;
 import com.android.tools.r8.naming.mappinginformation.MapVersionMappingInformation;
 import com.android.tools.r8.naming.mappinginformation.MappingInformation;
 import com.android.tools.r8.naming.mappinginformation.MappingInformationDiagnostics;
@@ -231,11 +230,13 @@
       if (isCommentLineWithJsonBrace()) {
         parseMappingInformation(
             info -> {
-              assert info.isMetaInfMappingInformation();
+              assert info.isMapVersionMappingInformation()
+                  || info.isUnknownJsonMappingInformation();
             });
         // Skip reading the rest of the line.
         lineOffset = line.length();
         nextLine();
+        continue;
       }
       String before = parseType(false);
       skipWhitespace();
@@ -257,7 +258,7 @@
           mapBuilder.classNamingBuilder(after, before, getPosition());
       skipWhitespace();
       if (nextLine()) {
-        parseMemberMappings(mapBuilder, currentClassBuilder);
+        parseMemberMappings(currentClassBuilder);
       }
     }
   }
@@ -269,7 +270,7 @@
         diagnosticsHandler,
         lineNo,
         info -> {
-          MapVersionMappingInformation generatorInfo = info.asMetaInfMappingInformation();
+          MapVersionMappingInformation generatorInfo = info.asMapVersionMappingInformation();
           if (generatorInfo != null) {
             if (generatorInfo.getMapVersion().equals(MapVersion.MAP_VERSION_EXPERIMENTAL)) {
               // A mapping file that is marked "experimental" will be treated as an unversioned
@@ -286,8 +287,7 @@
         });
   }
 
-  private void parseMemberMappings(Builder mapBuilder, ClassNaming.Builder classNamingBuilder)
-      throws IOException {
+  private void parseMemberMappings(ClassNaming.Builder classNamingBuilder) throws IOException {
     MemberNaming lastAddedNaming = null;
     MemberNaming activeMemberNaming = null;
     MappedRange activeMappedRange = null;
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
index d26d9a8..7f82be1 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/CompilerSynthesizedMappingInformation.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.naming.mappinginformation;
 
-import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.naming.MapVersion;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
@@ -61,9 +60,6 @@
 
   public static void deserialize(
       MapVersion version,
-      JsonObject object,
-      DiagnosticsHandler diagnosticsHandler,
-      int lineNumber,
       Consumer<MappingInformation> onMappingInfo) {
     if (isSupported(version)) {
       onMappingInfo.accept(builder().build());
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java
index cd72831..357be56 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MapVersionMappingInformation.java
@@ -20,7 +20,6 @@
   private final MapVersion mapVersion;
 
   public MapVersionMappingInformation(MapVersion mapVersion) {
-    super();
     this.mapVersion = mapVersion;
   }
 
@@ -30,12 +29,12 @@
   }
 
   @Override
-  public boolean isMetaInfMappingInformation() {
+  public boolean isMapVersionMappingInformation() {
     return true;
   }
 
   @Override
-  public MapVersionMappingInformation asMetaInfMappingInformation() {
+  public MapVersionMappingInformation asMapVersionMappingInformation() {
     return this;
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index f8f1e53..13bcfe9 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -18,30 +18,38 @@
 
   public abstract String serialize();
 
-  public boolean isMetaInfMappingInformation() {
+  public boolean isMapVersionMappingInformation() {
     return false;
   }
 
-  public MapVersionMappingInformation asMetaInfMappingInformation() {
-    return null;
+  public boolean isUnknownJsonMappingInformation() {
+    return false;
   }
 
   public boolean isFileNameInformation() {
     return false;
   }
 
-  public FileNameInformation asFileNameInformation() {
-    return null;
-  }
-
   public boolean isCompilerSynthesizedMappingInformation() {
     return false;
   }
 
+  public MapVersionMappingInformation asMapVersionMappingInformation() {
+    return null;
+  }
+
+  public FileNameInformation asFileNameInformation() {
+    return null;
+  }
+
   public CompilerSynthesizedMappingInformation asCompilerSynthesizedMappingInformation() {
     return null;
   }
 
+  public UnknownJsonMappingInformation asUnknownJsonMappingInformation() {
+    return null;
+  }
+
   public abstract boolean allowOther(MappingInformation information);
 
   public static void fromJsonObject(
@@ -92,11 +100,11 @@
             version, object, diagnosticsHandler, lineNumber, onMappingInfo);
         return;
       case CompilerSynthesizedMappingInformation.ID:
-        CompilerSynthesizedMappingInformation.deserialize(
-            version, object, diagnosticsHandler, lineNumber, onMappingInfo);
+        CompilerSynthesizedMappingInformation.deserialize(version, onMappingInfo);
         return;
       default:
         diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, id));
+        UnknownJsonMappingInformation.deserialize(id, object, onMappingInfo);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/UnknownJsonMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/UnknownJsonMappingInformation.java
new file mode 100644
index 0000000..848919b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/UnknownJsonMappingInformation.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2021, 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.naming.mappinginformation;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.google.gson.JsonObject;
+import java.util.function.Consumer;
+
+public class UnknownJsonMappingInformation extends MappingInformation {
+
+  private final String id;
+  private final String payload;
+
+  public UnknownJsonMappingInformation(String id, String payload) {
+    this.id = id;
+    this.payload = payload;
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  public String getPayload() {
+    return payload;
+  }
+
+  @Override
+  public String serialize() {
+    throw new Unreachable("We should not at this point serialize unknown information");
+  }
+
+  @Override
+  public boolean allowOther(MappingInformation information) {
+    return true;
+  }
+
+  @Override
+  public boolean isUnknownJsonMappingInformation() {
+    return true;
+  }
+
+  @Override
+  public UnknownJsonMappingInformation asUnknownJsonMappingInformation() {
+    return this;
+  }
+
+  public static void deserialize(
+      String id, JsonObject object, Consumer<MappingInformation> onMappingInfo) {
+    onMappingInfo.accept(new UnknownJsonMappingInformation(id, object.toString()));
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
index 0615725..35380e4 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
@@ -24,4 +24,6 @@
 
   RetraceFrameResult lookupFrame(
       String methodName, int position, List<TypeReference> formalTypes, TypeReference returnType);
+
+  RetraceUnknownJsonMappingInformationResult getUnknownJsonMappingInformation();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUnknownJsonMappingInformationResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownJsonMappingInformationResult.java
new file mode 100644
index 0000000..2afa333
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownJsonMappingInformationResult.java
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.Keep;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+@Keep
+public interface RetraceUnknownJsonMappingInformationResult {
+
+  /** Basic operation over 'elements' which represent a possible non-ambiguous retracing. */
+  Stream<RetraceUnknownMappingInformationElement> stream();
+
+  /** Short-hand for iterating the elements. */
+  default void forEach(Consumer<RetraceUnknownMappingInformationElement> action) {
+    stream().forEach(action);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMappingInformationElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMappingInformationElement.java
new file mode 100644
index 0000000..3bba032
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceUnknownMappingInformationElement.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, 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;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface RetraceUnknownMappingInformationElement {
+
+  String getIdentifier();
+
+  String getPayLoad();
+
+  RetraceUnknownJsonMappingInformationResult getRetraceResultContext();
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index 5dace5b..55ed4db 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.retrace.RetraceClassResult;
 import com.android.tools.r8.retrace.RetraceFrameResult;
 import com.android.tools.r8.retrace.RetraceSourceFileResult;
+import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
 import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.Pair;
@@ -344,6 +345,12 @@
           position);
     }
 
+    @Override
+    public RetraceUnknownJsonMappingInformationResult getUnknownJsonMappingInformation() {
+      return RetraceUnknownJsonMappingInformationResultImpl.build(
+          mapper.getAdditionalMappingInfo());
+    }
+
     private RetraceFrameResultImpl lookupFrame(MethodDefinition definition, int position) {
       MethodDefinition methodDefinition =
           MethodDefinition.create(classReference.getClassReference(), definition.getName());
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownJsonMappingInformationResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownJsonMappingInformationResultImpl.java
new file mode 100644
index 0000000..4a681a3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownJsonMappingInformationResultImpl.java
@@ -0,0 +1,45 @@
+// Copyright (c) 2021, 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.internal;
+
+import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.naming.mappinginformation.UnknownJsonMappingInformation;
+import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
+import com.android.tools.r8.retrace.RetraceUnknownMappingInformationElement;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class RetraceUnknownJsonMappingInformationResultImpl
+    implements RetraceUnknownJsonMappingInformationResult {
+
+  private final List<UnknownJsonMappingInformation> elements;
+
+  private RetraceUnknownJsonMappingInformationResultImpl(
+      List<UnknownJsonMappingInformation> elements) {
+    this.elements = elements;
+  }
+
+  @Override
+  public Stream<RetraceUnknownMappingInformationElement> stream() {
+    return elements.stream()
+        .map(
+            unknownJsonMappingInformation ->
+                new RetraceUnknownMappingInformationElementImpl(
+                    this, unknownJsonMappingInformation));
+  }
+
+  static RetraceUnknownJsonMappingInformationResult build(
+      List<MappingInformation> mappingInformations) {
+    ImmutableList.Builder<UnknownJsonMappingInformation> unknownBuilder = ImmutableList.builder();
+    mappingInformations.forEach(
+        info -> {
+          if (info.isUnknownJsonMappingInformation()) {
+            unknownBuilder.add(info.asUnknownJsonMappingInformation());
+          }
+        });
+    return new RetraceUnknownJsonMappingInformationResultImpl(unknownBuilder.build());
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownMappingInformationElementImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownMappingInformationElementImpl.java
new file mode 100644
index 0000000..5615408
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceUnknownMappingInformationElementImpl.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2021, 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.internal;
+
+import com.android.tools.r8.naming.mappinginformation.UnknownJsonMappingInformation;
+import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
+import com.android.tools.r8.retrace.RetraceUnknownMappingInformationElement;
+
+public class RetraceUnknownMappingInformationElementImpl
+    implements RetraceUnknownMappingInformationElement {
+
+  private final RetraceUnknownJsonMappingInformationResult result;
+  private final UnknownJsonMappingInformation mappingInformation;
+
+  RetraceUnknownMappingInformationElementImpl(
+      RetraceUnknownJsonMappingInformationResult result,
+      UnknownJsonMappingInformation mappingInformation) {
+    this.result = result;
+    this.mappingInformation = mappingInformation;
+  }
+
+  @Override
+  public String getIdentifier() {
+    return mappingInformation.getId();
+  }
+
+  @Override
+  public String getPayLoad() {
+    return mappingInformation.getPayload();
+  }
+
+  @Override
+  public RetraceUnknownJsonMappingInformationResult getRetraceResultContext() {
+    return result;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
index e73ce25..15cfbd0 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestHelper.java
@@ -45,7 +45,7 @@
           RetraceApiSynthesizedFrameTest.ApiTest.class,
           RetraceApiSynthesizedInnerFrameTest.ApiTest.class);
   public static List<Class<? extends RetraceApiBinaryTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
-      ImmutableList.of();
+      ImmutableList.of(RetraceApiUnknownJsonTest.ApiTest.class);
 
   public static void runJunitOnTests(
       CfRuntime runtime,
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiUnknownJsonTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiUnknownJsonTest.java
new file mode 100644
index 0000000..f11a75f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiUnknownJsonTest.java
@@ -0,0 +1,94 @@
+// Copyright (c) 2021, 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 com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceUnknownMappingInformationElement;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiUnknownJsonTest extends RetraceApiTestBase {
+
+  public RetraceApiUnknownJsonTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+    return ApiTest.class;
+  }
+
+  public static class ApiTest implements RetraceApiBinaryTest {
+
+    private final String extraMapping =
+        "{\"id\":\"some.information.with.context\",\"value\":\"Hello World\"}";
+    private final String mapping =
+        "# { 'id': 'com.android.tools.r8.mapping', version: '1.0' }\n"
+            + "# { 'id': 'some.information.without.context' }\n"
+            + "some.Class -> a:\n"
+            + "# "
+            + extraMapping
+            + "\n"
+            + "# {'id': 'sourceFile','fileName':'SomeFileName.kt'}\n"
+            + "  1:3:int strawberry(int):99:101 -> s\n"
+            + "  4:5:int mango(float):121:122 -> s\n";
+
+    @Test
+    public void testRetracingSourceFile() {
+      TestDiagnosticsHandler diagnosticsHandler = new TestDiagnosticsHandler();
+      List<RetraceUnknownMappingInformationElement> mappingInfos =
+          Retracer.createDefault(ProguardMapProducer.fromString(mapping), diagnosticsHandler)
+              .retraceClass(Reference.classFromTypeName("a"))
+              .stream()
+              .flatMap(element -> element.getUnknownJsonMappingInformation().stream())
+              .collect(Collectors.toList());
+      assertEquals(1, mappingInfos.size());
+      RetraceUnknownMappingInformationElement unknownMapping = mappingInfos.get(0);
+      assertEquals("some.information.with.context", unknownMapping.getIdentifier());
+      assertEquals(extraMapping, unknownMapping.getPayLoad());
+
+      assertEquals(2, diagnosticsHandler.infoMessages.size());
+      assertEquals(
+          "Could not find a handler for some.information.without.context",
+          diagnosticsHandler.infoMessages.get(0).getDiagnosticMessage());
+      assertEquals(
+          "Could not find a handler for some.information.with.context",
+          diagnosticsHandler.infoMessages.get(1).getDiagnosticMessage());
+    }
+
+    private static class TestDiagnosticsHandler implements com.android.tools.r8.DiagnosticsHandler {
+
+      private List<Diagnostic> infoMessages = new ArrayList<>();
+
+      @Override
+      public void warning(Diagnostic warning) {
+        throw new RuntimeException("Warning not expected");
+      }
+
+      @Override
+      public void error(Diagnostic error) {
+        throw new RuntimeException("Error not expected");
+      }
+
+      @Override
+      public void info(Diagnostic info) {
+        DiagnosticsHandler.super.info(info);
+        infoMessages.add(info);
+      }
+    }
+  }
+}