Update tracereferences to keep failed resolutions

Bug: 199142461
Change-Id: Ib81c1cd56b9fef7f37756a8d9a79c7f9df6255c1
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 55bec5b..8db4392 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -620,7 +620,8 @@
     return signaturePolymorphicMethod;
   }
 
-  private boolean isSignaturePolymorphicMethod(DexEncodedMethod method, DexItemFactory factory) {
+  public static boolean isSignaturePolymorphicMethod(
+      DexEncodedMethod method, DexItemFactory factory) {
     assert method.getHolderType() == factory.methodHandleType
         || method.getHolderType() == factory.varHandleType;
     return method.accessFlags.isVarargs()
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java
index c3c8e30..331ccec 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommandParser.java
@@ -48,7 +48,6 @@
                   "                          # outside of library are treated as a missing",
                   "                          # references.",
                   "  --output <file>         # Output result in <outfile>. If not passed the",
-                  "                          # result will go to standard out.",
                   "                          # result will go to standard out."),
               BaseCompilerCommandParser.MAP_DIAGNOSTICS_USAGE_MESSAGE,
               Arrays.asList(
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index ee3c33d..0a1ec66 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -200,7 +200,7 @@
       // - The holder type is registered from visiting the extends/implements clause of the sub
       //   class.
 
-      TracedMethodImpl tracedMethod = new TracedMethodImpl(method, referencedFrom);
+      TracedMethodImpl tracedMethod = new TracedMethodImpl(method.getDefinition(), referencedFrom);
       if (isTargetType(method.getHolderType())) {
         consumer.acceptMethod(tracedMethod, diagnostics);
         if (method.getAccessFlags().isVisibilityDependingOnPackage()) {
@@ -323,9 +323,8 @@
         MethodLookupResult lookupResult = graphLens.lookupInvokeStatic(method, context);
         assert lookupResult.getType().isStatic();
         DexMethod rewrittenMethod = lookupResult.getReference();
-        DexClassAndMethod resolvedMethod =
-            appInfo.unsafeResolveMethodDueToDexFormat(rewrittenMethod).getResolutionPair();
-        handleRewrittenMethodReference(rewrittenMethod, resolvedMethod);
+        handleRewrittenMethodResolution(
+            rewrittenMethod, appInfo.unsafeResolveMethodDueToDexFormat(rewrittenMethod));
       }
 
       @Override
@@ -333,8 +332,16 @@
         MethodLookupResult lookupResult = graphLens.lookupInvokeSuper(method, context);
         assert lookupResult.getType().isSuper();
         DexMethod rewrittenMethod = lookupResult.getReference();
-        DexClassAndMethod superTarget = appInfo.lookupSuperTarget(rewrittenMethod, context);
-        handleRewrittenMethodReference(rewrittenMethod, superTarget);
+        MethodResolutionResult resolutionResult =
+            appInfo.unsafeResolveMethodDueToDexFormat(rewrittenMethod);
+        if (resolutionResult.isFailedResolution()
+            && resolutionResult.asFailedResolution().hasMethodsCausingError()) {
+          handleRewrittenMethodResolution(rewrittenMethod, resolutionResult);
+          return;
+        }
+        handleRewrittenMethodReference(
+            rewrittenMethod,
+            resolutionResult.lookupInvokeSuperTarget(context.getHolder(), appInfo));
       }
 
       @Override
@@ -352,18 +359,39 @@
           return;
         }
         assert lookupResult.getType().isInterface() || lookupResult.getType().isVirtual();
-        MethodResolutionResult resolutionResult =
+        handleRewrittenMethodResolution(
+            method,
             lookupResult.getType().isInterface()
                 ? appInfo.resolveMethodOnInterface(method)
-                : appInfo.resolveMethodOnClass(method);
-        DexClassAndMethod resolvedMethod =
-            resolutionResult.isVirtualTarget() ? resolutionResult.getResolutionPair() : null;
-        handleRewrittenMethodReference(method, resolvedMethod);
+                : appInfo.resolveMethodOnClass(method));
+      }
+
+      private void handleRewrittenMethodResolution(
+          DexMethod method, MethodResolutionResult resolutionResult) {
+        if (resolutionResult.isFailedResolution()
+            && resolutionResult.asFailedResolution().hasMethodsCausingError()) {
+          resolutionResult
+              .asFailedResolution()
+              .forEachFailureDependency(
+                  methodCausingFailure -> {
+                    handleRewrittenMethodReference(method, methodCausingFailure);
+                  });
+          return;
+        }
+        handleRewrittenMethodReference(method, resolutionResult.getResolutionPair());
       }
 
       private void handleRewrittenMethodReference(
           DexMethod method, DexClassAndMethod resolvedMethod) {
-        assert resolvedMethod == null || resolvedMethod.getReference().match(method);
+        handleRewrittenMethodReference(
+            method, resolvedMethod == null ? null : resolvedMethod.getDefinition());
+      }
+
+      private void handleRewrittenMethodReference(
+          DexMethod method, DexEncodedMethod resolvedMethod) {
+        assert resolvedMethod == null
+            || resolvedMethod.getReference().match(method)
+            || DexClass.isSignaturePolymorphicMethod(resolvedMethod, factory);
         addType(method.getHolderType(), referencedFrom);
         addTypes(method.getParameters(), referencedFrom);
         addType(method.getReturnType(), referencedFrom);
diff --git a/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java b/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
index 1ea760a..ea39cb6 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/internal/TracedMethodImpl.java
@@ -5,7 +5,7 @@
 package com.android.tools.r8.tracereferences.internal;
 
 import com.android.tools.r8.diagnostic.DefinitionContext;
-import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.tracereferences.TraceReferencesConsumer.MethodAccessFlags;
@@ -17,9 +17,9 @@
     this(method.asMethodReference(), referencedFrom, null);
   }
 
