[Retrace] Identify ranges with cardinal to split overloaded mappings
Bug: 199058242
Bug: 145897713
Change-Id: Ibd0d2acec5072b17c5eea24e8162d751e2ac6e41
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNaming.java b/src/main/java/com/android/tools/r8/naming/ClassNaming.java
index c9de8ab..83b7b3f 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNaming.java
@@ -26,7 +26,7 @@
public abstract MappedRange addMappedRange(
Range obfuscatedRange,
MemberNaming.MethodSignature originalSignature,
- Object originalRange,
+ Range originalRange,
String obfuscatedName);
public abstract void addMappingInformation(
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
index a222acb..3c83c90 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForMapApplier.java
@@ -88,7 +88,7 @@
public MappedRange addMappedRange(
Range obfuscatedRange,
MemberNaming.MethodSignature originalSignature,
- Object originalRange,
+ Range originalRange,
String obfuscatedName) {
return null;
}
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 1d837b3..7a0a20c 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -85,7 +85,7 @@
public MappedRange addMappedRange(
Range minifiedRange,
MemberNaming.MethodSignature originalSignature,
- Object originalRange,
+ Range originalRange,
String renamedName) {
MappedRange range =
new MappedRange(minifiedRange, originalSignature, originalRange, renamedName);
@@ -413,7 +413,7 @@
public final Range minifiedRange; // Can be null, if so then originalRange must also be null.
public final MethodSignature signature;
- public final Object originalRange; // null, Integer or Range.
+ public final Range originalRange;
public final String renamedName;
/**
@@ -425,11 +425,7 @@
private List<MappingInformation> additionalMappingInfo = new ArrayList<>();
private MappedRange(
- Range minifiedRange, MethodSignature signature, Object originalRange, String renamedName) {
-
- assert originalRange == null
- || originalRange instanceof Integer
- || originalRange instanceof Range;
+ Range minifiedRange, MethodSignature signature, Range originalRange, String renamedName) {
this.minifiedRange = minifiedRange;
this.signature = signature;
@@ -466,13 +462,8 @@
if (originalRange == null) {
// Concrete identity mapping: "x:y:a() -> b"
return lineNumberAfterMinification;
- } else if (originalRange instanceof Integer) {
- // Inlinee: "x:y:a():u -> b"
- return (int) originalRange;
} else {
// "x:y:a():u:v -> b"
- assert originalRange instanceof Range;
- Range originalRange = (Range) this.originalRange;
if (originalRange.to == originalRange.from) {
// This is a single line mapping which we should report as the actual line.
return originalRange.to;
@@ -484,10 +475,8 @@
public int getFirstLineNumberOfOriginalRange() {
if (originalRange == null) {
return 0;
- } else if (originalRange instanceof Integer) {
- return (int) originalRange;
} else {
- return ((Range) originalRange).from;
+ return originalRange.from;
}
}
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 52b63e0..1dcd902 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapReader.java
@@ -293,8 +293,7 @@
MappedRange activeMappedRange = null;
Range previousMappedRange = null;
do {
- Object originalRange = null;
- Range mappedRange = null;
+ Range originalRange = null;
// Try to parse any information added in comments above member namings
if (isCommentLineWithJsonBrace()) {
final MemberNaming currentMember = activeMemberNaming;
@@ -326,13 +325,12 @@
break;
}
skipWhitespace();
- Object maybeRangeOrInt = maybeParseRangeOrInt();
- if (maybeRangeOrInt != null) {
- if (!(maybeRangeOrInt instanceof Range)) {
+ Range mappedRange = parseRange();
+ if (mappedRange != null) {
+ if (mappedRange.isCardinal) {
throw new ParseException(
- String.format("Invalid obfuscated line number range (%s).", maybeRangeOrInt));
+ String.format("Invalid obfuscated line number range (%s).", mappedRange));
}
- mappedRange = (Range) maybeRangeOrInt;
skipWhitespace();
expect(':');
}
@@ -343,7 +341,7 @@
// This is a mapping or inlining definition
nextChar();
skipWhitespace();
- originalRange = maybeParseRangeOrInt();
+ originalRange = parseRange();
if (originalRange == null) {
throw new ParseException("No number follows the colon after the method signature.");
}
@@ -371,7 +369,11 @@
if (activeMemberNaming != null) {
boolean changedName = !activeMemberNaming.getRenamedName().equals(renamedName);
boolean changedMappedRange = !Objects.equals(previousMappedRange, mappedRange);
- if (changedName || previousMappedRange == null || changedMappedRange) {
+ boolean originalRangeChange = originalRange == null || !originalRange.isCardinal;
+ if (changedName
+ || previousMappedRange == null
+ || changedMappedRange
+ || originalRangeChange) {
if (lastAddedNaming == null
|| !lastAddedNaming.getOriginalSignature().equals(activeMemberNaming.signature)) {
classNamingBuilder.addMemberEntry(activeMemberNaming);
@@ -407,7 +409,7 @@
nextChar();
isInit = true;
}
- // Progard sometimes outputs a ? as a method name. We have tools (dexsplitter) that depends
+ // Proguard sometimes outputs a ? as a method name. We have tools (dexsplitter) that depends
// on being able to map class names back to the original, but does not care if methods are
// correctly mapped. Using this on proguard output for anything else might not give correct
// remappings.
@@ -530,14 +532,14 @@
return '0' <= c && c <= '9';
}
- private Object maybeParseRangeOrInt() {
+ private Range parseRange() {
if (!isSimpleDigit(peekChar(0))) {
return null;
}
int from = parseNumber();
skipWhitespace();
if (peekChar(0) != ':') {
- return from;
+ return new Range(from);
}
expect(':');
skipWhitespace();
diff --git a/src/main/java/com/android/tools/r8/naming/Range.java b/src/main/java/com/android/tools/r8/naming/Range.java
index c91ae99..a8d8563 100644
--- a/src/main/java/com/android/tools/r8/naming/Range.java
+++ b/src/main/java/com/android/tools/r8/naming/Range.java
@@ -3,16 +3,28 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
+import java.util.Objects;
+
/** Represents a line number range. */
public class Range {
public final int from;
public final int to;
+ public final boolean isCardinal;
+
+ public Range(int line) {
+ this(line, line, true);
+ }
public Range(int from, int to) {
+ this(from, to, false);
+ }
+
+ private Range(int from, int to, boolean isCardinal) {
this.from = from;
this.to = to;
- // TODO(b/145897713): Seems like we should be able to assert from <= to.
+ this.isCardinal = isCardinal;
+ assert from <= to;
}
public boolean contains(int value) {
@@ -21,7 +33,7 @@
@Override
public String toString() {
- return from + ":" + to;
+ return isCardinal ? (from + "") : (from + ":" + to);
}
@Override
@@ -34,13 +46,11 @@
}
Range range = (Range) o;
- return from == range.from && to == range.to;
+ return from == range.from && to == range.to && isCardinal == range.isCardinal;
}
@Override
public int hashCode() {
- int result = from;
- result = 31 * result + to;
- return result;
+ return Objects.hash(from, to, isCardinal);
}
}
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 1163213..cfc923a 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
@@ -18,6 +18,7 @@
import com.android.tools.r8.retrace.RetraceClassResult;
import com.android.tools.r8.retrace.RetraceFrameResult;
import com.android.tools.r8.retrace.Retracer;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Pair;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
@@ -141,29 +142,48 @@
List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappings = new ArrayList<>();
internalStream()
.forEach(
- element ->
- mappings.add(
- new Pair<>(element, getMappedRangesForFrame(element, definition, position))));
+ element -> {
+ getMappedRangesForFrame(element, definition, position)
+ .forEach(
+ mappedRanges -> {
+ mappings.add(new Pair<>(element, mappedRanges));
+ });
+ });
return new RetraceFrameResultImpl(this, mappings, definition, position, retracer);
}
- private List<MappedRange> getMappedRangesForFrame(
+ private List<List<MappedRange>> getMappedRangesForFrame(
RetraceClassElementImpl element, MethodDefinition definition, int position) {
+ List<List<MappedRange>> overloadedRanges = new ArrayList<>();
if (mapper == null) {
- return null;
+ overloadedRanges.add(null);
+ return overloadedRanges;
}
assert element.mapper != null;
MappedRangesOfName mappedRanges = mapper.mappedRangesByRenamedName.get(definition.getName());
if (mappedRanges == null || mappedRanges.getMappedRanges().isEmpty()) {
- return null;
+ overloadedRanges.add(null);
+ return overloadedRanges;
}
- if (position < 0) {
- return mappedRanges.getMappedRanges();
+ List<MappedRange> mappedRangesForPosition = null;
+ if (position >= 0) {
+ mappedRangesForPosition = mappedRanges.allRangesForLine(position, false);
}
- List<MappedRange> mappedRangesForPosition = mappedRanges.allRangesForLine(position, false);
- return mappedRangesForPosition.isEmpty()
- ? mappedRanges.getMappedRanges()
- : mappedRangesForPosition;
+ if (mappedRangesForPosition == null || mappedRangesForPosition.isEmpty()) {
+ mappedRangesForPosition = mappedRanges.getMappedRanges();
+ }
+ assert mappedRangesForPosition != null && !mappedRangesForPosition.isEmpty();
+ // Mapped ranges can have references to overloaded signatures. We distinguish those by looking
+ // at the cardinal mapping range.
+ for (MappedRange mappedRange : mappedRangesForPosition) {
+ if (overloadedRanges.isEmpty()
+ || mappedRange.originalRange == null
+ || !mappedRange.originalRange.isCardinal) {
+ overloadedRanges.add(new ArrayList<>());
+ }
+ ListUtils.last(overloadedRanges).add(mappedRange);
+ }
+ return overloadedRanges;
}
@Override
@@ -334,14 +354,16 @@
private RetraceFrameResultImpl lookupFrame(MethodDefinition definition, int position) {
MethodDefinition methodDefinition =
MethodDefinition.create(classReference.getClassReference(), definition.getName());
+ ImmutableList.Builder<Pair<RetraceClassElementImpl, List<MappedRange>>> builder =
+ ImmutableList.builder();
+ classResult
+ .getMappedRangesForFrame(this, methodDefinition, position)
+ .forEach(
+ mappedRanges -> {
+ builder.add(new Pair<>(this, mappedRanges));
+ });
return new RetraceFrameResultImpl(
- classResult,
- ImmutableList.of(
- new Pair<>(
- this, classResult.getMappedRangesForFrame(this, methodDefinition, position))),
- methodDefinition,
- position,
- classResult.retracer);
+ classResult, builder.build(), methodDefinition, position, classResult.retracer);
}
}
}
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 ec1b7d0..48af35f 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -482,7 +482,7 @@
classNamingBuilder.addMappedRange(
obfuscatedRange,
getOriginalMethodSignature.apply(caller.method),
- Math.max(caller.line, 0), // Prevent against "no-position".
+ new Range(Math.max(caller.line, 0)), // Prevent against "no-position".
obfuscatedName);
caller = caller.callerPosition;
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
index 9efecb4..17dadf2 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
@@ -195,8 +195,10 @@
MappedRange range) {
assertEquals(function, range.signature.name);
int expectedLineNumber = hasPosition ? location.line : 0;
- Object expectedOriginalRange =
- innermostFrame ? new Range(expectedLineNumber, expectedLineNumber) : expectedLineNumber;
+ Range expectedOriginalRange =
+ innermostFrame
+ ? new Range(expectedLineNumber, expectedLineNumber)
+ : new Range(expectedLineNumber);
assertEquals(expectedOriginalRange, range.originalRange);
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineFileNameStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineFileNameStackTrace.java
index ebc23a1..ef36965 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineFileNameStackTrace.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineFileNameStackTrace.java
@@ -33,8 +33,8 @@
"com.android.tools.r8.naming.retrace.Main -> com.android.tools.r8.naming.retrace.Main:",
" 3:3:void foo.Bar$Baz.baz(long):0:0 -> main",
" 3:3:void Foo$Bar.bar(int):2 -> main",
- " 3:3:void com.android.tools.r8.naming.retrace.Main$Foo.method1(java.lang.String):8:8"
- + " -> main",
+ " 3:3:void com.android.tools.r8.naming.retrace.Main$Foo.method1(java.lang.String):8 ->"
+ + " main",
" 3:3:void main(java.lang.String[]):7 -> main");
}
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java
index cacbe03..d1659cd 100644
--- a/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/OverloadSameLineTest.java
@@ -32,8 +32,8 @@
"Exception in thread \"main\" java.lang.NullPointerException",
// TODO(b/199058242): Should be ambiguous and not inline frames
"\tat com.android.tools.r8.naming.retrace.Main.overload(Main.java:7)",
- "\tat com.android.tools.r8.naming.retrace.Main.overload(Main.java:13)",
- "\tat com.android.tools.r8.naming.retrace.Main.overload(Main.java:15)");
+ "\t<OR> at com.android.tools.r8.naming.retrace.Main.overload(Main.java:15)",
+ "\t<OR> at com.android.tools.r8.naming.retrace.Main.overload(Main.java:13)");
}
@Override