[Compose] Fix incorrect ranges for inlined frames

Bug: b/241763080
Change-Id: Ie7ff4d5ed81c2adc2fca6d4742dfebae9264e928
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 35fbc04..926fb77 100644
--- a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
+++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -552,7 +552,6 @@
           MemberNaming memberNaming = rangesOfName.getMemberNaming(mapper);
           List<MappedRange> newMappedRanges = rangesOfName.getMappedRanges();
           RangeBuilder minified = new RangeBuilder();
-          RangeBuilder original = new RangeBuilder();
           // The new minified ranges may have ranges that range over positions that has additional
           // information, such as inlinees:
           // Existing:
@@ -578,7 +577,6 @@
           ComputedOutlineInformation computedOutlineInformation = new ComputedOutlineInformation();
           for (MappedRange mappedRange : newMappedRanges) {
             minified.addRange(mappedRange.minifiedRange);
-            original.addRange(mappedRange.originalRange);
             // Register mapping information that is dependent on the residual naming to allow
             // updating later on.
             registerMappingInformationFromMappedRanges(mappedRange);
@@ -604,23 +602,23 @@
                 // emits `1:1:void foo() -> a` instead of `1:1:void foo():1:1 -> a`, so R8 must
                 // capture the preamble position by explicitly inserting 0 as original range.
                 Entry<Integer, List<MappedRange>> existingEntry =
-                    listSegmentTree.findEntry(original.getStartOrNoRangeFrom());
+                    listSegmentTree.findEntry(
+                        mappedRange.getFirstPositionOfOriginalRange(NO_RANGE_FROM));
                 // We assume that all new minified ranges for a method are rewritten in the new map
                 // such that no previous existing positions exists.
                 if (existingEntry != null) {
-                  // listSegmentTree.removeSegment(existingEntry.getKey());
                   existingMappedRanges = existingEntry.getValue();
                 } else {
                   // The original can be discarded if it no longer exists or if the method is
                   // non-throwing.
-                  if (original.hasValue()
-                      && !original.isPreamble()
+                  if (mappedRange.originalRange != null
+                      && !mappedRange.originalRange.isPreamble()
                       && !options.mappingComposeOptions().allowNonExistingOriginalRanges) {
                     throw new MappingComposeException(
                         "Could not find original starting position of '"
-                            + minified.start
+                            + mappedRange.minifiedRange.from
                             + "' which should be "
-                            + original.start);
+                            + mappedRange.getFirstPositionOfOriginalRange(NO_RANGE_FROM));
                   }
                 }
                 assert minified.hasValue();
@@ -673,12 +671,11 @@
                   .computeResidualSignature(type -> inverseClassMapping.getOrDefault(type, type))
                   .asMethodSignature();
           if (lastComposedRange.minifiedRange != null) {
-            methodsWithPosition
-                .computeIfAbsent(residualSignature, ignored -> new SegmentTree<>(false))
-                .add(
-                    minified.getStartOrNoRangeFrom(),
-                    minified.getEndOrNoRangeFrom(),
-                    composedRanges);
+            SegmentTree<List<MappedRange>> listSegmentTree =
+                methodsWithPosition.computeIfAbsent(
+                    residualSignature, ignored -> new SegmentTree<>(false));
+            listSegmentTree.add(
+                minified.getStartOrNoRangeFrom(), minified.getEndOrNoRangeFrom(), composedRanges);
           } else {
             assert composedRanges.size() == 1;
             methodsWithoutPosition.put(residualSignature, lastComposedRange);
@@ -734,7 +731,6 @@
       ExistingMapping mappedRangesForPosition =
           computeExistingMapping(
               existingRanges, (start, end) -> originalRange.set(new Range(start, end)));
-      List<MappedRange> newComposedRanges = new ArrayList<>();
       MappedRange lastExistingRange = ListUtils.last(existingRanges);
       if (newRange.originalRange == null && newRange.minifiedRange == null) {
         MappedRange newComposedRange =
@@ -744,118 +740,117 @@
             newComposedRange.getAdditionalMappingInformation(),
             lastExistingRange.getAdditionalMappingInformation(),
             info -> newComposedRange.addMappingInformation(info, ConsumerUtils.emptyConsumer()));
-        newComposedRanges.add(newComposedRange);
-      } else {
-        assert newRange.minifiedRange != null;
-        // First check if the original range matches the existing minified range.
-        List<MappedRange> existingMappedRanges =
-            mappedRangesForPosition.getMappedRangesForPosition(
-                newRange.getFirstPositionOfOriginalRange(NO_RANGE_FROM));
-        if (existingMappedRanges == null) {
-          // If we cannot lookup the original position because it has been removed we compose with
-          // the existing method signature.
-          if (newRange.originalRange != null && newRange.originalRange.isPreamble()) {
-            return Collections.singletonList(
-                new MappedRange(
-                    null, lastExistingRange.signature, originalRange.get(), newRange.renamedName));
-          } else {
-            throw new MappingComposeException(
-                "Unexpected missing original position for '" + newRange + "'.");
-          }
-        }
-        // We have found an existing range for the original position.
-        MappedRange lastExistingMappedRange = ListUtils.last(existingMappedRanges);
-        // If the existing mapped minified range is equal to the original range of the new range
-        // then we have a perfect mapping that we can translate directly.
-        if (lastExistingMappedRange.minifiedRange.equals(newRange.originalRange)) {
-          computeComposedMappedRange(
-              newComposedRanges,
-              newRange,
-              existingMappedRanges,
-              computedOutlineInformation,
-              newRange.minifiedRange.from,
-              newRange.minifiedRange.to);
+        return Collections.singletonList(newComposedRange);
+      }
+      List<MappedRange> newComposedRanges = new ArrayList<>();
+      assert newRange.minifiedRange != null;
+      // First check if the original range matches the existing minified range.
+      List<MappedRange> existingMappedRanges =
+          mappedRangesForPosition.getMappedRangesForPosition(
+              newRange.getFirstPositionOfOriginalRange(NO_RANGE_FROM));
+      if (existingMappedRanges == null) {
+        // If we cannot lookup the original position because it has been removed we compose with
+        // the existing method signature.
+        if (newRange.originalRange != null && newRange.originalRange.isPreamble()) {
+          return Collections.singletonList(
+              new MappedRange(
+                  null, lastExistingRange.signature, originalRange.get(), newRange.renamedName));
         } else {
-          // Otherwise, we have a situation where the minified range references over multiple
-          // existing ranges. We simply chop op when the range changes on the right hand side. To
-          // ensure we do not mess up the spans from the original range, we have to check if the
-          // current starting position is inside an original range, and then chop it off.
-          // Similarly, when writing the last block, we have to cut it off to match.
-          int lastStartingMinifiedFrom = newRange.minifiedRange.from;
-          for (int position = newRange.minifiedRange.from;
-              position <= newRange.minifiedRange.to;
-              position++) {
-            List<MappedRange> existingMappedRangesForPosition =
-                mappedRangesForPosition.getMappedRangesForPosition(
-                    newRange.getOriginalLineNumber(position));
-            MappedRange lastExistingMappedRangeForPosition = null;
-            if (existingMappedRangesForPosition != null) {
-              lastExistingMappedRangeForPosition = ListUtils.last(existingMappedRangesForPosition);
-            }
-            if (lastExistingMappedRangeForPosition == null
-                || !lastExistingMappedRange.minifiedRange.equals(
-                    lastExistingMappedRangeForPosition.minifiedRange)) {
-              // We have seen an existing range we have to compute a splitting for.
-              computeComposedMappedRange(
-                  newComposedRanges,
-                  newRange,
-                  existingMappedRanges,
-                  computedOutlineInformation,
-                  lastStartingMinifiedFrom,
-                  position - 1);
-              // Advance the last starting position to this point and advance the existing mapped
-              // ranges for this position.
-              lastStartingMinifiedFrom = position;
-              if (existingMappedRangesForPosition == null) {
-                if (!options.mappingComposeOptions().allowNonExistingOriginalRanges) {
-                  throw new MappingComposeException(
-                      "Unexpected missing original position for '" + newRange + "'.");
-                }
-                // We are at the first position of a hole. If we have existing ranges:
-                // 1:1:void foo():41:41 -> a
-                // 9:9:void foo():49:49 -> a
-                // We may have a new range that is:
-                // 21:29:void foo():1:9
-                // We end up here at position 2 and we have already committed
-                // 21:21:void foo():41:41.
-                // We then introduce a "fake" normal range to simulate the result of retracing one
-                // after the other to end up with:
-                // 21:21:void foo():41:41
-                // 22:28:void foo():2:8
-                // 29:29:void foo():49:49.
-                int startOriginalPosition = newRange.getOriginalLineNumber(position);
-                Integer endOriginalPosition =
-                    mappedRangesForPosition.getCeilingForPosition(position);
-                if (endOriginalPosition == null) {
-                  endOriginalPosition = newRange.getLastPositionOfOriginalRange() + 1;
-                }
-                Range newOriginalRange = new Range(startOriginalPosition, endOriginalPosition - 1);
-                MappedRange nonExistingMappedRange =
-                    new MappedRange(
-                        newOriginalRange,
-                        lastExistingMappedRange.getOriginalSignature().asMethodSignature(),
-                        newOriginalRange,
-                        lastExistingMappedRange.renamedName);
-                nonExistingMappedRange.setResidualSignatureInternal(
-                    lastExistingRange.getResidualSignature());
-                lastExistingMappedRange = nonExistingMappedRange;
-                existingMappedRanges = Collections.singletonList(nonExistingMappedRange);
-                position += (endOriginalPosition - startOriginalPosition) - 1;
-              } else {
-                lastExistingMappedRange = lastExistingMappedRangeForPosition;
-                existingMappedRanges = existingMappedRangesForPosition;
-              }
-            }
-          }
+          throw new MappingComposeException(
+              "Unexpected missing original position for '" + newRange + "'.");
+        }
+      }
+      // We have found an existing range for the original position.
+      MappedRange lastExistingMappedRange = ListUtils.last(existingMappedRanges);
+      // If the existing mapped minified range is equal to the original range of the new range
+      // then we have a perfect mapping that we can translate directly.
+      if (lastExistingMappedRange.minifiedRange.equals(newRange.originalRange)) {
+        computeComposedMappedRange(
+            newComposedRanges,
+            newRange,
+            existingMappedRanges,
+            computedOutlineInformation,
+            newRange.minifiedRange.from,
+            newRange.minifiedRange.to);
+        return newComposedRanges;
+      }
+      // Otherwise, we have a situation where the minified range references over multiple
+      // existing ranges. We simply chop op when the range changes on the right hand side. To
+      // ensure we do not mess up the spans from the original range, we have to check if the
+      // current starting position is inside an original range, and then chop it off.
+      // Similarly, when writing the last block, we have to cut it off to match.
+      int lastStartingMinifiedFrom = newRange.minifiedRange.from;
+      for (int position = newRange.minifiedRange.from;
+          position <= newRange.minifiedRange.to;
+          position++) {
+        List<MappedRange> existingMappedRangesForPosition =
+            mappedRangesForPosition.getMappedRangesForPosition(
+                newRange.getOriginalLineNumber(position));
+        MappedRange lastExistingMappedRangeForPosition = null;
+        if (existingMappedRangesForPosition != null) {
+          lastExistingMappedRangeForPosition = ListUtils.last(existingMappedRangesForPosition);
+        }
+        if (lastExistingMappedRangeForPosition == null
+            || !lastExistingMappedRange.minifiedRange.equals(
+                lastExistingMappedRangeForPosition.minifiedRange)) {
+          // We have seen an existing range we have to compute a splitting for.
           computeComposedMappedRange(
               newComposedRanges,
               newRange,
               existingMappedRanges,
               computedOutlineInformation,
               lastStartingMinifiedFrom,
-              newRange.minifiedRange.to);
+              position - 1);
+          // Advance the last starting position to this point and advance the existing mapped
+          // ranges for this position.
+          lastStartingMinifiedFrom = position;
+          if (existingMappedRangesForPosition == null) {
+            if (!options.mappingComposeOptions().allowNonExistingOriginalRanges) {
+              throw new MappingComposeException(
+                  "Unexpected missing original position for '" + newRange + "'.");
+            }
+            // We are at the first position of a hole. If we have existing ranges:
+            // 1:1:void foo():41:41 -> a
+            // 9:9:void foo():49:49 -> a
+            // We may have a new range that is:
+            // 21:29:void foo():1:9
+            // We end up here at position 2 and we have already committed
+            // 21:21:void foo():41:41.
+            // We then introduce a "fake" normal range to simulate the result of retracing one after
+            // the other to end up with:
+            // 21:21:void foo():41:41
+            // 22:28:void foo():2:8
+            // 29:29:void foo():49:49.
+            int startOriginalPosition = newRange.getOriginalLineNumber(position);
+            Integer endOriginalPosition = mappedRangesForPosition.getCeilingForPosition(position);
+            if (endOriginalPosition == null) {
+              endOriginalPosition = newRange.getLastPositionOfOriginalRange() + 1;
+            }
+            Range newOriginalRange = new Range(startOriginalPosition, endOriginalPosition - 1);
+            MappedRange nonExistingMappedRange =
+                new MappedRange(
+                    newOriginalRange,
+                    lastExistingMappedRange.getOriginalSignature().asMethodSignature(),
+                    newOriginalRange,
+                    lastExistingMappedRange.renamedName);
+            nonExistingMappedRange.setResidualSignatureInternal(
+                lastExistingRange.getResidualSignature());
+            lastExistingMappedRange = nonExistingMappedRange;
+            existingMappedRanges = Collections.singletonList(nonExistingMappedRange);
+            position += (endOriginalPosition - startOriginalPosition) - 1;
+          } else {
+            lastExistingMappedRange = lastExistingMappedRangeForPosition;
+            existingMappedRanges = existingMappedRangesForPosition;
+          }
         }
       }
+      computeComposedMappedRange(
+          newComposedRanges,
+          newRange,
+          existingMappedRanges,
+          computedOutlineInformation,
+          lastStartingMinifiedFrom,
+          newRange.minifiedRange.to);
       return newComposedRanges;
     }
 
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsTest.java
index c352c94..e228204 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsTest.java
@@ -46,14 +46,13 @@
           "    4:4:void x(int):2:2 -> z",
           "    4:4:void y():4 -> z");
   private static final String mappingResult =
