Add test for invalid lookup in traceref when having classes in lib and program

Bug: b/226170842
Change-Id: Id67c9ce7cb93a3a4718b25f909b1df72aff62b3f
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java
new file mode 100644
index 0000000..4dcf1cd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceMethodResolutionWithLibraryAndProgramClassTest.java
@@ -0,0 +1,147 @@
+// 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 TraceMethodResolutionWithLibraryAndProgramClassTest 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")));
+    ImmutableSet<MethodReference> missingSet =
+        ImmutableSet.of(
+            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);
+  }
+
+  // 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;
+    }
+  }
+}