blob: 37f1987506825dd890095b7ef9ad92c55ccb8bad [file] [log] [blame]
// Copyright (c) 2024, 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.horizontalclassmerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.horizontalclassmerging.ConditionalMethodRulesAndHorizontalMergingTest.Example1.BaseClass;
import com.android.tools.r8.horizontalclassmerging.ConditionalMethodRulesAndHorizontalMergingTest.Example1.MyHiddenMethodCaller;
import com.android.tools.r8.horizontalclassmerging.ConditionalMethodRulesAndHorizontalMergingTest.Example2.MyFieldValuePrinter;
import com.android.tools.r8.horizontalclassmerging.ConditionalMethodRulesAndHorizontalMergingTest.Example2.PrintableFieldInterface;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.lang.reflect.Field;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class ConditionalMethodRulesAndHorizontalMergingTest extends TestBase {
static final String EXPECTED =
StringUtils.lines("on Base", "on Sub", "intField = 42", "stringField = Hello!");
private final TestParameters parameters;
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
}
public ConditionalMethodRulesAndHorizontalMergingTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testReference() throws Exception {
testForRuntime(parameters)
.addProgramClasses(TestClass.class)
.addProgramClassesAndInnerClasses(getExampleClasses())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addKeepMainRule(TestClass.class)
// The following rules are what was generated by the keepanno extraction for the doc tests.
.addKeepRules(
"-if class " + typeName(MyHiddenMethodCaller.class) + " {",
" void callHiddenMethod(" + typeName(BaseClass.class) + ");",
"}",
"-keepclassmembers class * extends " + typeName(BaseClass.class) + " {",
" *** hiddenMethod();",
"}",
"-if class " + typeName(MyHiddenMethodCaller.class) + " {",
" void callHiddenMethod(" + typeName(BaseClass.class) + ");",
"}",
"-keepclassmembers class " + typeName(BaseClass.class) + " {",
" *** hiddenMethod();",
"}",
"-if class " + typeName(MyFieldValuePrinter.class) + " {",
" void printFieldValues(" + typeName(PrintableFieldInterface.class) + ");",
"}",
"-keepclassmembers class * extends " + typeName(PrintableFieldInterface.class) + " {",
" *** *;",
"}"
// Removed the rule variant on the base interface as it does not have fields.
)
.addProgramClasses(TestClass.class)
.addProgramClassesAndInnerClasses(getExampleClasses())
.setMinApi(parameters)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
public List<Class<?>> getExampleClasses() {
return ImmutableList.of(Example1.class, Example2.class);
}
static class TestClass {
public static void main(String[] args) throws Exception {
Example1.run();
Example2.run();
}
}
static class Example1 {
static class BaseClass {
void hiddenMethod() {
System.out.println("on Base");
}
}
static class SubClass extends BaseClass {
void hiddenMethod() {
System.out.println("on Sub");
}
}
public static class MyHiddenMethodCaller {
public void callHiddenMethod(BaseClass base) throws Exception {
base.getClass().getDeclaredMethod("hiddenMethod").invoke(base);
}
}
static void run() throws Exception {
new MyHiddenMethodCaller().callHiddenMethod(new BaseClass());
new MyHiddenMethodCaller().callHiddenMethod(new SubClass());
}
}
static class Example2 {
interface PrintableFieldInterface {}
static class ClassWithFields implements PrintableFieldInterface {
final int intField = 42;
String stringField = "Hello!";
}
public static class MyFieldValuePrinter {
public void printFieldValues(PrintableFieldInterface objectWithFields) throws Exception {
for (Field field : objectWithFields.getClass().getDeclaredFields()) {
System.out.println(field.getName() + " = " + field.get(objectWithFields));
}
}
}
static void run() throws Exception {
new MyFieldValuePrinter().printFieldValues(new ClassWithFields());
}
}
}