-  public TracedMethodImpl(DexClassAndMethod method, DefinitionContext referencedFrom) {
+  public TracedMethodImpl(DexEncodedMethod method, DefinitionContext referencedFrom) {
     this(
-        method.getMethodReference(),
+        method.getReference().asMethodReference(),
         referencedFrom,
         new MethodAccessFlagsImpl(method.getAccessFlags()));
   }
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesFailedResolutionInSourceTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesFailedResolutionInSourceTest.java
new file mode 100644
index 0000000..d753147
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesFailedResolutionInSourceTest.java
@@ -0,0 +1,101 @@
+// Copyright (c) 2021, 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.tracereferences;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TraceReferencesFailedResolutionInSourceTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public TraceReferencesFailedResolutionInSourceTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  static class SeenReferencesConsumer implements TraceReferencesConsumer {
+
+    private Set<MethodReference> seenMethods = new HashSet<>();
+
+    @Override
+    public void acceptType(TracedClass tracedClass, DiagnosticsHandler handler) {}
+
+    @Override
+    public void acceptField(TracedField tracedField, DiagnosticsHandler handler) {}
+
+    @Override
+    public void acceptMethod(TracedMethod tracedMethod, DiagnosticsHandler handler) {
+      seenMethods.add(tracedMethod.getReference());
+    }
+  }
+
+  @Test
+  public void testInvalidResolution() throws Exception {
+    Path dir = temp.newFolder().toPath();
+    Path targetJar =
+        ZipBuilder.builder(dir.resolve("target.jar"))
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(I.class))
+            .build();
+    Path sourceJar =
+        ZipBuilder.builder(dir.resolve("source.jar"))
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(),
+                ToolHelper.getClassFileForTestClass(A.class),
+                ToolHelper.getClassFileForTestClass(B.class),
+                ToolHelper.getClassFileForTestClass(Main.class))
+            .build();
+    SeenReferencesConsumer consumer = new SeenReferencesConsumer();
+    TraceReferences.run(
+        TraceReferencesCommand.builder()
+            .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+            .addSourceFiles(sourceJar)
+            .addTargetFiles(targetJar)
+            .setConsumer(consumer)
+            .build());
+    assertTrue(consumer.seenMethods.isEmpty());
+  }
+
+  public interface I {
+    default void f() {
+      System.out.println("I::f");
+    }
+  }
+
+  public static class A {
+    private static void f() {
+      System.out.println("A::f");
+    }
+  }
+
+  public static class B extends A implements I {}
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      new B().f();
+    }
+  }
+}