Test for setup with classpath extending program.
Bug: 149201158
Change-Id: I1af3172ce256434a5db2e190f5457844bdc406aa
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 0e510a9..8bc4820 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -30,6 +30,16 @@
super(state);
}
+ private Path writeClassesToJar(Collection<Class<?>> classes) {
+ try {
+ Path archive = getState().getNewTempFolder().resolve("out.jar");
+ TestBase.writeClassesToJar(archive, classes);
+ return archive;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public static JvmTestBuilder create(TestState state) {
return new JvmTestBuilder(state);
}
@@ -77,14 +87,7 @@
@Override
public JvmTestBuilder addProgramClasses(Collection<Class<?>> classes) {
- try {
- Path out = getState().getNewTempFolder().resolve("out.jar");
- TestBase.writeClassesToJar(out, classes);
- addProgramFiles(out);
- return self();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ return addProgramFiles(writeClassesToJar(classes));
}
@Override
diff --git a/src/test/java/com/android/tools/r8/classlookup/ClasspathClassExtendsProgramClassTest.java b/src/test/java/com/android/tools/r8/classlookup/ClasspathClassExtendsProgramClassTest.java
new file mode 100644
index 0000000..b409e5a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classlookup/ClasspathClassExtendsProgramClassTest.java
@@ -0,0 +1,105 @@
+// 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.classlookup;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.Reference;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+// This test runs an R8 setup where a classpath class extends a program class and the program in
+// turn uses the classpath class. Having such a cyclic compilation setup is very odd, but with
+// sufficient keep rules it can work.
+@RunWith(Parameterized.class)
+public class ClasspathClassExtendsProgramClassTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public ClasspathClassExtendsProgramClassTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ public static class ProgramClass {
+
+ public void foo() {
+ System.out.println("ProgramClass::foo");
+ }
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ ProgramClass object = args.length == 42 ? new ProgramClass() : new ClasspathClass();
+ object.foo();
+ }
+ }
+
+ public static class ClasspathIndirection extends ProgramClass {
+ // Intentionally empty.
+ }
+
+ public static class ClasspathClass extends ClasspathIndirection {
+
+ @Override
+ public void foo() {
+ System.out.println("ClasspathClass::foo");
+ }
+ }
+
+ @Test
+ public void testReference() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class, ProgramClass.class)
+ .addRunClasspathFiles(compileClasspath())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("ClasspathClass::foo");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(Main.class, ProgramClass.class)
+ .addClasspathClasses(ClasspathClass.class, ClasspathIndirection.class)
+ .addKeepMainRule(Main.class)
+ // Keep the method that is overridden by the classpath class.
+ .addKeepMethodRules(Reference.methodFromMethod(ProgramClass.class.getDeclaredMethod("foo")))
+ .addRunClasspathFiles(compileClasspath())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("ClasspathClass::foo");
+ }
+
+ private Path compileClasspath() throws java.io.IOException, CompilationFailedException {
+ return compile(
+ ImmutableList.of(ClasspathClass.class, ClasspathIndirection.class),
+ ImmutableList.of(ProgramClass.class));
+ }
+
+ private Path compile(Collection<Class<?>> compilationUnit, Collection<Class<?>> classpath)
+ throws java.io.IOException, CompilationFailedException {
+ if (parameters.isCfRuntime()) {
+ Path out = temp.newFolder().toPath().resolve("out.jar");
+ writeClassesToJar(out, compilationUnit);
+ return out;
+ }
+ return testForD8()
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClasses(compilationUnit)
+ .addClasspathClasses(classpath)
+ .compile()
+ .writeToZip();
+ }
+}