blob: da0b781228078a8cd7583d92f0a9685398e5b0d4 [file] [log] [blame]
// Copyright (c) 2019, 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.shaking.annotations;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class ProgramAnnotationRemovalTest extends TestBase {
private final TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
public ProgramAnnotationRemovalTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testCompat() throws Exception {
runTest(true);
}
@Test
public void testNonCompat() throws Exception {
runTest(false);
}
private void runTest(boolean enableCompatMode) throws Exception {
R8TestRunResult result =
testForR8Compat(parameters.getBackend(), enableCompatMode)
.addInnerClasses(ProgramAnnotationRemovalTest.class)
.addKeepMainRule(TestClass.class)
.addKeepRuntimeVisibleAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), TestClass.class);
CodeInspector inspector = result.inspector();
ClassSubject liveAnnotationClassSubject = inspector.clazz(LiveProgramAnnotation.class);
assertThat(liveAnnotationClassSubject, isPresent());
ClassSubject deadAnnotationClassSubject = inspector.clazz(DeadProgramAnnotation.class);
assertThat(deadAnnotationClassSubject, not(isPresent()));
ClassSubject testClassSubject = inspector.clazz(TestClass.class);
assertThat(testClassSubject, isPresent());
MethodSubject methodWithLiveProgramAnnotationSubject =
testClassSubject.uniqueMethodWithName("methodWithLiveProgramAnnotation");
assertThat(methodWithLiveProgramAnnotationSubject, isPresent());
assertEquals(
BooleanUtils.intValue(enableCompatMode),
methodWithLiveProgramAnnotationSubject.getMethod().annotations().size());
MethodSubject methodWithDeadProgramAnnotationSubject =
testClassSubject.uniqueMethodWithName("methodWithDeadProgramAnnotation");
assertThat(methodWithDeadProgramAnnotationSubject, isPresent());
assertEquals(0, methodWithDeadProgramAnnotationSubject.getMethod().annotations().size());
result.applyIf(
enableCompatMode,
r -> r.assertSuccessWithOutputLines("@" + liveAnnotationClassSubject.getFinalName() + "()"),
TestRunResult::assertSuccessWithEmptyOutput);
}
static class TestClass {
public static void main(String[] args) throws Exception {
methodWithLiveProgramAnnotation();
methodWithDeadProgramAnnotation();
// Do something with LiveProgramAnnotation to ensure it becomes live.
if (System.currentTimeMillis() <= 0) {
System.out.println(LiveProgramAnnotation.class);
}
}
@NeverInline
@LiveProgramAnnotation
static void methodWithLiveProgramAnnotation() throws Exception {
Method method = TestClass.class.getDeclaredMethod("methodWithLiveProgramAnnotation");
for (Annotation annotation : method.getDeclaredAnnotations()) {
System.out.println(annotation);
}
}
@NeverInline
@DeadProgramAnnotation
static void methodWithDeadProgramAnnotation() throws Exception {
Method method = TestClass.class.getDeclaredMethod("methodWithDeadProgramAnnotation");
for (Annotation annotation : method.getDeclaredAnnotations()) {
System.out.println(annotation);
}
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface LiveProgramAnnotation {}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface DeadProgramAnnotation {}
}