| // 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 String[] EXPECTED_FULL_MODE = |
| new String[] { |
| "class " + Foo.class.getTypeName(), |
| "interface " + I.class.getTypeName(), |
| "interface " + I.class.getTypeName(), |
| "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() |
| .compile() |
| .inspect(this::inspectSignatures) |
| .run(parameters.getRuntime(), Main.class) |
| .assertSuccessWithOutputLines(isCompat ? EXPECTED : EXPECTED_FULL_MODE); |
| } |
| |
| private void inspectSignatures(CodeInspector inspector) { |
| ClassSubject fooClass = inspector.clazz(Foo.class); |
| assertThat(fooClass, isPresent()); |
| assertEquals( |
| isCompat ? "<T::Ljava/lang/Comparable<TT;>;>Ljava/lang/Object;" : null, |
| fooClass.getFinalSignatureAttribute()); |
| ClassSubject iClass = inspector.clazz(I.class); |
| assertThat(iClass, isPresent()); |
| assertEquals( |
| isCompat |
| ? "<T::Ljava/lang/Comparable<TT;>;R:L" |
| + binaryName(Foo.class) |
| + "<TT;>;>Ljava/lang/Object;" |
| : null, |
| iClass.getFinalSignatureAttribute()); |
| ClassSubject fooInnerClass = inspector.clazz(Main.class.getTypeName() + "$1"); |
| assertThat(fooInnerClass, isPresent()); |
| assertEquals( |
| isCompat |
| ? "Ljava/lang/Object;L" |
| + binaryName(I.class) |
| + "<Ljava/lang/String;L" |
| + binaryName(Foo.class) |
| + "<Ljava/lang/String;>;>;" |
| : null, |
| fooInnerClass.getFinalSignatureAttribute()); |
| } |
| } |