Test retracing R8-processed R8.

Change-Id: Id8257d84073c1ea55155bb1b83a51ee41f6e66fd
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 0bad20c..4397db9 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -59,6 +59,7 @@
 import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
 import com.android.tools.r8.utils.LineNumberOptimizer;
 import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.SelfRetraceTest;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
@@ -586,6 +587,7 @@
   private static void run(String[] args) throws CompilationFailedException {
     R8Command command = R8Command.parse(args, CommandLineOrigin.INSTANCE).build();
     if (command.isPrintHelp()) {
+      SelfRetraceTest.test();
       System.out.println(USAGE_MESSAGE);
       return;
     }
diff --git a/src/main/java/com/android/tools/r8/utils/SelfRetraceTest.java b/src/main/java/com/android/tools/r8/utils/SelfRetraceTest.java
new file mode 100644
index 0000000..ab891e8
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/SelfRetraceTest.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2018, 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.utils;
+
+// NOTE: If you change this file you may need to update the expected line numbers in
+// tools/test_self_retrace.py
+public class SelfRetraceTest {
+  private static String SELFRETRACETEST_ENVIRONMENT_VAR = "R8_THROW_EXCEPTION_FOR_TESTING_RETRACE";
+
+  private void foo3() {
+    throw new RuntimeException("Intentional exception for testing retrace.");
+  }
+
+  private void foo2() {
+    foo3();
+  }
+
+  private void foo1() {
+    foo2();
+  }
+
+  public static void test() {
+    if (System.getenv(SELFRETRACETEST_ENVIRONMENT_VAR) != null) {
+      new SelfRetraceTest().foo1();
+    }
+  }
+}
diff --git a/src/main/keep-compatdx.txt b/src/main/keep-compatdx.txt
index 51b401c..75a8012 100644
--- a/src/main/keep-compatdx.txt
+++ b/src/main/keep-compatdx.txt
@@ -3,3 +3,4 @@
 # BSD-style license that can be found in the LICENSE file.
 
 -keep public class com.android.tools.r8.compatdx.CompatDx { public static void main(java.lang.String[]); }
+-keepattributes LineNumberTable
diff --git a/src/main/keep-compatproguard.txt b/src/main/keep-compatproguard.txt
index f508bea..e29d13e 100644
--- a/src/main/keep-compatproguard.txt
+++ b/src/main/keep-compatproguard.txt
@@ -3,3 +3,4 @@
 # BSD-style license that can be found in the LICENSE file.
 
 -keep public class com.android.tools.r8.compatproguard.CompatProguard { public static void main(java.lang.String[]); }
+-keepattributes LineNumberTable
diff --git a/src/main/keep.txt b/src/main/keep.txt
index 0d3812c..7642a71 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -12,3 +12,5 @@
 -keep public class com.android.tools.r8.compatdx.CompatDx { public static void main(java.lang.String[]); }
 -keep public class com.android.tools.r8.dexfilemerger.DexFileMerger { public static void main(java.lang.String[]); }
 -keep public class com.android.tools.r8.dexsplitter.DexSplitter { public static void main(java.lang.String[]); }
+
+-keepattributes LineNumberTable
diff --git a/tools/test_self_retrace.py b/tools/test_self_retrace.py
new file mode 100755
index 0000000..08b97db
--- /dev/null
+++ b/tools/test_self_retrace.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# Copyright (c) 2018, 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.
+
+import gradle
+import os
+import subprocess
+import sys
+import utils
+
+RETRACE_JAR = os.path.join(
+  utils.THIRD_PARTY,
+  'proguard',
+  'proguard6.0.1',
+  'lib',
+  'retrace.jar')
+
+EXCEPTION_LINE = 'Intentional exception for testing retrace.'
+EXPECTED_LINES = [
+  'com.android.tools.r8.utils.SelfRetraceTest.foo3(SelfRetraceTest.java:13)',
+  'com.android.tools.r8.utils.SelfRetraceTest.foo2(SelfRetraceTest.java:17)',
+  'com.android.tools.r8.utils.SelfRetraceTest.foo1(SelfRetraceTest.java:21)',
+  'com.android.tools.r8.utils.SelfRetraceTest.test(SelfRetraceTest.java:26)',
+  'com.android.tools.r8.R8.run(R8.java:',
+]
+
+def main():
+  gradle.RunGradle(['r8lib'])
+
+  # Run 'r8 --help' which throws an exception.
+  cmd = ['java','-cp', utils.R8LIB_JAR, 'com.android.tools.r8.R8', '--help']
+  os.environ["R8_THROW_EXCEPTION_FOR_TESTING_RETRACE"] = "1"
+  utils.PrintCmd(cmd)
+  p = subprocess.Popen(cmd, stderr=subprocess.PIPE)
+  _, stacktrace = p.communicate()
+  assert(p.returncode != 0)
+  assert(EXCEPTION_LINE in stacktrace)
+  # r8lib must be minified, original class names must not be present.
+  assert('SelfRetraceTest' not in stacktrace)
+
+  # Run the retrace tool.
+  cmd = ['java', '-jar', RETRACE_JAR, utils.R8LIB_JAR + ".map"]
+  utils.PrintCmd(cmd)
+  p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+  retrace_stdout, _ = p.communicate(stacktrace)
+  assert p.returncode == 0
+  retrace_lines = retrace_stdout.splitlines()
+  line_index = -1
+  for line in retrace_lines:
+    if line_index < 0:
+      if 'java.lang.RuntimeException' in line:
+        assert(EXCEPTION_LINE in line)
+        line_index = 0;
+    else:
+      assert EXPECTED_LINES[line_index] in line
+      line_index += 1
+      if line_index >= len(EXPECTED_LINES):
+         break
+  assert(line_index >= 0)
+
+if __name__ == '__main__':
+  sys.exit(main())