Ensure not reporting missing definitions for multiple types in traceref

Bug: b/226170842
Change-Id: Idb09af434698ac1cb369836505b70b91aff024a2
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
index 6b6991d..c56866e 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -1127,6 +1127,11 @@
         Consumer<? super FailedResolutionResult> failedResolutionConsumer) {
       failedResolutionConsumer.accept(this);
     }
+
+    public boolean hasTypesOrMethodsCausingError() {
+      return (typesCausingError != null && !typesCausingError.isEmpty())
+          || hasMethodsCausingError();
+    }
   }
 
   public static class ClassNotFoundResult extends FailedResolutionResult {
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 a17a299..3a25350 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -245,11 +245,12 @@
           }
         }
       }
-
+      MethodResolutionResult methodResolutionResult =
+          method.getHolder().isInterface()
+              ? appInfo().resolveMethodOnInterface(method.getHolder(), method.getReference())
+              : appInfo().resolveMethodOnClass(method.getHolder(), method.getReference());
       DexClassAndMethod superTarget =
-          appInfo()
-              .resolveMethodOnLegacy(method.getHolder(), method.getReference())
-              .lookupInvokeSpecialTarget(method.getHolder(), appInfo());
+          methodResolutionResult.lookupInvokeSpecialTarget(method.getHolder(), appInfo());
       if (superTarget != null
           && !superTarget.isProgramMethod()
           && isTargetType(superTarget.getHolderType())) {
@@ -269,8 +270,7 @@
           method -> {
             DexClassAndMethod resolvedMethod =
                 appInfo()
-                    .resolveMethodOnLegacy(
-                        superType, method.getReference(), superType != clazz.superType)
+                    .resolveMethodOn(superType, method.getReference(), superType != clazz.superType)
                     .getResolutionPair();
             if (resolvedMethod != null
                 && !resolvedMethod.isProgramMethod()
@@ -314,7 +314,7 @@
         assert lookupResult.getType().isStatic();
         DexMethod rewrittenMethod = lookupResult.getReference();
         handleRewrittenMethodResolution(
-            rewrittenMethod, appInfo().unsafeResolveMethodDueToDexFormatLegacy(rewrittenMethod));
+            rewrittenMethod, appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod));
       }
 
       @Override
@@ -323,7 +323,7 @@
         assert lookupResult.getType().isSuper();
         DexMethod rewrittenMethod = lookupResult.getReference();
         MethodResolutionResult resolutionResult =
