blob: 1578c3467c460e9e87b1326bfd298b453ae1c468 [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 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");
}
}