[Compose] Fix composition of outline positions

Bug: b/280564959
Change-Id: Ie29664b3f7755a2cd6bea22d739189ebd6877d28
diff --git a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
index e4fc96d..8be5e9a 100644
--- a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
+++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -865,38 +865,40 @@
         assert verifyAllOutlineCallSitesAreEqualTo(outlineCallSite, computedMappedRangeForOutlines);
         ComputedMappedRangeForOutline computedMappedRangeForOutline =
             ListUtils.first(computedMappedRangeForOutlines);
-          Int2IntSortedMap newPositionMap =
-              new Int2IntLinkedOpenHashMap(outlineCallSite.getPositions().size());
-          visitOutlineMappedPositions(
-              outlineCallSite,
-              computedMappedRangeForOutline.current.getOriginalSignature(),
-              positionInfo -> {
-                int newIndex = firstAvailableRange.getAndIncrement();
-                Range newMinifiedRange = new Range(newIndex, newIndex);
-                MappedRange outerMostOutlineCallsiteFrame =
-                    ListUtils.last(positionInfo.mappedRanges());
-                for (MappedRange inlineMappedRangeInOutlinePosition : positionInfo.mappedRanges()) {
-                  if (inlineMappedRangeInOutlinePosition != outerMostOutlineCallsiteFrame) {
-                    composedRanges.add(
-                        inlineMappedRangeInOutlinePosition.withMinifiedRange(newMinifiedRange));
-                  }
-                }
+        Int2IntSortedMap newPositionMap =
+            new Int2IntLinkedOpenHashMap(outlineCallSite.getPositions().size());
+        visitOutlineMappedPositions(
+            outlineCallSite,
+            computedMappedRangeForOutline.current.getOriginalSignature(),
+            positionInfo -> {
+              int newIndex = firstAvailableRange.getAndIncrement();
+              Range newMinifiedRange = new Range(newIndex, newIndex);
+              boolean isCaller = false;
+              for (MappedRange existingMappedRange : positionInfo.mappedRanges()) {
                 int originalPosition =
-                    outerMostOutlineCallsiteFrame.getOriginalLineNumber(
+                    existingMappedRange.getOriginalLineNumber(
                         positionInfo.outlineCallsitePosition());
-                boolean hasInlineFrames = positionInfo.mappedRanges().size() > 1;
-                composedRanges.add(
+                Range newOriginalRange =
+                    isCaller
+                        ? new Range(originalPosition)
+                        : new Range(originalPosition, originalPosition);
+                MappedRange newMappedRange =
                     new MappedRange(
                         newMinifiedRange,
-                        lastComposedRange.signature,
-                        hasInlineFrames
-                            ? new Range(originalPosition)
-                            : new Range(originalPosition, originalPosition),
-                        lastComposedRange.getRenamedName()));
-                newPositionMap.put(positionInfo.outlinePosition(), newIndex);
-                outlineCallSite.setPositionsInternal(newPositionMap);
-              });
-        }
+                        existingMappedRange.getOriginalSignature(),
+                        newOriginalRange,
+                        lastComposedRange.getRenamedName());
+                if (!existingMappedRange.getAdditionalMappingInformation().isEmpty()) {
+                  newMappedRange.setAdditionalMappingInformationInternal(
+                      existingMappedRange.getAdditionalMappingInformation());
+                }
+                composedRanges.add(newMappedRange);
+                isCaller = true;
+              }
+              newPositionMap.put(positionInfo.outlinePosition(), newIndex);
+            });
+        outlineCallSite.setPositionsInternal(newPositionMap);
+      }
     }
 
     private boolean verifyAllOutlineCallSitesAreEqualTo(
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java
index 2e55faf..df61bf9 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineCallSiteInlinedTest.java
@@ -55,52 +55,48 @@
           "com.android.tools.r8.D8Command -> com.android.tools.r8.D8Command:",
           "# {'id':'sourceFile','fileName':'SourceFile'}",
           "    1:724:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer):0:723"
-              + " -> lambda$bar$0$com-android-tools-r8-D8Command",
+              + " -> lambda$bar$0$new",
           "    1:724:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0"
-              + " -> lambda$bar$0$com-android-tools-r8-D8Command",
+              + " lambda$bar$0$new(foo.StringConsumer):0"
+              + " -> lambda$bar$0$new",
           "      # {'id':'com.android.tools.r8.synthesized'}");
   private static final String mappingResult =
       StringUtils.unixLines(
           "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
           "com.android.tools.r8.D8Command -> com.android.tools.r8.D8Command:",
           "# {'id':'sourceFile','fileName':'D8Command.java'}",
-          // TODO(b/288117378): This 1:1 range corresponds to position 0 in the residual of R8. This
-          //  should probably not have the `getParseFlagsInformation` inline frame.
           "    1:1:java.util.List getParseFlagsInformation():592:592 -> getParseFlagsInformation",
+          // The following two frames is the preamble it is mapping to position 0. There is no
+          // positional information in mappingFoo, so the right thing here is to use the original
+          // signature from mappingBar/residual signature from mappingFoo.
           "    1:1:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
+              + " lambda$bar$0$new",
           "    1:1:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
+              + " lambda$bar$0$new(foo.StringConsumer):0:0 -> lambda$bar$0$new",
           "    # {'id':'com.android.tools.r8.synthesized'}",
-          "    2:2:foo.MapConsumer lambda$bar$0(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
+          // This frame is the outline position in mappingFoo.
+          "    2:2:foo.MapConsumer lambda$bar$0(foo.StringConsumer):0:0 -> lambda$bar$0$new",
           "    # {'id':'com.android.tools.r8.residualsignature',"
               + "'signature':'(Lfoo/StringConsumer;)Lfoo/internal/MapConsumer;'}",
           "    # {'id':'com.android.tools.r8.outlineCallsite',"
               + "'positions':{'23':725,'24':726,'25':727},"
               + "'outline':'Lfoo/SomeClass;outline(JJJ)V'}",
           "    2:2:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    3:724:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer) ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    3:724:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):0:0 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    725:725:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):720:720 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    726:726:foo.PGMapConsumer foo.PGMapConsumer.builder():52:52 -> lambda$bar$0",
-          "    726:726:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):720 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command",
-          "    727:727:void foo.PGMapConsumer.<init>():55:55 -> lambda$bar$0",
-          "    727:727:foo.PGMapConsumer foo.PGMapConsumer.builder():52 -> lambda$bar$0",
-          "    727:727:foo.internal.MapConsumer"
-              + " lambda$bar$0$com-android-tools-r8-D8Command(foo.StringConsumer):720 ->"
-              + " lambda$bar$0$com-android-tools-r8-D8Command");
+              + " lambda$bar$0$new(foo.StringConsumer):0:0 -> lambda$bar$0$new",
+          // This is the tail before any synthetic outline positions where the only information
+          // is in mappingBar.
+          "    3:724:foo.internal.MapConsumer lambda$bar$0(foo.StringConsumer) -> lambda$bar$0$new",
+          "    3:724:foo.internal.MapConsumer lambda$bar$0$new(foo.StringConsumer):0:0 "
+              + "-> lambda$bar$0$new",
+          // The remaining positions are the synthetic outline positions needed for correct
+          // retracing.
+          "    725:725:foo.MapConsumer lambda$bar$0(foo.StringConsumer):720:720 "
+              + "-> lambda$bar$0$new",
+          "    726:726:foo.PGMapConsumer foo.PGMapConsumer.builder():52:52 -> lambda$bar$0$new",
+          "    726:726:foo.MapConsumer lambda$bar$0(foo.StringConsumer):720 -> lambda$bar$0$new",
+          "    727:727:void foo.PGMapConsumer.<init>():55:55 -> lambda$bar$0$new",
+          "    727:727:foo.PGMapConsumer foo.PGMapConsumer.builder():52 -> lambda$bar$0$new",
+          "    727:727:foo.MapConsumer lambda$bar$0(foo.StringConsumer):720 -> lambda$bar$0$new");
 
   @Test
   public void testCompose() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlinePositionRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlinePositionRangeTest.java
