blob: 6e0e9e303733b1464976adec69637b9c416f1d1f [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.ir.optimize.reflection;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.StringUtils;
import java.util.concurrent.Callable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class GetClassOnKeptClassTest extends TestBase {
static final String EXPECTED =
StringUtils.lines(
"class " + KeptClass.class.getTypeName(),
"class " + KeptClass.class.getTypeName(),
"class " + UnknownClass.class.getTypeName(),
"class " + UnknownClass.class.getTypeName());
private final TestParameters parameters;
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevels().build();
}
public GetClassOnKeptClassTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testReference() throws Exception {
testForRuntime(parameters)
.addProgramClasses(KeptClass.class, UnknownClass.class, TestClass.class)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.enableInliningAnnotations()
.addProgramClasses(KeptClass.class, TestClass.class)
.addKeepMainRule(TestClass.class)
.addKeepClassRules(KeptClass.class)
.setMinApi(parameters.getApiLevel())
.compile()
.addRunClasspathFiles(buildOnDexRuntime(parameters, UnknownClass.class))
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
static class KeptClass implements Callable<Class<?>> {
@NeverInline
static Class<?> getClassMethod(KeptClass instance) {
// Nullable argument. Should not be rewritten to const-class to preserve NPE.
return instance.getClass();
}
@NeverInline
@Override
public Class<?> call() {
// Non-null `this` pointer.
return getClass();
}
}
static class UnknownClass extends KeptClass {
// Empty subtype of KeptClass.
}
static class TestClass {
static KeptClass getInstance(int i) throws Exception {
return i == 0
? new KeptClass()
: (KeptClass)
Class.forName(TestClass.class.getName().replace("TestClass", "UnknownClass"))
.getDeclaredConstructor()
.newInstance();
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 2; i++) {
KeptClass instance = getInstance(args.length + i);
System.out.println(instance.call());
System.out.println(KeptClass.getClassMethod(instance));
}
}
}
}