[Retrace] Lookup source file mappings for inline frames

Bug: 160938883
Change-Id: I557e14f0876218057a7937c310a5884efed85f92
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
index f984045..e13c832 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassResult.java
@@ -26,15 +26,18 @@
 
   private final ClassReference obfuscatedReference;
   private final ClassNamingForNameMapper mapper;
+  private final RetraceApi retracer;
 
-  private RetraceClassResult(ClassReference obfuscatedReference, ClassNamingForNameMapper mapper) {
+  private RetraceClassResult(
+      ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetraceApi retracer) {
     this.obfuscatedReference = obfuscatedReference;
     this.mapper = mapper;
+    this.retracer = retracer;
   }
 
   static RetraceClassResult create(
-      ClassReference obfuscatedReference, ClassNamingForNameMapper mapper) {
-    return new RetraceClassResult(obfuscatedReference, mapper);
+      ClassReference obfuscatedReference, ClassNamingForNameMapper mapper, RetraceApi retracer) {
+    return new RetraceClassResult(obfuscatedReference, mapper, retracer);
   }
 
   public RetraceFieldResult lookupField(String fieldName) {
@@ -75,12 +78,12 @@
           if (element.mapper != null) {
             mappedRangesForT = lookupFunction.apply(element.mapper, name);
           }
-          elementBox.set(constructor.create(element, mappedRangesForT, name));
+          elementBox.set(constructor.create(element, mappedRangesForT, name, retracer));
         });
     return elementBox.get();
   }
 
-  private boolean hasRetraceResult() {
+  boolean hasRetraceResult() {
     return mapper != null;
   }
 
@@ -101,7 +104,7 @@
   }
 
   private interface ResultConstructor<T, R> {
-    R create(Element element, T mappings, String obfuscatedName);
+    R create(Element element, T mappings, String obfuscatedName, RetraceApi retraceApi);
   }
 
   public boolean isAmbiguous() {
@@ -186,7 +189,10 @@
         BiFunction<ClassNamingForNameMapper, String, T> lookupFunction,
         ResultConstructor<T, R> constructor) {
       return constructor.create(
-          this, mapper != null ? lookupFunction.apply(mapper, name) : null, name);
+          this,
+          mapper != null ? lookupFunction.apply(mapper, name) : null,
+          name,
+          classResult.retracer);
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
index 57b5354..5477eaa 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFieldResult.java
@@ -23,14 +23,17 @@
   private final RetraceClassResult.Element classElement;
   private final List<MemberNaming> memberNamings;
   private final String obfuscatedName;
+  private final RetraceApi retracer;
 
   RetraceFieldResult(
       RetraceClassResult.Element classElement,
       List<MemberNaming> memberNamings,
-      String obfuscatedName) {
+      String obfuscatedName,
+      RetraceApi retracer) {
     this.classElement = classElement;
     this.memberNamings = memberNamings;
     this.obfuscatedName = obfuscatedName;
+    this.retracer = retracer;
     assert classElement != null;
     assert memberNamings == null
         || (!memberNamings.isEmpty() && memberNamings.stream().allMatch(Objects::nonNull));
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
index ff1af91..7977858 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceMethodResult.java
@@ -26,15 +26,18 @@
   private final String obfuscatedName;
   private final RetraceClassResult.Element classElement;
   private final MappedRangesOfName mappedRanges;
+  private final RetraceApi retracer;
   private Boolean isAmbiguousCached = null;
 
   RetraceMethodResult(
       RetraceClassResult.Element classElement,
       MappedRangesOfName mappedRanges,
-      String obfuscatedName) {
+      String obfuscatedName,
+      RetraceApi retracer) {
     this.classElement = classElement;
     this.mappedRanges = mappedRanges;
     this.obfuscatedName = obfuscatedName;
+    this.retracer = retracer;
     assert classElement != null;
   }
 
@@ -87,7 +90,7 @@
       }
     }
     return new RetraceMethodResult(
-        classElement, new MappedRangesOfName(narrowedRanges), obfuscatedName);
+        classElement, new MappedRangesOfName(narrowedRanges), obfuscatedName, retracer);
   }
 
   @Override
