Add outline key to outline call site mapping information

Bug: b/242682464
Change-Id: Ie5c73f12c6cb22f44fc6f50753cddd7f6dae895a
diff --git a/src/main/java/com/android/tools/r8/naming/MapVersion.java b/src/main/java/com/android/tools/r8/naming/MapVersion.java
index 8d8c9e0..322d15d 100644
--- a/src/main/java/com/android/tools/r8/naming/MapVersion.java
+++ b/src/main/java/com/android/tools/r8/naming/MapVersion.java
@@ -12,10 +12,11 @@
   MAP_VERSION_NONE("none"),
   MAP_VERSION_1_0("1.0"),
   MAP_VERSION_2_0("2.0"),
+  MAP_VERSION_2_1("2.1"),
   MAP_VERSION_EXPERIMENTAL("experimental"),
   MAP_VERSION_UNKNOWN("unknown");
 
-  public static final MapVersion STABLE = MAP_VERSION_2_0;
+  public static final MapVersion STABLE = MAP_VERSION_2_1;
 
   private final String name;
 
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
index 6cb093d..5af9615 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/OutlineCallsiteMappingInformation.java
@@ -6,6 +6,9 @@
 
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
 import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap;
@@ -15,14 +18,18 @@
 public class OutlineCallsiteMappingInformation extends MappingInformation {
 
   public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_2_0;
+  public static final MapVersion SUPPORTED_WITH_OUTLINE_VERSION = MapVersion.MAP_VERSION_2_1;
   public static final String ID = "com.android.tools.r8.outlineCallsite";
 
   private static final String POSITIONS_KEY = "positions";
+  private static final String OUTLINE_KEY = "outline";
 
   private final Int2IntSortedMap positions;
+  private final MethodReference outline;
 
-  private OutlineCallsiteMappingInformation(Int2IntSortedMap positions) {
+  private OutlineCallsiteMappingInformation(Int2IntSortedMap positions, MethodReference outline) {
     this.positions = positions;
+    this.outline = outline;
   }
 
   @Override
@@ -40,6 +47,9 @@
           mappedPositions.add(obfuscatedPosition + "", new JsonPrimitive(originalPosition));
         });
     result.add(POSITIONS_KEY, mappedPositions);
+    if (outline != null) {
+      result.add(OUTLINE_KEY, new JsonPrimitive(outline.toString()));
+    }
     return result.toString();
   }
 
@@ -62,8 +72,9 @@
     return positions.getOrDefault(originalPosition, originalPosition);
   }
 
-  public static OutlineCallsiteMappingInformation create(Int2IntSortedMap positions) {
-    return new OutlineCallsiteMappingInformation(positions);
+  public static OutlineCallsiteMappingInformation create(
+      Int2IntSortedMap positions, MethodReference outline) {
+    return new OutlineCallsiteMappingInformation(positions, outline);
   }
 
   public static boolean isSupported(MapVersion version) {
@@ -75,8 +86,7 @@
     if (isSupported(version)) {
       JsonObject postionsMapObject = object.getAsJsonObject(POSITIONS_KEY);
       if (postionsMapObject == null) {
-        throw new CompilationError(
-            "Expected '" + POSITIONS_KEY + "' to be present: " + object.getAsString());
+        throw new CompilationError("Expected '" + POSITIONS_KEY + "' to be present: " + object);
       }
       Int2IntSortedMap positionsMap = new Int2IntLinkedOpenHashMap();
       postionsMapObject
@@ -92,7 +102,14 @@
                   throw new CompilationError("Invalid position entry: " + entry.toString());
                 }
               });
