[Retrace] Add support for source file macro %S used in remapper
Bug: 159425023
Change-Id: Iec1e56e1d84e43b0cc6b78b7b8ac44339c2ee024
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java b/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
index 4973190..20e12e0 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.retrace;
import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
@@ -33,6 +34,9 @@
private static final int NO_MATCH = -1;
+ private final RegularExpressionGroup[] syntheticGroups =
+ new RegularExpressionGroup[] {new SourceFileLineNumberGroup()};
+
private final RegularExpressionGroup[] groups =
new RegularExpressionGroup[] {
new TypeNameGroup(),
@@ -130,19 +134,17 @@
String regularExpression, List<RegularExpressionGroupHandler> handlers) {
int currentIndex = 0;
int captureGroupIndex = 0;
+ regularExpression = registerSyntheticGroups(regularExpression);
while (currentIndex < regularExpression.length()) {
RegularExpressionGroup firstGroup = null;
int firstIndexFromCurrent = regularExpression.length();
for (RegularExpressionGroup group : groups) {
- int nextIndexOf = regularExpression.indexOf(group.shortName(), currentIndex);
- if (nextIndexOf > NO_MATCH && nextIndexOf < firstIndexFromCurrent) {
- // Check if previous character in the regular expression is not \\ to ensure not
- // overriding a matching on shortName.
- if (nextIndexOf > 0 && regularExpression.charAt(nextIndexOf - 1) == '\\') {
- continue;
- }
+ int firstIndex =
+ firstIndexOfGroup(
+ currentIndex, firstIndexFromCurrent, regularExpression, group.shortName());
+ if (firstIndex > NO_MATCH) {
firstGroup = group;
- firstIndexFromCurrent = nextIndexOf;
+ firstIndexFromCurrent = firstIndex;
}
}
if (firstGroup != null) {
@@ -161,6 +163,49 @@
return regularExpression;
}
+ private int firstIndexOfGroup(int startIndex, int endIndex, String expression, String shortName) {
+ int nextIndexOf = startIndex;
+ while (nextIndexOf != NO_MATCH) {
+ nextIndexOf = expression.indexOf(shortName, nextIndexOf);
+ if (nextIndexOf > NO_MATCH) {
+ if (nextIndexOf < endIndex && !isEscaped(expression, nextIndexOf)) {
+ return nextIndexOf;
+ }
+ nextIndexOf++;
+ }
+ }
+ return NO_MATCH;
+ }
+
+ private boolean isEscaped(String expression, int index) {
+ boolean escaped = false;
+ while (index > 0 && expression.charAt(--index) == '\\') {
+ escaped = !escaped;
+ }
+ return escaped;
+ }
+
+ private String registerSyntheticGroups(String regularExpression) {
+ boolean modifiedExpression;
+ do {
+ modifiedExpression = false;
+ for (RegularExpressionGroup syntheticGroup : syntheticGroups) {
+ int firstIndex =
+ firstIndexOfGroup(
+ 0, regularExpression.length(), regularExpression, syntheticGroup.shortName());
+ if (firstIndex > NO_MATCH) {
+ regularExpression =
+ regularExpression.substring(0, firstIndex)
+ + syntheticGroup.subExpression()
+ + regularExpression.substring(firstIndex + syntheticGroup.shortName().length());
+ // Loop as long as we can replace.
+ modifiedExpression = true;
+ }
+ }
+ } while (modifiedExpression);
+ return regularExpression;
+ }
+
static class RetraceString {
private final Element classContext;
@@ -387,6 +432,10 @@
abstract String subExpression();
abstract RegularExpressionGroupHandler createHandler(String captureGroup);
+
+ boolean isSynthetic() {
+ return false;
+ }
}
// TODO(b/145731185): Extend support for identifiers with strings inside back ticks.
@@ -718,6 +767,29 @@
}
}
+ private class SourceFileLineNumberGroup extends RegularExpressionGroup {
+
+ @Override
+ String shortName() {
+ return "%S";
+ }
+
+ @Override
+ String subExpression() {
+ return "%s(?::%l)?";
+ }
+
+ @Override
+ RegularExpressionGroupHandler createHandler(String captureGroup) {
+ throw new Unreachable("Should never be called");
+ }
+
+ @Override
+ boolean isSynthetic() {
+ return true;
+ }
+ }
+
private static final String JAVA_TYPE_REGULAR_EXPRESSION =
"(" + javaIdentifierSegment + "\\.)*" + javaIdentifierSegment + "[\\[\\]]*";
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
index bb69fc3..d8768a2 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceRegularExpressionTests.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.retrace;
+import static com.android.tools.r8.retrace.Retrace.DEFAULT_REGULAR_EXPRESSION;
import static junit.framework.TestCase.assertEquals;
import com.android.tools.r8.TestBase;
@@ -11,6 +12,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.retrace.stacktraces.InlineFileNameStackTrace;
+import com.android.tools.r8.retrace.stacktraces.RetraceAssertionErrorStackTrace;
import com.android.tools.r8.retrace.stacktraces.StackTraceForTest;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
@@ -24,9 +26,6 @@
@RunWith(Parameterized.class)
public class RetraceRegularExpressionTests extends TestBase {
- private static final String DEFAULT_REGULAR_EXPRESSION =
- "(?:.*?\\bat\\s+%c\\.%m\\s*\\(%s(?::%l)?\\)\\s*(?:~\\[.*\\])?)|(?:(?:.*?[:\"]\\s+)?%c(?::.*)?)";
-
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withNoneRuntime().build();
@@ -731,6 +730,41 @@
});
}
+ @Test
+ public void testSourceFileLineNumber() {
+ runRetraceTest(
+ DEFAULT_REGULAR_EXPRESSION.replace("%s(?::%l)?", "%S"),
+ new RetraceAssertionErrorStackTrace());
+ }
+
+ @Test
+ public void testEscaping() {
+ runRetraceTest(
+ "\\%c\\\\%c\\\\\\%c.%m\\(\\\\%S\\)\\\\\\%S",
+ new StackTraceForTest() {
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return ImmutableList.of("%c\\com.android.tools.r8.Foo\\%c.a(\\SourceFile:1)\\%S");
+ }
+
+ @Override
+ public String mapping() {
+ return "com.android.tools.r8.Bar -> com.android.tools.r8.Foo:\n"
+ + " 1:1:void m():13:13 -> a";
+ }
+
+ @Override
+ public List<String> retracedStackTrace() {
+ return ImmutableList.of("%c\\com.android.tools.r8.Bar\\%c.m(\\Bar.java:13)\\%S");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 0;
+ }
+ });
+ }
+
private TestDiagnosticMessagesImpl runRetraceTest(
String regularExpression, StackTraceForTest stackTraceForTest) {
TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();