-            appInfo().unsafeResolveMethodDueToDexFormatLegacy(rewrittenMethod);
+            appInfo().unsafeResolveMethodDueToDexFormat(rewrittenMethod);
         if (resolutionResult.isFailedResolution()
             && resolutionResult.asFailedResolution().hasMethodsCausingError()) {
           handleRewrittenMethodResolution(rewrittenMethod, resolutionResult);
@@ -352,23 +352,26 @@
         handleRewrittenMethodResolution(
             method,
             lookupResult.getType().isInterface()
-                ? appInfo().resolveMethodOnInterfaceHolderLegacy(method)
-                : appInfo().resolveMethodOnClassHolderLegacy(method));
+                ? appInfo().resolveMethodOnInterfaceHolder(method)
+                : appInfo().resolveMethodOnClassHolder(method));
       }
 
       private void handleRewrittenMethodResolution(
           DexMethod method, MethodResolutionResult resolutionResult) {
-        if (resolutionResult.isFailedResolution()
-            && resolutionResult.asFailedResolution().hasMethodsCausingError()) {
-          resolutionResult
-              .asFailedResolution()
-              .forEachFailureDependency(
-                  type -> addType(type, referencedFrom),
-                  methodCausingFailure ->
-                      handleRewrittenMethodReference(method, methodCausingFailure));
-          return;
-        }
-        handleRewrittenMethodReference(method, resolutionResult.getResolutionPair());
+        resolutionResult.forEachMethodResolutionResult(
+            result -> {
+              if (result.isFailedResolution()
+                  && result.asFailedResolution().hasTypesOrMethodsCausingError()) {
+                result
+                    .asFailedResolution()
+                    .forEachFailureDependency(
+                        type -> addType(type, referencedFrom),
+                        methodCausingFailure ->
+                            handleRewrittenMethodReference(method, methodCausingFailure));
+                return;
+              }
+              handleRewrittenMethodReference(method, result.getResolutionPair());
+            });
       }
 
       private void handleRewrittenMethodReference(
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java
index 4dcf1cd..0a2809a 100644
--- a/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java
@@ -13,11 +13,10 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
-import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
 import com.google.common.collect.ImmutableSet;
 import java.nio.file.Path;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import org.junit.Test;
@@ -26,7 +25,6 @@
 import org.junit.runners.Parameterized.Parameter;
 import org.junit.runners.Parameterized.Parameters;
 
-// This is a regression test for b/226170842.
 @RunWith(Parameterized.class)
 public class TraceMethodResolutionWithLibraryAndProgramClassTest extends TestBase {
 
@@ -59,23 +57,21 @@
   }
 
   @Test
-  public void testInvalidResolution() throws Exception {
+  public void testValidResolution() throws Exception {
     Path dir = temp.newFolder().toPath();
     Path libJar =
         ZipBuilder.builder(dir.resolve("lib.jar"))
             .addFilesRelative(
-                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(A.class))
-            .addBytes(
-                DescriptorUtils.getPathFromJavaType(B.class),
-                transformer(B.class).removeMethods(MethodPredicate.all()).transform())
+                ToolHelper.getClassPathForTests(),
+                ToolHelper.getClassFileForTestClass(A.class),
+                ToolHelper.getClassFileForTestClass(B.class))
             .build();
     Path targetJar =
         ZipBuilder.builder(dir.resolve("target.jar"))
-            .addBytes(
-                DescriptorUtils.getPathFromJavaType(A.class),
-                transformer(A.class).removeMethods(MethodPredicate.all()).transform())
             .addFilesRelative(
-                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(B.class))
+                ToolHelper.getClassPathForTests(),
+                ToolHelper.getClassFileForTestClass(A.class),
+                ToolHelper.getClassFileForTestClass(B.class))
             .build();
     Path sourceJar =
         ZipBuilder.builder(dir.resolve("source.jar"))
@@ -94,14 +90,11 @@
     ImmutableSet<MethodReference> foundSet =
         ImmutableSet.of(
             Reference.methodFromMethod(A.class.getMethod("foo")),
-            Reference.methodFromMethod(A.class.getMethod("bar")));
-    ImmutableSet<MethodReference> missingSet =
-        ImmutableSet.of(
+            Reference.methodFromMethod(A.class.getMethod("bar")),
             Reference.methodFromMethod(B.class.getMethod("baz")),
             Reference.methodFromMethod(B.class.getMethod("qux")));
     assertEquals(foundSet, consumer.seenMethods);
-    // TODO(b/226170842): Methods should not be missing.
-    assertEquals(missingSet, consumer.seenMissingMethods);
+    assertEquals(Collections.emptySet(), consumer.seenMissingMethods);
   }
 
   // A is added to both library and program, but the program one is missing the methods {foo,bar}
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithMissingLibraryAndProgramClassTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithMissingLibraryAndProgramClassTest.java
new file mode 100644
index 0000000..18ece27
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithMissingLibraryAndProgramClassTest.java
@@ -0,0 +1,144 @@
+// Copyright (c) 2022, 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.assertEquals;
+
+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.references.Reference;
+import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import com.google.common.collect.ImmutableSet;
+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.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+// This is a regression test for b/226170842.
+@RunWith(Parameterized.class)
+public class TraceMethodResolutionWithMissingLibraryAndProgramClassTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  static class SeenReferencesConsumer implements TraceReferencesConsumer {
+
+    private final Set<MethodReference> seenMethods = new HashSet<>();
+    private final Set<MethodReference> seenMissingMethods = 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) {
+      if (tracedMethod.isMissingDefinition()) {
+        seenMissingMethods.add(tracedMethod.getReference());
+      } else {
+        seenMethods.add(tracedMethod.getReference());
+      }
+    }
+  }
+
+  @Test
+  public void testInvalidResolution() throws Exception {
+    Path dir = temp.newFolder().toPath();
+    Path libJar =
+        ZipBuilder.builder(dir.resolve("lib.jar"))
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(A.class))
+            .addBytes(
+                DescriptorUtils.getPathFromJavaType(B.class),
+                transformer(B.class).removeMethods(MethodPredicate.all()).transform())
+            .build();
+    Path targetJar =
+        ZipBuilder.builder(dir.resolve("target.jar"))
+            .addBytes(
+                DescriptorUtils.getPathFromJavaType(A.class),
+                transformer(A.class).removeMethods(MethodPredicate.all()).transform())
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(B.class))
+            .build();
+    Path sourceJar =
+        ZipBuilder.builder(dir.resolve("source.jar"))
+            .addFilesRelative(
+                ToolHelper.getClassPathForTests(), ToolHelper.getClassFileForTestClass(Main.class))
+            .build();
+    SeenReferencesConsumer consumer = new SeenReferencesConsumer();
+    TraceReferences.run(
+        TraceReferencesCommand.builder()
+            .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+            .addLibraryFiles(libJar)
+            .addTargetFiles(targetJar)
+            .addSourceFiles(sourceJar)
+            .setConsumer(consumer)
+            .build());
+    ImmutableSet<MethodReference> foundSet =
+        ImmutableSet.of(
+            Reference.methodFromMethod(A.class.getMethod("foo")),
+            Reference.methodFromMethod(A.class.getMethod("bar")),
+            Reference.methodFromMethod(B.class.getMethod("baz")),
+            Reference.methodFromMethod(B.class.getMethod("qux")));
+    assertEquals(foundSet, consumer.seenMethods);
+    assertEquals(foundSet, consumer.seenMissingMethods);
+  }
+
+  // A is added to both library and program, but the program one is missing the methods {foo,bar}
+  public static class A {
+
+    public static boolean foo() {
+      return true;
+    }
+
+    public int bar() {
+      return 42;
+    }
+  }
+
+  // B is added to both library and program, but the library one is missing the methods {baz,qux}
+  public static class B {
+
+    public static boolean baz() {
+      return false;
+    }
+
+    public int qux() {
+      return 42;
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      A a = getAInstance(null);
+      B b = getBInstance(null);
+      int value = (A.foo() && B.baz()) ? a.bar() : b.qux();
+    }
+
+    private static A getAInstance(Object o) {
+      return (A) o;
+    }
+
+    private static B getBInstance(Object o) {
+      return (B) o;
+    }
+  }
+}