-      onMappingInfo.accept(OutlineCallsiteMappingInformation.create(positionsMap));
+      MethodReference outline = null;
+      JsonElement outlineElement = object.get(OUTLINE_KEY);
+      if (outlineElement != null) {
+        outline = MethodReferenceUtils.methodFromSmali(outlineElement.getAsString());
+      } else if (version.isGreaterThanOrEqualTo(SUPPORTED_WITH_OUTLINE_VERSION)) {
+        throw new CompilationError("Expected '" + OUTLINE_KEY + "' to be present: " + object);
+      }
+      onMappingInfo.accept(OutlineCallsiteMappingInformation.create(positionsMap, outline));
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/references/MethodReference.java b/src/main/java/com/android/tools/r8/references/MethodReference.java
index e0314b8..5ef8596 100644
--- a/src/main/java/com/android/tools/r8/references/MethodReference.java
+++ b/src/main/java/com/android/tools/r8/references/MethodReference.java
@@ -85,6 +85,6 @@
 
   @Override
   public String toString() {
-    return getHolderClass().toString() + getMethodName() + getMethodDescriptor();
+    return getHolderClass() + getMethodName() + getMethodDescriptor();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index a0a2a74..90d26b4 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -57,6 +57,7 @@
 import com.android.tools.r8.naming.MemberNaming;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.PositionRangeAllocator;
 import com.android.tools.r8.naming.PositionRangeAllocator.CardinalPositionRangeAllocator;
 import com.android.tools.r8.naming.PositionRangeAllocator.NonCardinalPositionRangeAllocator;
@@ -71,6 +72,7 @@
 import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation;
 import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation.RemoveInnerFramesAction;
 import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation.ThrowsCondition;
+import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.retrace.internal.RetraceUtils;
 import com.android.tools.r8.shaking.KeepInfoCollection;
@@ -674,7 +676,9 @@
           DexMethod outlineMethod = getOutlineMethod(mappedPositions.get(0));
           if (outlineMethod != null) {
             outlinesToFix
-                .computeIfAbsent(outlineMethod, ignored -> new OutlineFixupBuilder())
+                .computeIfAbsent(
+                    outlineMethod,
+                    outline -> new OutlineFixupBuilder(computeMappedMethod(outline, appView)))
                 .setMappedPositionsOutline(mappedPositions);
             methodMappingInfo.add(OutlineMappingInformation.builder().build());
           }
@@ -778,7 +782,8 @@
                   });
               outlinesToFix
                   .computeIfAbsent(
-                      firstPosition.outlineCallee, ignored -> new OutlineFixupBuilder())
+                      firstPosition.outlineCallee,
+                      outline -> new OutlineFixupBuilder(computeMappedMethod(outline, appView)))
                   .addMappedRangeForOutlineCallee(lastMappedRange, positionMap);
             }
             i = j;
@@ -831,6 +836,14 @@
     return false;
   }
 
+  private static MethodReference computeMappedMethod(DexMethod current, AppView<?> appView) {
+    NamingLens namingLens = appView.getNamingLens();
+    DexMethod renamedMethodSignature =
+        namingLens.lookupMethod(
+            appView.graphLens().getRenamedMethodSignature(current), appView.dexItemFactory());
+    return renamedMethodSignature.asMethodReference();
+  }
+
   private static DexMethod getOutlineMethod(MappedPosition mappedPosition) {
     if (mappedPosition.isOutline) {
       return mappedPosition.method;
@@ -1403,12 +1416,17 @@
 
   private static class OutlineFixupBuilder {
 
-    private static int MINIFIED_POSITION_REMOVED = -1;
+    private static final int MINIFIED_POSITION_REMOVED = -1;
 
+    private final MethodReference outlineMethod;
     private List<MappedPosition> mappedOutlinePositions = null;
     private final List<Pair<MappedRange, Int2IntMap>> mappedOutlineCalleePositions =
         new ArrayList<>();
 
+    private OutlineFixupBuilder(MethodReference outlineMethod) {
+      this.outlineMethod = outlineMethod;
+    }
+
     public void setMappedPositionsOutline(List<MappedPosition> mappedPositionsOutline) {
       this.mappedOutlinePositions = mappedPositionsOutline;
     }
@@ -1437,7 +1455,7 @@
               }
             });
         mappedRange.addMappingInformation(
-            OutlineCallsiteMappingInformation.create(map), Unreachable::raise);
+            OutlineCallsiteMappingInformation.create(map, outlineMethod), Unreachable::raise);
       }
     }
 
diff --git a/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java b/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
index 037fafb..8e240d7 100644
--- a/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
@@ -147,4 +147,13 @@
     }
     return builder.append(")").toString();
   }
+
+  public static MethodReference methodFromSmali(String smali) {
+    int holderEndIndex = smali.indexOf(";") + 1;
+    int methodDescriptorIndex = smali.indexOf("(", holderEndIndex);
+    return Reference.methodFromDescriptor(
+        smali.substring(0, holderEndIndex),
+        smali.substring(holderEndIndex, methodDescriptorIndex),
+        smali.substring(methodDescriptorIndex));
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index e29b4e8..aeb419e 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -281,6 +281,10 @@
     return clazz(Reference.classFromTypeName(name));
   }
 
+  public ClassNameMapper getMapping() {
+    return mapping;
+  }
+
   // Simple wrapper to more easily change the implementation for retracing subjects.
   // This should in time be replaced by use of the Retrace API.
   public static class MappingWrapper {