| // 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.classmerging.horizontal; |
| |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.jar; |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestClassMergingTest; |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostA; |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostA$NestMemberA; |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostA$NestMemberB; |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostB; |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostB$NestMemberA; |
| import static com.android.tools.r8.classmerging.horizontal.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostB$NestMemberB; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assume.assumeTrue; |
| |
| import com.android.tools.r8.R8FullTestBuilder; |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.TestParametersCollection; |
| import com.android.tools.r8.TestRuntime.CfVm; |
| import com.android.tools.r8.ThrowableConsumer; |
| import com.android.tools.r8.examples.JavaExampleClassProxy; |
| import com.android.tools.r8.graph.DexClass; |
| import com.android.tools.r8.references.ClassReference; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Streams; |
| import java.nio.file.Path; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| import org.junit.Test; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| public class NestClassMergingTestRunner extends HorizontalClassMergingTestBase { |
| |
| public static class HorizontalClassMergingTestSources { |
| |
| private static final String EXAMPLE_FILE = "examplesJava11"; |
| |
| public static final JavaExampleClassProxy nestClassMergingTest = |
| new JavaExampleClassProxy(EXAMPLE_FILE, "horizontalclassmerging/NestClassMergingTest"); |
| public static final JavaExampleClassProxy nestHostA = |
| new JavaExampleClassProxy(EXAMPLE_FILE, "horizontalclassmerging/NestHostA"); |
| public static final JavaExampleClassProxy nestHostA$NestMemberA = |
| new JavaExampleClassProxy(EXAMPLE_FILE, "horizontalclassmerging/NestHostA$NestMemberA"); |
| public static final JavaExampleClassProxy nestHostA$NestMemberB = |
| new JavaExampleClassProxy(EXAMPLE_FILE, "horizontalclassmerging/NestHostA$NestMemberB"); |
| public static final JavaExampleClassProxy nestHostB = |
| new JavaExampleClassProxy(EXAMPLE_FILE, "horizontalclassmerging/NestHostB"); |
| public static final JavaExampleClassProxy nestHostB$NestMemberA = |
| new JavaExampleClassProxy(EXAMPLE_FILE, "horizontalclassmerging/NestHostB$NestMemberA"); |
| public static final JavaExampleClassProxy nestHostB$NestMemberB = |
| new JavaExampleClassProxy(EXAMPLE_FILE, "horizontalclassmerging/NestHostB$NestMemberB"); |
| |
| public static Path jar() { |
| return JavaExampleClassProxy.examplesJar(EXAMPLE_FILE + "/horizontalclassmerging"); |
| } |
| } |
| |
| public NestClassMergingTestRunner(TestParameters parameters) { |
| super(parameters); |
| } |
| |
| @Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters() |
| .withCfRuntimesStartingFromIncluding(CfVm.JDK11) |
| .withDexRuntimes() |
| .withAllApiLevels() |
| .build(); |
| } |
| |
| @Test |
| public void test() throws Exception { |
| runTest( |
| builder -> |
| builder |
| .addDontObfuscate() |
| .addHorizontallyMergedClassesInspector( |
| inspector -> { |
| if (parameters.canUseNestBasedAccesses()) { |
| inspector |
| .assertIsCompleteMergeGroup( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberA.getClassReference(), |
| nestHostA$NestMemberB.getClassReference()) |
| .assertIsCompleteMergeGroup( |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberA.getClassReference(), |
| nestHostB$NestMemberB.getClassReference()); |
| } else { |
| inspector.assertIsCompleteMergeGroup( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberA.getClassReference(), |
| nestHostA$NestMemberB.getClassReference(), |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberA.getClassReference(), |
| nestHostB$NestMemberB.getClassReference()); |
| } |
| })); |
| } |
| |
| @Test |
| public void testMergeHostIntoNestMemberA() throws Exception { |
| assumeTrue(parameters.isCfRuntime()); |
| runTest( |
| builder -> |
| builder |
| .addHorizontallyMergedClassesInspector( |
| inspector -> |
| inspector |
| .assertIsCompleteMergeGroup( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberA.getClassReference()) |
| .assertIsCompleteMergeGroup( |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberA.getClassReference()) |
| .assertClassReferencesNotMerged( |
| nestHostA$NestMemberB.getClassReference(), |
| nestHostB$NestMemberB.getClassReference())) |
| .addNoHorizontalClassMergingRule( |
| nestHostA$NestMemberB.getClassReference().getTypeName(), |
| nestHostB$NestMemberB.getClassReference().getTypeName()) |
| .addOptionsModification( |
| options -> { |
| options.testing.horizontalClassMergingTarget = |
| (appView, canditates, target) -> { |
| Set<ClassReference> candidateClassReferences = |
| Streams.stream(canditates) |
| .map(DexClass::getClassReference) |
| .collect(Collectors.toSet()); |
| if (candidateClassReferences.contains(nestHostA.getClassReference())) { |
| assertEquals( |
| ImmutableSet.of( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberA.getClassReference()), |
| candidateClassReferences); |
| } else { |
| assertEquals( |
| ImmutableSet.of( |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberA.getClassReference()), |
| candidateClassReferences); |
| } |
| return Iterables.find( |
| canditates, |
| candidate -> { |
| ClassReference classReference = candidate.getClassReference(); |
| return classReference.equals( |
| nestHostA$NestMemberA.getClassReference()) |
| || classReference.equals( |
| nestHostB$NestMemberA.getClassReference()); |
| }); |
| }; |
| })); |
| } |
| |
| @Test |
| public void testMergeHostIntoNestMemberB() throws Exception { |
| assumeTrue(parameters.isCfRuntime()); |
| runTest( |
| builder -> |
| builder |
| .addHorizontallyMergedClassesInspector( |
| inspector -> |
| inspector |
| .assertIsCompleteMergeGroup( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberB.getClassReference()) |
| .assertIsCompleteMergeGroup( |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberB.getClassReference()) |
| .assertClassReferencesNotMerged( |
| nestHostA$NestMemberA.getClassReference(), |
| nestHostB$NestMemberA.getClassReference())) |
| .addNoHorizontalClassMergingRule( |
| nestHostA$NestMemberA.getClassReference().getTypeName(), |
| nestHostB$NestMemberA.getClassReference().getTypeName()) |
| .addOptionsModification( |
| options -> { |
| options.testing.horizontalClassMergingTarget = |
| (appView, canditates, target) -> { |
| Set<ClassReference> candidateClassReferences = |
| Streams.stream(canditates) |
| .map(DexClass::getClassReference) |
| .collect(Collectors.toSet()); |
| if (candidateClassReferences.contains(nestHostA.getClassReference())) { |
| assertEquals( |
| ImmutableSet.of( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberB.getClassReference()), |
| candidateClassReferences); |
| } else { |
| assertEquals( |
| ImmutableSet.of( |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberB.getClassReference()), |
| candidateClassReferences); |
| } |
| return Iterables.find( |
| canditates, |
| candidate -> { |
| ClassReference classReference = candidate.getClassReference(); |
| return classReference.equals( |
| nestHostA$NestMemberB.getClassReference()) |
| || classReference.equals( |
| nestHostB$NestMemberB.getClassReference()); |
| }); |
| }; |
| })); |
| } |
| |
| @Test |
| public void testMergeMemberAIntoNestHost() throws Exception { |
| assumeTrue(parameters.isCfRuntime()); |
| runTest( |
| builder -> |
| builder |
| .addHorizontallyMergedClassesInspector( |
| inspector -> |
| inspector |
| .assertIsCompleteMergeGroup( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberA.getClassReference()) |
| .assertIsCompleteMergeGroup( |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberA.getClassReference()) |
| .assertClassReferencesNotMerged( |
| nestHostA$NestMemberB.getClassReference(), |
| nestHostB$NestMemberB.getClassReference())) |
| .addNoHorizontalClassMergingRule( |
| nestHostA$NestMemberB.getClassReference().getTypeName(), |
| nestHostB$NestMemberB.getClassReference().getTypeName()) |
| .addOptionsModification( |
| options -> { |
| options.testing.horizontalClassMergingTarget = |
| (appView, canditates, target) -> { |
| Set<ClassReference> candidateClassReferences = |
| Streams.stream(canditates) |
| .map(DexClass::getClassReference) |
| .collect(Collectors.toSet()); |
| if (candidateClassReferences.contains(nestHostA.getClassReference())) { |
| assertEquals( |
| ImmutableSet.of( |
| nestHostA.getClassReference(), |
| nestHostA$NestMemberA.getClassReference()), |
| candidateClassReferences); |
| } else { |
| assertEquals( |
| ImmutableSet.of( |
| nestHostB.getClassReference(), |
| nestHostB$NestMemberA.getClassReference()), |
| candidateClassReferences); |
| } |
| return Iterables.find( |
| canditates, |
| candidate -> { |
| ClassReference classReference = candidate.getClassReference(); |
| return classReference.equals(nestHostA.getClassReference()) |
| || classReference.equals(nestHostB.getClassReference()); |
| }); |
| }; |
| })); |
| } |
| |
| private void runTest(ThrowableConsumer<R8FullTestBuilder> configuration) throws Exception { |
| testForR8(parameters.getBackend()) |
| .addKeepMainRule(nestClassMergingTest.getClassReference()) |
| .addProgramFiles(jar()) |
| .addKeepRules( |
| "-keeppackagenames horizontalclassmerging", |
| "-nomethodstaticizing class * { void privatePrint(...); }") |
| .apply(configuration) |
| .enableInliningAnnotations() |
| .enableNeverClassInliningAnnotations() |
| .setMinApi(parameters) |
| .run(parameters.getRuntime(), nestClassMergingTest.getClassReference().getTypeName()) |
| .assertSuccessWithOutputLines( |
| "NestHostA", |
| "NestHostA$NestMemberA", |
| "NestHostA$NestMemberB", |
| "NestHostB", |
| "NestHostB$NestMemberA", |
| "NestHostB$NestMemberB"); |
| } |
| } |