blob: f640e6ff007c0d1a675bab6d6d748ef3965fab93 [file] [log] [blame]
// 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 horizontalclassmerging;
import static horizontalclassmerging.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestClassMergingTest;
import static horizontalclassmerging.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostA;
import static horizontalclassmerging.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostA$NestMemberA;
import static horizontalclassmerging.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostA$NestMemberB;
import static horizontalclassmerging.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostB;
import static horizontalclassmerging.NestClassMergingTestRunner.HorizontalClassMergingTestSources.nestHostB$NestMemberA;
import static horizontalclassmerging.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.classmerging.horizontal.HorizontalClassMergingTestBase;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
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 {
public static final Class<?> nestClassMergingTest = NestClassMergingTest.class;
public static final Class<?> nestHostA = NestHostA.class;
public static final Class<?> nestHostA$NestMemberA = NestHostA.NestMemberA.class;
public static final Class<?> nestHostA$NestMemberB = NestHostA.NestMemberB.class;
public static final Class<?> nestHostB = NestHostB.class;
public static final Class<?> nestHostB$NestMemberA = NestHostB.NestMemberA.class;
public static final Class<?> nestHostB$NestMemberB = NestHostB.NestMemberB.class;
}
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, nestHostA$NestMemberA, nestHostA$NestMemberB)
.assertIsCompleteMergeGroup(
nestHostB, nestHostB$NestMemberA, nestHostB$NestMemberB);
} else {
inspector.assertIsCompleteMergeGroup(
nestHostA,
nestHostA$NestMemberA,
nestHostA$NestMemberB,
nestHostB,
nestHostB$NestMemberA,
nestHostB$NestMemberB);
}
}));
}
@Test
public void testMergeHostIntoNestMemberA() throws Exception {
assumeTrue(parameters.isCfRuntime());
runTest(
builder ->
builder
.addHorizontallyMergedClassesInspector(
inspector ->
inspector
.assertIsCompleteMergeGroup(nestHostA, nestHostA$NestMemberA)
.assertIsCompleteMergeGroup(nestHostB, nestHostB$NestMemberA)
.assertClassReferencesNotMerged(
Reference.classFromClass(nestHostA$NestMemberB),
Reference.classFromClass(nestHostB$NestMemberB)))
.addNoHorizontalClassMergingRule(
nestHostA$NestMemberB.getTypeName(), nestHostB$NestMemberB.getTypeName())
.addOptionsModification(
options -> {
options.testing.horizontalClassMergingTarget =
(appView, canditates, target) -> {
Set<ClassReference> candidateClassReferences =
Streams.stream(canditates)
.map(DexClass::getClassReference)
.collect(Collectors.toSet());
if (candidateClassReferences.contains(
Reference.classFromClass(nestHostA))) {
assertEquals(
ImmutableSet.of(
Reference.classFromClass(nestHostA),
Reference.classFromClass(nestHostA$NestMemberA)),
candidateClassReferences);
} else {
assertEquals(
ImmutableSet.of(
Reference.classFromClass(nestHostB),
Reference.classFromClass(nestHostB$NestMemberA)),
candidateClassReferences);
}
return Iterables.find(
canditates,
candidate -> {
ClassReference classReference = candidate.getClassReference();
return classReference.equals(
Reference.classFromClass(nestHostA$NestMemberA))
|| classReference.equals(
Reference.classFromClass(nestHostB$NestMemberA));
});
};
}));
}
@Test
public void testMergeHostIntoNestMemberB() throws Exception {
assumeTrue(parameters.isCfRuntime());
runTest(
builder ->
builder
.addHorizontallyMergedClassesInspector(
inspector ->
inspector
.assertIsCompleteMergeGroup(nestHostA, nestHostA$NestMemberB)
.assertIsCompleteMergeGroup(nestHostB, nestHostB$NestMemberB)
.assertClassReferencesNotMerged(
Reference.classFromClass(nestHostA$NestMemberA),
Reference.classFromClass(nestHostB$NestMemberA)))
.addNoHorizontalClassMergingRule(
nestHostA$NestMemberA.getTypeName(), nestHostB$NestMemberA.getTypeName())
.addOptionsModification(
options -> {
options.testing.horizontalClassMergingTarget =
(appView, canditates, target) -> {
Set<ClassReference> candidateClassReferences =
Streams.stream(canditates)
.map(DexClass::getClassReference)
.collect(Collectors.toSet());
if (candidateClassReferences.contains(
Reference.classFromClass(nestHostA))) {
assertEquals(
ImmutableSet.of(
Reference.classFromClass(nestHostA),
Reference.classFromClass(nestHostA$NestMemberB)),
candidateClassReferences);
} else {
assertEquals(
ImmutableSet.of(
Reference.classFromClass(nestHostB),
Reference.classFromClass(nestHostB$NestMemberB)),
candidateClassReferences);
}
return Iterables.find(
canditates,
candidate -> {
ClassReference classReference = candidate.getClassReference();
return classReference.equals(
Reference.classFromClass(nestHostA$NestMemberB))
|| classReference.equals(
Reference.classFromClass(nestHostB$NestMemberB));
});
};
}));
}
@Test
public void testMergeMemberAIntoNestHost() throws Exception {
assumeTrue(parameters.isCfRuntime());
runTest(
builder ->
builder
.addHorizontallyMergedClassesInspector(
inspector ->
inspector
.assertIsCompleteMergeGroup(nestHostA, nestHostA$NestMemberA)
.assertIsCompleteMergeGroup(nestHostB, nestHostB$NestMemberA)
.assertClassReferencesNotMerged(
Reference.classFromClass(nestHostA$NestMemberB),
Reference.classFromClass(nestHostB$NestMemberB)))
.addNoHorizontalClassMergingRule(
nestHostA$NestMemberB.getTypeName(), nestHostB$NestMemberB.getTypeName())
.addOptionsModification(
options -> {
options.testing.horizontalClassMergingTarget =
(appView, canditates, target) -> {
Set<ClassReference> candidateClassReferences =
Streams.stream(canditates)
.map(DexClass::getClassReference)
.collect(Collectors.toSet());
if (candidateClassReferences.contains(
Reference.classFromClass(nestHostA))) {
assertEquals(
ImmutableSet.of(
Reference.classFromClass(nestHostA),
Reference.classFromClass(nestHostA$NestMemberA)),
candidateClassReferences);
} else {
assertEquals(
ImmutableSet.of(
Reference.classFromClass(nestHostB),
Reference.classFromClass(nestHostB$NestMemberA)),
candidateClassReferences);
}
return Iterables.find(
canditates,
candidate -> {
ClassReference classReference = candidate.getClassReference();
return classReference.equals(Reference.classFromClass(nestHostA))
|| classReference.equals(Reference.classFromClass(nestHostB));
});
};
}));
}
private void runTest(ThrowableConsumer<R8FullTestBuilder> configuration) throws Exception {
testForR8(parameters.getBackend())
.addKeepMainRule(nestClassMergingTest)
.addProgramClassesAndInnerClasses(
NestClassMergingTest.class, NestHostB.class, NestHostA.class)
.addKeepRules(
"-keeppackagenames horizontalclassmerging",
"-nomethodstaticizing class * { void privatePrint(...); }")
.apply(configuration)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters)
.run(parameters.getRuntime(), nestClassMergingTest.getTypeName())
.assertSuccessWithOutputLines(
"NestHostA",
"NestHostA$NestMemberA",
"NestHostA$NestMemberB",
"NestHostB",
"NestHostB$NestMemberA",
"NestHostB$NestMemberB");
}
}