Enable --regex, --verbose and --info as command line parameters
This makes retrace compatible with the command line interface exposed by proguard.
Bug: 132850880
Change-Id: I835074dc62b431b7bfb85fb6c8204f0e57a38626
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index c6dad1b..057875d 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.utils.ExceptionUtils.STATUS_ERROR;
+import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.Keep;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -35,7 +36,7 @@
public static final String USAGE_MESSAGE =
StringUtils.lines(
- "Usage: retrace <proguard-map> <stacktrace-file>",
+ "Usage: retrace <proguard-map> <stacktrace-file> [--regex <regexp>, --verbose, --info]",
" where <proguard-map> is an r8 generated mapping file.");
private static Builder parseArguments(String[] args, DiagnosticsHandler diagnosticsHandler) {
@@ -48,16 +49,19 @@
if (help != null) {
return null;
}
+ Boolean info = OptionsParsing.tryParseBoolean(context, "--info");
+ if (info != null) {
+ // This is already set in the diagnostics handler.
+ continue;
+ }
Boolean verbose = OptionsParsing.tryParseBoolean(context, "--verbose");
if (verbose != null) {
- // TODO(b/132850880): Enable support for verbose.
- diagnosticsHandler.error(new StringDiagnostic("Currently no support for --verbose"));
+ builder.setVerbose(true);
continue;
}
String regex = OptionsParsing.tryParseSingle(context, "--regex", "r");
if (regex != null && !regex.isEmpty()) {
- // TODO(b/132850880): Enable support for regex.
- diagnosticsHandler.error(new StringDiagnostic("Currently no support for --regex"));
+ builder.setRegularExpression(regex);
continue;
}
if (!hasSetProguardMap) {
@@ -108,7 +112,7 @@
}
/**
- * The main entry point for running the retrace.
+ * The main entry point for running retrace.
*
* @param command The command that describes the desired behavior of this retrace invocation.
*/
@@ -140,9 +144,11 @@
}
}
- static void run(String[] args) {
- DiagnosticsHandler diagnosticsHandler = new DiagnosticsHandler() {};
- Builder builder = parseArguments(args, diagnosticsHandler);
+ public static void run(String[] args) {
+ RetraceDiagnosticsHandler retraceDiagnosticsHandler =
+ new RetraceDiagnosticsHandler(
+ new DiagnosticsHandler() {}, Arrays.asList(args).contains("--info"));
+ Builder builder = parseArguments(args, retraceDiagnosticsHandler);
if (builder == null) {
// --help was an argument to list
assert Arrays.asList(args).contains("--help");
@@ -153,6 +159,7 @@
retraced -> System.out.print(StringUtils.lines(retraced)));
run(builder.build());
}
+
/**
* The main entry point for running a legacy compatible retrace from the command line.
*
@@ -190,4 +197,33 @@
System.exit(STATUS_ERROR);
}
}
+
+ private static class RetraceDiagnosticsHandler implements DiagnosticsHandler {
+
+ private final DiagnosticsHandler diagnosticsHandler;
+ private final boolean printInfo;
+
+ public RetraceDiagnosticsHandler(DiagnosticsHandler diagnosticsHandler, boolean printInfo) {
+ this.diagnosticsHandler = diagnosticsHandler;
+ this.printInfo = printInfo;
+ assert diagnosticsHandler != null;
+ }
+
+ @Override
+ public void error(Diagnostic error) {
+ diagnosticsHandler.error(error);
+ }
+
+ @Override
+ public void warning(Diagnostic warning) {
+ diagnosticsHandler.warning(warning);
+ }
+
+ @Override
+ public void info(Diagnostic info) {
+ if (printInfo) {
+ diagnosticsHandler.info(info);
+ }
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java b/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java
index a7f194f..93addc4 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceCommand.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.Keep;
+import com.android.tools.r8.utils.StringDiagnostic;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
@@ -56,7 +57,7 @@
public static class Builder {
private boolean isVerbose;
- private DiagnosticsHandler diagnosticsHandler;
+ private final DiagnosticsHandler diagnosticsHandler;
private ProguardMapProducer proguardMapProducer;
private String regularExpression;
private List<String> stackTrace;
@@ -127,6 +128,11 @@
if (this.retracedStackTraceConsumer == null) {
throw new RuntimeException("RetracedStackConsumer not specified");
}
+ if (isVerbose && regularExpression != null) {
+ this.diagnosticsHandler.warning(
+ new StringDiagnostic(
+ "Retrace does not support verbose output when a regular expression is specified"));
+ }
return new RetraceCommand(
isVerbose,
regularExpression,
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index 258d869..ebe1bbf 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.retrace;
-import static com.android.tools.r8.ToolHelper.LINE_SEPARATOR;
+import static com.android.tools.r8.retrace.RetraceTests.DEFAULT_REGULAR_EXPRESSION;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.retrace.stacktraces.ActualRetraceBotStackTrace;
+import com.android.tools.r8.retrace.stacktraces.ActualRetraceBotStackTraceWithInfo;
+import com.android.tools.r8.retrace.stacktraces.FoundMethodVerboseStackTrace;
import com.android.tools.r8.utils.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -22,6 +25,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import org.hamcrest.Matcher;
import org.junit.Rule;
@@ -30,7 +34,7 @@
public class RetraceCommandLineTests {
- private static final boolean testExternal = true;
+ private static final boolean testExternal = false;
@Rule public TemporaryFolder folder = new TemporaryFolder();
@@ -56,7 +60,36 @@
@Test
public void testVerbose() throws IOException {
- runAbortTest(containsString("Currently no support for --verbose"), "--verbose");
+ FoundMethodVerboseStackTrace stackTrace = new FoundMethodVerboseStackTrace();
+ runTest(
+ stackTrace.mapping(),
+ StringUtils.joinLines(stackTrace.obfuscatedStackTrace()),
+ false,
+ StringUtils.joinLines(stackTrace.retracedStackTrace()) + "\n",
+ "--verbose");
+ }
+
+ @Test
+ public void testRegularExpression() throws IOException {
+ ActualRetraceBotStackTrace stackTrace = new ActualRetraceBotStackTrace();
+ runTest(
+ stackTrace.mapping(),
+ StringUtils.joinLines(stackTrace.obfuscatedStackTrace()),
+ false,
+ StringUtils.joinLines(stackTrace.retracedStackTrace()) + "\n",
+ "--regex=" + DEFAULT_REGULAR_EXPRESSION);
+ }
+
+ @Test
+ public void testRegularExpressionWithInfo() throws IOException {
+ ActualRetraceBotStackTraceWithInfo stackTrace = new ActualRetraceBotStackTraceWithInfo();
+ runTest(
+ stackTrace.mapping(),
+ StringUtils.joinLines(stackTrace.obfuscatedStackTrace()),
+ false,
+ StringUtils.joinLines(stackTrace.retracedStackTrace()) + "\n",
+ "--regex=" + DEFAULT_REGULAR_EXPRESSION,
+ "--info");
}
@Test
@@ -66,7 +99,7 @@
@Test
public void testHelp() throws IOException {
- ProcessResult processResult = runRetraceCommandLine(null, "--help");
+ ProcessResult processResult = runRetraceCommandLine(null, Arrays.asList("--help"));
assertEquals(0, processResult.exitCode);
assertEquals(Retrace.USAGE_MESSAGE, processResult.stdout);
}
@@ -82,34 +115,39 @@
" at r8.retrace(App:184)",
" ... 7 more");
- private void runTest(String mapping, String stackTrace, boolean stacktraceStdIn, String expected)
+ private void runTest(
+ String mapping, String stackTrace, boolean stacktraceStdIn, String expected, String... args)
throws IOException {
- ProcessResult result = runRetrace(mapping, stackTrace, stacktraceStdIn);
+ ProcessResult result = runRetrace(mapping, stackTrace, stacktraceStdIn, args);
assertEquals(0, result.exitCode);
assertEquals(expected, result.stdout);
}
private void runAbortTest(Matcher<String> errorMatch, String... args) throws IOException {
- ProcessResult result = runRetraceCommandLine(null, args);
+ ProcessResult result = runRetraceCommandLine(null, Arrays.asList(args));
assertEquals(1, result.exitCode);
assertThat(result.stderr, errorMatch);
}
- private ProcessResult runRetrace(String mapping, String stackTrace, boolean stacktraceStdIn)
+ private ProcessResult runRetrace(
+ String mapping, String stackTrace, boolean stacktraceStdIn, String... additionalArgs)
throws IOException {
Path mappingFile = folder.newFile("mapping.txt").toPath();
Files.write(mappingFile, mapping.getBytes());
File stackTraceFile = folder.newFile("stacktrace.txt");
Files.write(stackTraceFile.toPath(), stackTrace.getBytes());
- if (stacktraceStdIn) {
- return runRetraceCommandLine(stackTraceFile, mappingFile.toString());
- } else {
- return runRetraceCommandLine(
- null, mappingFile.toString(), stackTraceFile.toPath().toString());
+
+ Collection<String> args = new ArrayList<>();
+ args.add(mappingFile.toString());
+ if (!stacktraceStdIn) {
+ args.add(stackTraceFile.toPath().toString());
}
+ args.addAll(Arrays.asList(additionalArgs));
+ return runRetraceCommandLine(stacktraceStdIn ? stackTraceFile : null, args);
}
- private ProcessResult runRetraceCommandLine(File stdInput, String... args) throws IOException {
+ private ProcessResult runRetraceCommandLine(File stdInput, Collection<String> args)
+ throws IOException {
if (testExternal) {
List<String> command = new ArrayList<>();
command.add(ToolHelper.getSystemJavaExecutable());
@@ -117,7 +155,7 @@
command.add("-cp");
command.add(ToolHelper.R8_JAR.toString());
command.add("com.android.tools.r8.retrace.Retrace");
- command.addAll(Arrays.asList(args));
+ command.addAll(args);
ProcessBuilder builder = new ProcessBuilder(command);
if (stdInput != null) {
builder.redirectInput(stdInput);
@@ -136,7 +174,9 @@
System.setErr(new PrintStream(errorByteStream));
int exitCode = 0;
try {
- Retrace.run(args);
+ String[] strArgs = new String[0];
+ strArgs = args.toArray(strArgs);
+ Retrace.run(strArgs);
} catch (Throwable t) {
exitCode = 1;
}
@@ -149,7 +189,7 @@
exitCode,
outputByteStream.toString(),
errorByteStream.toString(),
- StringUtils.join(LINE_SEPARATOR, args));
+ StringUtils.joinLines(args));
}
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index 59a67ad..e29c928 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -43,7 +43,7 @@
// This is a slight modification of the default regular expression shown for proguard retrace
// that allow for retracing classes in the form <class>: lorem ipsum...
// Seems like Proguard retrace is expecting the form "Caused by: <class>".
- private static final String DEFAULT_REGULAR_EXPRESSION =
+ public static final String DEFAULT_REGULAR_EXPRESSION =
"(?:.*?\\bat\\s+%c\\.%m\\s*\\(%s(?::%l)?\\)\\s*(?:~\\[.*\\])?)|(?:(?:(?:%c|.*)?[:\"]\\s+)?%c(?::.*)?)";
@Parameters(name = "{0}, use regular expression: {1}")
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/ActualRetraceBotStackTraceWithInfo.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/ActualRetraceBotStackTraceWithInfo.java
new file mode 100644
index 0000000..53aa7c6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/ActualRetraceBotStackTraceWithInfo.java
@@ -0,0 +1,128 @@
+// Copyright (c) 2019, 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.retrace.stacktraces;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ActualRetraceBotStackTraceWithInfo extends ActualBotStackTraceBase {
+
+ @Override
+ public List<String> obfuscatedStackTrace() {
+ return Arrays.asList(
+ "com.android.tools.r8.CompilationFailedException: Compilation failed to complete",
+ "\tat com.android.tools.r8.BaseCommand$Builder.build(:6)",
+ "\tat com.android.tools.r8.R8TestBuilder.internalCompile(R8TestBuilder.java:104)",
+ "\tat com.android.tools.r8.R8TestBuilder.internalCompile(R8TestBuilder.java:29)",
+ "\tat com.android.tools.r8.TestCompilerBuilder.compile(TestCompilerBuilder.java:89)",
+ "\tat com.android.tools.r8.TestCompilerBuilder.run(TestCompilerBuilder.java:113)",
+ "\tat com.android.tools.r8.TestBuilder.run(TestBuilder.java:49)",
+ "\tat com.android.tools.r8.ir.optimize.classinliner.ClassInlinerTest.testCodeSample(ClassInlinerTest.java:289)",
+ "",
+ "Caused by:",
+ "com.android.tools.r8.utils.b: Error: offset: 158, line: 2, column: 33, Unexpected"
+ + " attribute at <no file>:2:33",
+ "-keepattributes -keepattributes LineNumberTable",
+ " ^",
+ "\tat com.android.tools.r8.utils.t0.a(:21)",
+ "\tat com.android.tools.r8.shaking.ProguardConfigurationParser.parse(:19)",
+ "\tat com.android.tools.r8.R8Command$Builder.i(:16)",
+ "\tat com.android.tools.r8.R8Command$Builder.b(:11)",
+ "\tat com.android.tools.r8.R8Command$Builder.b(:1)",
+ "\tat com.android.tools.r8.BaseCommand$Builder.build(:2)",
+ "\t... 6 more");
+ }
+
+ @Override
+ public String mapping() {
+ return r8MappingFromGitSha("dab96bbe5948133f0ae6e0a88fc133464421cf47");
+ }
+
+ // The Pruning lines is debug info printed by the command line interface if one passes --info and
+ // --regex=<DEFAULT_REGULAR_EXPRESSION> as options.
+ @Override
+ public List<String> retracedStackTrace() {
+ return Arrays.asList(
+ "Pruning \tat com.android.tools.r8.utils.Reporter.error(Reporter.java:21) from result"
+ + " because method is not defined on line number 21",
+ "Pruning \tat com.android.tools.r8.utils.Reporter.error(Reporter.java:21) from result"
+ + " because method is not defined on line number 21",
+ "Pruning \tat com.android.tools.r8.utils.Reporter.fatalError(Reporter.java:21) from result"
+ + " because method is not defined on line number 21",
+ "Pruning \tat"
+ + " com.android.tools.r8.utils.Reporter.addSuppressedExceptions(Reporter.java:21) from"
+ + " result because method is not defined on line number 21",
+ "Pruning \tat"
+ + " com.android.tools.r8.shaking.ProguardConfigurationParser.parse(ProguardConfigurationParser.java:19)"
+ + " from result because method is not defined on line number 19",
+ "Pruning \tat"
+ + " com.android.tools.r8.shaking.ProguardConfigurationParser.parse(ProguardConfigurationParser.java:19)"
+ + " from result because method is not defined on line number 19",
+ "Pruning \tat"
+ + " com.android.tools.r8.shaking.ProguardConfigurationParser.parse(ProguardConfigurationParser.java:19)"
+ + " from result because method is not in range on line number 19",
+ "Pruning \tat"
+ + " com.android.tools.r8.shaking.ProguardConfigurationParser.parse(ProguardConfigurationParser.java:19)"
+ + " from result because method is not in range on line number 19",
+ "Pruning \tat com.android.tools.r8.R8Command$Builder.makeCommand(R8Command.java:11) from"
+ + " result because method is not defined on line number 11",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.setDisableVerticalClassMerging(R8Command.java:11)"
+ + " from result because method is not defined on line number 11",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.lambda$addProguardConfigurationFiles$4(R8Command.java:11)"
+ + " from result because method is not defined on line number 11",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.lambda$addProguardConfiguration$6(R8Command.java:11)"
+ + " from result because method is not defined on line number 11",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.lambda$addProguardConfiguration$6(R8Command.java:11)"
+ + " from result because method is not defined on line number 11",
+ "Pruning \tat com.android.tools.r8.R8Command$Builder.makeCommand(R8Command.java:11) from"
+ + " result because method is not in range on line number 11",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.setDisableVerticalClassMerging(R8Command.java:1)"
+ + " from result because method is not defined on line number 1",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.lambda$addProguardConfigurationFiles$4(R8Command.java:1)"
+ + " from result because method is not defined on line number 1",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.lambda$addProguardConfiguration$6(R8Command.java:1)"
+ + " from result because method is not defined on line number 1",
+ "Pruning \tat"
+ + " com.android.tools.r8.R8Command$Builder.lambda$addProguardConfiguration$6(R8Command.java:1)"
+ + " from result because method is not defined on line number 1",
+ "Pruning \tat com.android.tools.r8.R8Command$Builder.makeCommand(R8Command.java:1) from"
+ + " result because method is not defined on line number 1",
+ "Pruning \tat com.android.tools.r8.R8Command$Builder.makeCommand(R8Command.java:1) from"
+ + " result because method is not defined on line number 1",
+ "com.android.tools.r8.CompilationFailedException: Compilation failed to complete",
+ "\tat com.android.tools.r8.BaseCommand$Builder.build(BaseCommand.java:143)",
+ "\tat com.android.tools.r8.R8TestBuilder.internalCompile(R8TestBuilder.java:104)",
+ "\tat com.android.tools.r8.R8TestBuilder.internalCompile(R8TestBuilder.java:29)",
+ "\tat com.android.tools.r8.TestCompilerBuilder.compile(TestCompilerBuilder.java:89)",
+ "\tat com.android.tools.r8.TestCompilerBuilder.run(TestCompilerBuilder.java:113)",
+ "\tat com.android.tools.r8.TestBuilder.run(TestBuilder.java:49)",
+ "\tat com.android.tools.r8.ir.optimize.classinliner.ClassInlinerTest.testCodeSample(ClassInlinerTest.java:289)",
+ "",
+ "Caused by:",
+ "com.android.tools.r8.utils.AbortException: Error: offset: 158, line: 2, column: 33,"
+ + " Unexpected attribute at <no file>:2:33",
+ "-keepattributes -keepattributes LineNumberTable",
+ " ^",
+ "\tat com.android.tools.r8.utils.Reporter.failIfPendingErrors(Reporter.java:101)",
+ "\tat com.android.tools.r8.shaking.ProguardConfigurationParser.parse(ProguardConfigurationParser.java:187)",
+ "\tat com.android.tools.r8.R8Command$Builder.makeR8Command(R8Command.java:432)",
+ "\tat com.android.tools.r8.R8Command$Builder.makeCommand(R8Command.java:413)",
+ "\tat com.android.tools.r8.R8Command$Builder.makeCommand(R8Command.java:61)",
+ "\tat com.android.tools.r8.BaseCommand$Builder.build(BaseCommand.java:139)",
+ "\t... 6 more");
+ }
+
+ @Override
+ public int expectedWarnings() {
+ return 1;
+ }
+}