index e55a18f..753f3d7 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlinePositionRangeTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlinePositionRangeTest.java
@@ -42,7 +42,7 @@
               + "'positions': { '1': 10, '2': 11 },"
               + "'outline':'La;a()I' }",
           "    10:11:int some.inlinee(int):23:24 -> s",
-          "    10:11:int outlineCaller(int):42 -> s");
+          "    10:11:int outlineCaller(int):1337 -> s");
   private static final String mappingBar =
       StringUtils.unixLines(
           "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
@@ -58,11 +58,10 @@
           "    # {'id':'com.android.tools.r8.outlineCallsite',"
               + "'positions':{'4':43,'5':44},"
               + "'outline':'Lb;m()I'}",
-          // TODO(b/280564959): We should not introduce ambiguity here.
-          "    43:43:int some.inlinee(int):23:24 -> s",
-          "    43:43:int outlineCaller(int):42 -> o",
-          "    44:44:int some.inlinee(int):23:24 -> s",
-          "    44:44:int outlineCaller(int):42 -> o",
+          "    43:43:int some.inlinee(int):23:23 -> o",
+          "    43:43:int outlineCaller(int):1337 -> o",
+          "    44:44:int some.inlinee(int):24:24 -> o",
+          "    44:44:int outlineCaller(int):1337 -> o",
           "outline.Class -> b:",
           "    4:5:int outline():11:12 -> m",
           "    # {'id':'com.android.tools.r8.outline'}");
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
index 48bfdfd..98ba4d5 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineTest.java
@@ -62,7 +62,7 @@
               + "'positions':{'4':43,'5':44},"
               + "'outline':'Lc;m()I'}",
           "    43:43:int outlineCaller(int):23:23 -> o",
-          "    44:44:int foo.bar.baz.outlineCaller(int):98:98 -> s",
+          "    44:44:int foo.bar.baz.outlineCaller(int):98:98 -> o",
           "    44:44:int outlineCaller(int):24 -> o",
           "outline.Class -> c:",
           "    4:5:int some.inlinee():75:76 -> m",
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java
index 20b1cb8..e79ad2c 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOutlineWithIdRangeTest.java
@@ -66,7 +66,7 @@
               + "'positions':{'1':9,'2':10},"
               + "'outline':'Lpackage/new_internal/X;b(JJJ)J'}",
           "    8:8:void foo():38:38 -> b",
-          "    9:9:void inlineeInOutline():1337:1337 -> a",
+          "    9:9:void inlineeInOutline():1337:1337 -> b",
           "    9:9:void foo():42 -> b",
           "    10:10:void foo():44:44 -> b",
           "package.Class$$ExternalSyntheticOutline0 -> package.new_internal.X:",