@@ -182,7 +185,8 @@
     }
 
     public RetraceSourceFileResult retraceSourceFile(String sourceFile) {
-      return RetraceUtils.getSourceFile(classElement, methodReference.getHolderClass(), sourceFile);
+      return RetraceUtils.getSourceFile(
+          classElement, methodReference.getHolderClass(), sourceFile, retraceMethodResult.retracer);
     }
   }
 }
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 15479f9..40b3f41 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceRegularExpression.java
@@ -838,7 +838,8 @@
                   : RetraceUtils.getSourceFile(
                       retraceString.getClassContext(),
                       retraceString.context.qualifiedContext,
-                      fileName);
+                      fileName,
+                      retracer);
           retracedStrings.add(
               retraceString
                   .updateContext(context -> context.withSource(sourceFileResult.getFilename()))
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java b/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
index fd569b1..77aff7d 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceUtils.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.utils.Box;
 import com.google.common.collect.Sets;
 import com.google.common.io.Files;
 import java.util.Set;
@@ -61,21 +62,33 @@
   }
 
   static RetraceSourceFileResult getSourceFile(
-      RetraceClassResult.Element classElement, ClassReference context, String sourceFile) {
-    // For inline frames we do not have the class element associated with it.
+      RetraceClassResult.Element classElement,
+      ClassReference context,
+      String sourceFile,
+      RetraceApi retracer) {
+    // If no context is specified always retrace using the found class element.
     if (context == null) {
       return classElement.retraceSourceFile(sourceFile);
     }
     if (context.equals(classElement.getClassReference())) {
       return classElement.retraceSourceFile(sourceFile);
     } else {
-      return new RetraceSourceFileResult(
-          synthesizeFileName(
-              context.getTypeName(),
-              classElement.getClassReference().getTypeName(),
-              sourceFile,
-              true),
-          true);
+      RetraceClassResult contextClassResult = retracer.retrace(context);
+      assert !contextClassResult.isAmbiguous();
+      if (contextClassResult.hasRetraceResult()) {
+        Box<RetraceSourceFileResult> retraceSourceFile = new Box<>();
+        contextClassResult.forEach(
+            element -> retraceSourceFile.set(element.retraceSourceFile(sourceFile)));
+        return retraceSourceFile.get();
+      } else {
+        return new RetraceSourceFileResult(
+            synthesizeFileName(
+                context.getTypeName(),
+                classElement.getClassReference().getTypeName(),
+                sourceFile,
+                true),
+            true);
+      }
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/retrace/Retracer.java b/src/main/java/com/android/tools/r8/retrace/Retracer.java
index b2dad89..0f7d547 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retracer.java
@@ -38,7 +38,7 @@
   @Override
   public RetraceClassResult retrace(ClassReference classReference) {
     return RetraceClassResult.create(
-        classReference, classNameMapper.getClassNaming(classReference.getTypeName()));
+        classReference, classNameMapper.getClassNaming(classReference.getTypeName()), this);
   }
 
   @Override
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 9af9e28..8bf3b29 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.retrace.stacktraces.FileNameExtensionStackTrace;
 import com.android.tools.r8.retrace.stacktraces.InlineFileNameStackTrace;
 import com.android.tools.r8.retrace.stacktraces.InlineNoLineNumberStackTrace;
+import com.android.tools.r8.retrace.stacktraces.InlineSourceFileContextStackTrace;
 import com.android.tools.r8.retrace.stacktraces.InlineWithLineNumbersStackTrace;
 import com.android.tools.r8.retrace.stacktraces.InvalidStackTrace;
 import com.android.tools.r8.retrace.stacktraces.NamedModuleStackTrace;
@@ -173,6 +174,11 @@
     runRetraceTest(new UnknownSourceStackTrace());
   }
 
+  @Test
+  public void testInlineSourceFileContext() {
+    runRetraceTest(new InlineSourceFileContextStackTrace());
+  }
+
   private TestDiagnosticMessagesImpl runRetraceTest(StackTraceForTest stackTraceForTest) {
     TestDiagnosticMessagesImpl diagnosticsHandler = new TestDiagnosticMessagesImpl();
     RetraceCommand retraceCommand =
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineSourceFileContextStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineSourceFileContextStackTrace.java
new file mode 100644
index 0000000..3c22097
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/InlineSourceFileContextStackTrace.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2020, 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 com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class InlineSourceFileContextStackTrace implements StackTraceForTest {
+
+  @Override
+  public List<String> obfuscatedStackTrace() {
+    return Arrays.asList(
+        "  at com.google.appreduce.remapper.KotlinJavaSourceFileTestObject"
+            + ".main(KotlinJavaSourceFileTestObject.java:1)");
+  }
+
+  @Override
+  public String mapping() {
+    return StringUtils.joinLines(
+        "com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary ->"
+            + " com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary:",
+        "# {\"id\":\"sourceFile\",\"fileName\":\"KotlinJavaSourceFileTestLibrary.kt\"}",
+        "    void <init>() -> <init>",
+        "com.google.appreduce.remapper.KotlinJavaSourceFileTestObject ->"
+            + " com.google.appreduce.remapper.KotlinJavaSourceFileTestObject:",
+        "    void <init>() -> <init>",
+        "    1:1:void com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
+            + ".throwsException():22:22 -> main",
+        "    1:1:void com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
+            + ".callsThrowsException():19 -> main",
+        "    1:1:void main(java.lang.String[]):32 -> main",
+        "    2:7:void printStackTraceUpToMain(java.lang.Exception):19:24 -> main",
+        "    2:7:void main(java.lang.String[]):34 -> main");
+  }
+
+  @Override
+  public List<String> retracedStackTrace() {
+    return Arrays.asList(
+        "  at com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
+            + ".throwsException(KotlinJavaSourceFileTestLibrary.kt:22)",
+        "  at com.google.appreduce.remapper.KotlinJavaSourceFileTestLibrary"
+            + ".callsThrowsException(KotlinJavaSourceFileTestLibrary.kt:19)",
+        "  at com.google.appreduce.remapper.KotlinJavaSourceFileTestObject"
+            + ".main(KotlinJavaSourceFileTestObject.java:32)");
+  }
+
+  @Override
+  public int expectedWarnings() {
+    return 0;
+  }
+}