Add test for generic signatures that should be pruned in fullmode

Bug: 184927364
Change-Id: Ic051d4d851e6501745455f9390a21051680f3bc2
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepReferencesPruneTest.java b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepReferencesPruneTest.java
new file mode 100644
index 0000000..1c3ddbb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/GenericSignatureKeepReferencesPruneTest.java
@@ -0,0 +1,112 @@
+// 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.graph.genericsignature;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.graph.genericsignature.testclasses.Foo;
+import com.android.tools.r8.graph.genericsignature.testclasses.I;
+import com.android.tools.r8.graph.genericsignature.testclasses.J;
+import com.android.tools.r8.graph.genericsignature.testclasses.K;
+import com.android.tools.r8.graph.genericsignature.testclasses.L;
+import com.android.tools.r8.graph.genericsignature.testclasses.Main;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.util.List;
+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 GenericSignatureKeepReferencesPruneTest extends TestBase {
+
+  private final String[] EXPECTED =
+      new String[] {
+        Foo.class.getTypeName() + "<java.lang.String>",
+        I.class.getTypeName()
+            + "<java.lang.Integer, "
+            + Foo.class.getTypeName()
+            + "<java.lang.Integer>>",
+        I.class.getTypeName()
+            + "<java.lang.String, "
+            + Foo.class.getTypeName()
+            + "<java.lang.String>>",
+        "Hello world"
+      };
+
+  private final TestParameters parameters;
+  private final boolean isCompat;
+
+  @Parameters(name = "{0}, isCompat: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+  }
+
+  public GenericSignatureKeepReferencesPruneTest(TestParameters parameters, boolean isCompat) {
+    this.parameters = parameters;
+    this.isCompat = isCompat;
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm()
+        .addProgramClasses(I.class, Foo.class, J.class, K.class, L.class)
+        .addProgramClassesAndInnerClasses(Main.class)
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines(EXPECTED);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    (isCompat ? testForR8Compat(parameters.getBackend()) : testForR8(parameters.getBackend()))
+        .addProgramClasses(I.class, Foo.class, J.class, K.class, L.class)
+        .addProgramClassesAndInnerClasses(Main.class)
+        .addKeepClassAndMembersRules(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepAttributeSignature()
+        .addKeepAttributeInnerClassesAndEnclosingMethod()
+        .enableInliningAnnotations()
+        .enableNeverClassInliningAnnotations()
+        .noMinification()
+        .run(parameters.getRuntime(), Main.class)
+        // TODO(b/184927364): Should have different output due to pruning the inner class.
+        .assertSuccessWithOutputLines(EXPECTED)
+        .inspect(this::inspectSignatures);
+  }
+
+  private void inspectSignatures(CodeInspector inspector) {
+    ClassSubject fooClass = inspector.clazz(Foo.class);
+    assertThat(fooClass, isPresent());
+    // TODO(b/184927364): Fullmode should not keep the interface bound.
+    assertEquals(
+        "<T::Ljava/lang/Comparable<TT;>;>Ljava/lang/Object;",
+        fooClass.getFinalSignatureAttribute());
+    ClassSubject iClass = inspector.clazz(I.class);
+    assertThat(iClass, isPresent());
+    // TODO(b/184927364): Fullmode should not keep the interface and class bound.
+    assertEquals(
+        "<T::Ljava/lang/Comparable<TT;>;R:L" + binaryName(Foo.class) + "<TT;>;>Ljava/lang/Object;",
+        iClass.getFinalSignatureAttribute());
+    ClassSubject fooInnerClass = inspector.clazz(Main.class.getTypeName() + "$1");
+    assertThat(fooInnerClass, isPresent());
+    // TODO(b/184927364): Fullmode should completely remove this signature
+    assertEquals(
+        "Ljava/lang/Object;L"
+            + binaryName(I.class)
+            + "<Ljava/lang/String;L"
+            + binaryName(Foo.class)
+            + "<Ljava/lang/String;>;>;",
+        fooInnerClass.getFinalSignatureAttribute());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/Foo.java b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/Foo.java
new file mode 100644
index 0000000..81000d6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/Foo.java
@@ -0,0 +1,19 @@
+// 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.graph.genericsignature.testclasses;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+
+@NeverClassInline
+public class Foo<T extends Comparable<T>> implements J, K<T> {
+
+  @Override
+  @NeverInline
+  public String bar(String t) {
+    System.out.println("Foo::bar");
+    return t;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/I.java b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/I.java
new file mode 100644
index 0000000..089286d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/I.java
@@ -0,0 +1,12 @@
+// 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.graph.genericsignature.testclasses;
+
+import com.android.tools.r8.NeverInline;
+
+public interface I<T extends Comparable<T>, R extends Foo<T>> extends L<R> {
+  @NeverInline
+  T method(T t);
+}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/J.java b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/J.java
new file mode 100644
index 0000000..8deed10
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/J.java
@@ -0,0 +1,10 @@
+// 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.graph.genericsignature.testclasses;
+
+public interface J {
+
+  String bar(String t);
+}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/K.java b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/K.java
new file mode 100644
index 0000000..608c12d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/K.java
@@ -0,0 +1,7 @@
+// 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.graph.genericsignature.testclasses;
+
+public interface K<T> {}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/L.java b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/L.java
new file mode 100644
index 0000000..bf3895b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/L.java
@@ -0,0 +1,7 @@
+// 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.graph.genericsignature.testclasses;
+
+public interface L<T> {}
diff --git a/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/Main.java b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/Main.java
new file mode 100644
index 0000000..ccf9f04
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/genericsignature/testclasses/Main.java
@@ -0,0 +1,39 @@
+// 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.graph.genericsignature.testclasses;
+
+import java.lang.reflect.Type;
+
+public class Main extends Foo<String> implements I<Integer, Foo<Integer>> {
+
+  public static <T extends I<String, Foo<String>>> T test(T t) {
+    for (Type genericInterface : t.getClass().getGenericInterfaces()) {
+      System.out.println(genericInterface);
+    }
+    t.method("Hello world");
+    return t;
+  }
+
+  public static void main(String[] args) {
+    System.out.println(Main.class.getGenericSuperclass());
+    for (Type genericInterface : Main.class.getGenericInterfaces()) {
+      System.out.println(genericInterface);
+    }
+    test(
+        new I<String, Foo<String>>() {
+          @Override
+          public String method(String s) {
+            System.out.println(s);
+            return s;
+          }
+        });
+  }
+
+  @Override
+  public Integer method(Integer integer) {
+    System.out.println("Main::method");
+    return integer;
+  }
+}