[Compose] Account for invalid minified range when composing inlinees
Bug: b/241763080
Change-Id: I3e1dba290e0b0ab0607b586302ccaad845477abc
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 2f5c0f9..bb4b37a 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -728,5 +728,20 @@
public List<MappingInformation> getAdditionalMappingInformation() {
return Collections.unmodifiableList(additionalMappingInformation);
}
+
+ public MappedRange partitionOnMinifiedRange(Range minifiedRange) {
+ if (minifiedRange.equals(this.minifiedRange)) {
+ return this;
+ }
+ Range splitOriginalRange =
+ new Range(
+ getOriginalLineNumber(minifiedRange.from), getOriginalLineNumber(minifiedRange.to));
+ MappedRange splitMappedRange =
+ new MappedRange(minifiedRange, signature, splitOriginalRange, renamedName);
+ if (minifiedRange.to >= this.minifiedRange.to) {
+ splitMappedRange.additionalMappingInformation = this.getAdditionalMappingInformation();
+ }
+ return splitMappedRange;
+ }
}
}
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 926fb77..d5ac7cb 100644
--- a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
+++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -547,8 +547,9 @@
Map<String, String> inverseClassMapping =
classNameMapper.getObfuscatedToOriginalMapping().inverse;
for (Entry<String, MappedRangesOfName> entry : mapper.mappedRangesByRenamedName.entrySet()) {
- MappedRangesOfName mappedRangesOfName = entry.getValue();
- for (MappedRangesOfName rangesOfName : mappedRangesOfName.partitionOnMethodSignature()) {
+ List<MappedRangesOfName> mappedRangesOfNames =
+ entry.getValue().partitionOnMethodSignature();
+ for (MappedRangesOfName rangesOfName : mappedRangesOfNames) {
MemberNaming memberNaming = rangesOfName.getMemberNaming(mapper);
List<MappedRange> newMappedRanges = rangesOfName.getMappedRanges();
RangeBuilder minified = new RangeBuilder();
@@ -575,7 +576,9 @@
// ...
List<MappedRange> composedRanges = new ArrayList<>();
ComputedOutlineInformation computedOutlineInformation = new ComputedOutlineInformation();
- for (MappedRange mappedRange : newMappedRanges) {
+ List<List<MappedRange>> composedInlineFrames = new ArrayList<>();
+ for (int i = 0; i < newMappedRanges.size(); i++) {
+ MappedRange mappedRange = newMappedRanges.get(i);
minified.addRange(mappedRange.minifiedRange);
// Register mapping information that is dependent on the residual naming to allow
// updating later on.
@@ -631,9 +634,34 @@
: Collections.singletonList(existingMappedRange);
}
}
- composedRanges.addAll(
- composeMappedRangesForMethod(
- existingMappedRanges, mappedRange, computedOutlineInformation));
+ // Mapping the original ranges all the way back may cause the minified map range and the
+ // original mapped range to have different spans. We therefore maintain a collection of
+ // inline frames to add when we see the last mapped range.
+ List<List<MappedRange>> newComposedInlineFrames = new ArrayList<>();
+ if (composedInlineFrames.isEmpty()) {
+ splitOnNewMinifiedRange(
+ composeMappedRangesForMethod(
+ existingMappedRanges, mappedRange, computedOutlineInformation),
+ Collections.emptyList(),
+ newComposedInlineFrames::add);
+ } else {
+ for (List<MappedRange> composedInlineFrame : composedInlineFrames) {
+ MappedRange splitMappedRange =
+ mappedRange.partitionOnMinifiedRange(composedInlineFrame.get(0).minifiedRange);
+ splitOnNewMinifiedRange(
+ composeMappedRangesForMethod(
+ existingMappedRanges, splitMappedRange, computedOutlineInformation),
+ composedInlineFrame,
+ newComposedInlineFrames::add);
+ }
+ }
+ composedInlineFrames = newComposedInlineFrames;
+ if (!isInlineMappedRange(newMappedRanges, i)) {
+ for (List<MappedRange> composedInlineFrame : composedInlineFrames) {
+ composedRanges.addAll(composedInlineFrame);
+ }
+ composedInlineFrames = Collections.emptyList();
+ }
}
MappedRange lastComposedRange = ListUtils.last(composedRanges);
if (computedOutlineInformation.seenOutlineMappingInformation != null) {
@@ -684,6 +712,38 @@
}
}
+ private void splitOnNewMinifiedRange(
+ List<MappedRange> mappedRanges,
+ List<MappedRange> previouslyMapped,
+ Consumer<List<MappedRange>> consumer) {
+ assert !mappedRanges.isEmpty();
+ Range minifiedRange = mappedRanges.get(0).minifiedRange;
+ if (minifiedRange == null) {
+ consumer.accept(ListUtils.joinNewArrayList(previouslyMapped, mappedRanges));
+ return;
+ }
+ Box<Range> lastMinifiedRange = new Box<>(minifiedRange);
+ int lastMappedIndex = 0;
+ for (int i = 0; i < mappedRanges.size(); i++) {
+ MappedRange mappedRange = mappedRanges.get(i);
+ Range lastMinifiedRangeFinal = lastMinifiedRange.get();
+ if (!mappedRange.minifiedRange.equals(lastMinifiedRangeFinal)) {
+ consumer.accept(
+ ListUtils.joinNewArrayList(
+ ListUtils.map(
+ previouslyMapped, x -> x.partitionOnMinifiedRange(lastMinifiedRangeFinal)),
+ mappedRanges.subList(lastMappedIndex, i)));
+ lastMinifiedRange.set(mappedRange.minifiedRange);
+ lastMappedIndex = i;
+ }
+ }
+ consumer.accept(
+ ListUtils.joinNewArrayList(
+ ListUtils.map(
+ previouslyMapped, x -> x.partitionOnMinifiedRange(lastMinifiedRange.get())),
+ mappedRanges.subList(lastMappedIndex, mappedRanges.size())));
+ }
+
private ComposingClassBuilder getExistingClassBuilder(MethodSignature originalSignature) {
return originalSignature.isQualified()
? committedPreviousClassBuilders.get(originalSignature.toHolderFromQualified())
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index 406d482..68e530f 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -328,4 +328,11 @@
}
return true;
}
+
+ public static <T> List<T> joinNewArrayList(List<T> one, List<T> other) {
+ ArrayList<T> ts = new ArrayList<>(one.size() + other.size());
+ ts.addAll(one);
+ ts.addAll(other);
+ return ts;
+ }
}
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 a60b723..a732f72 100644
--- a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java
@@ -52,15 +52,15 @@
" 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 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():30:30 -> w",
+ " 10:10:void new_synthetic_method():0:0 -> 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.
+ " 11:11:void new_synthetic_method():0:0 -> w");
@Test
public void testCompose() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOriginalViolatesNewRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOriginalViolatesNewRangeTest.java
new file mode 100644
index 0000000..fe94d29
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOriginalViolatesNewRangeTest.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2022, 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.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComposeOriginalViolatesNewRangeTest extends TestBase {
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public ComposeOriginalViolatesNewRangeTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
+ private static final String mappingFoo =
+ StringUtils.unixLines(
+ "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+ "com.foo -> a:",
+ " 1:1:void m1():10:10 -> x",
+ " 2:2:void m1():20:20 -> x");
+ private static final String mappingBar =
+ StringUtils.unixLines(
+ "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+ "a -> b:",
+ " 3:4:void x():1:2 -> z");
+ private static final String mappingResult =
+ StringUtils.unixLines(
+ "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+ "com.foo -> b:",
+ " 3:3:void m1():10:10 -> z",
+ " 4:4:void m1():20:20 -> z");
+
+ @Test
+ public void testCompose() throws Exception {
+ ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
+ ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
+ String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
+ assertEquals(mappingResult, doubleToSingleQuote(composed));
+ }
+}