Add test for normalizing proto to virtual method defined in library
Bug: b/258720808
Change-Id: Ib2e17221cb013005e1410deff257cc72df4e1558
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationDestinationOverrideLibraryTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationDestinationOverrideLibraryTest.java
new file mode 100644
index 0000000..3b7a115
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationDestinationOverrideLibraryTest.java
@@ -0,0 +1,111 @@
+// 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.optimize.proto;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoMethodStaticizing;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+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;
+
+@RunWith(Parameterized.class)
+public class ProtoNormalizationDestinationOverrideLibraryTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private static final String[] EXPECTED = new String[] {"LibraryMethod421337"};
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class, ProgramClass.class, X.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryClasses(LibraryClass.class)
+ .addRunClasspathFiles(buildOnDexRuntime(parameters, LibraryClass.class))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ // TODO(b/258720808): We should not fail compilation.
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Main.class, ProgramClass.class, X.class)
+ .addDefaultRuntimeLibrary(parameters)
+ .addLibraryClasses(LibraryClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(Main.class)
+ .addDontObfuscate()
+ .enableInliningAnnotations()
+ .enableNoMethodStaticizingAnnotations()
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorMessageThatMatches(
+ containsString(
+ "went from not overriding a library method to overriding a library"
+ + " method"));
+ }));
+ }
+
+ public static class LibraryClass {
+
+ public void foo(int i1, int i2, String bar) {
+ System.out.println(bar + i1 + i2);
+ }
+
+ public static void callFoo(LibraryClass clazz) {
+ clazz.foo(42, 1337, "LibraryMethod");
+ }
+ }
+
+ public static class ProgramClass extends LibraryClass {
+ @NeverInline
+ @NoMethodStaticizing
+ public void foo(String bar, int i1, int i2) {
+ System.out.println(i1 + i2 + bar);
+ }
+ }
+
+ // Needs to have a class name that is after lexicographically than ProgramClass.
+ public static class X {
+ @NeverInline
+ public void foo(int i1, String bar, int i2) {
+ System.out.println(i1 + bar + i2);
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ ProgramClass programClass = new ProgramClass();
+ X otherProgramClass = new X();
+ if (args.length == 1) {
+ programClass.foo("Hello World", 1, 1);
+ otherProgramClass.foo(1, "Hello World", 1);
+ } else if (args.length > 1) {
+ programClass.foo("Goodbye World", 2, 2);
+ otherProgramClass.foo(2, "Goodbye World", 2);
+ }
+ LibraryClass.callFoo(programClass);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
index ba776e4..c179493 100644
--- a/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/optimize/proto/ProtoNormalizationWithVirtualMethodCollisionTest.java
@@ -33,6 +33,20 @@
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
+ private final String[] EXPECTED =
+ new String[] {"A::foo", "B", "A", "B::foo", "B", "A", "B::foo", "B", "A"};
+
+ private final String[] R8_EXPECTED =
+ new String[] {"A::foo", "B", "A", "A::foo", "B", "A", "B::foo", "B", "A"};
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
@Test
public void test() throws Exception {
testForR8(parameters.getBackend())
@@ -40,20 +54,23 @@
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
- // TODO(b/173398086): uniqueMethodWithName() does not work with proto changes.
.addDontObfuscate()
+ .addKeepClassAndMembersRules(B.class)
.setMinApi(parameters.getApiLevel())
.compile()
+ .run(parameters.getRuntime(), Main.class)
+ // TODO(b/258720808): We should not produce incorrect results.
+ .assertSuccessWithOutputLines(R8_EXPECTED)
.inspect(
inspector -> {
- ClassSubject aClassSubject = inspector.clazz(A.class);
- assertThat(aClassSubject, isPresent());
-
ClassSubject bClassSubject = inspector.clazz(B.class);
assertThat(bClassSubject, isPresent());
- TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
TypeSubject bTypeSubject = bClassSubject.asTypeSubject();
+ TypeSubject aTypeSubject = aClassSubject.asTypeSubject();
MethodSubject fooMethodSubject = aClassSubject.uniqueMethodWithOriginalName("foo");
assertThat(fooMethodSubject, isPresent());
@@ -62,12 +79,10 @@
// TODO(b/173398086): Consider rewriting B.foo(B, A) to B.foo(A, B, C) instead of
// B.foo$1(A, B).
MethodSubject otherFooMethodSubject =
- bClassSubject.uniqueMethodWithOriginalName("foo$1");
+ bClassSubject.uniqueMethodWithOriginalName("foo");
assertThat(otherFooMethodSubject, isPresent());
assertThat(otherFooMethodSubject, hasParameters(aTypeSubject, bTypeSubject));
- })
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("A", "B", "A", "B");
+ });
}
static class Main {
@@ -75,16 +90,18 @@
public static void main(String[] args) {
A a = new A();
B b = new B();
+ a.foo(b, a);
a.foo(a, b);
- b.foo(b, a);
+ b.foo(a, b);
}
}
@NoVerticalClassMerging
- static class A {
+ static class B {
@NeverInline
public void foo(A a, B b) {
+ System.out.println("B::foo");
System.out.println(a);
System.out.println(b);
}
@@ -95,10 +112,11 @@
}
}
- static class B extends A {
+ static class A extends B {
@NeverInline
public void foo(B b, A a) {
+ System.out.println("A::foo");
System.out.println(a);
System.out.println(b);
}