-      // TODO(b/241763080): We should be able to compose.
       StringUtils.unixLines(
           "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
           "com.foo -> b:",
           "    3:3:void m1():10 -> z",
-          "    3:3:void y():3 -> z",
-          "    4:4:void x(int):2:2 -> z", // should be m2(int).
-          "    4:4:void y():4 -> z");
+          "    3:3:void y():30:30 -> z",
+          "    4:4:void m2(int):20 -> z",
+          "    4:4:void y():31:31 -> z");
 
   @Test
   public void testCompose() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java
index 23179b1..a60b723 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java
@@ -52,14 +52,14 @@
           "    10:11:void z():3:4 -> w",
           "    10:11:void new_synthetic_method():0 -> w");
   private static final String mappingResult =
-      // TODO(b/241763080): This is wrong in so many different ways.
+      // TODO(b/241763080): This is now only a bit wrong.
       StringUtils.unixLines(
           "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
           "com.foo -> c:",
           "    10:10:void m1():10 -> w",
-          "    10:10:void y():3 -> w",
-          "    11:11:void x(int):2:2 -> w", // Should be m2.
-          "    11:11:void y():4 -> w",
+          "    10:10:void y():30:30 -> w",
+          "    11:11:void m2(int):20 -> w",
+          "    11:11:void y():31:31 -> w",
           "    10:11:void new_synthetic_method():0 -> w"); // The range here is invalid.
 
   @Test