blob: 7a5300d68ab95a9b4243b11a2af5fc19094cd562 [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.rewrite.enums;
import static junit.framework.TestCase.assertTrue;
import com.android.tools.r8.NeverClassInline;
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.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
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 EnumValuesLengthTest extends TestBase {
private final TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
public EnumValuesLengthTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testValuesLengthRemoved() throws Exception {
testForR8(parameters.getBackend())
.addKeepMainRule(Main.class)
.addInnerClasses(EnumValuesLengthTest.class)
.noMinification()
.setMinApi(parameters.getApiLevel())
.addOptionsModification(
opt -> {
opt.enableEnumValueOptimization = true;
// We need to keep the switch map to ensure kept switch maps have their
// values array length rewritten.
opt.enableEnumSwitchMapRemoval = false;
})
.compile()
.inspect(this::assertValuesLengthRemoved)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("0", "2", "5", "a", "D", "c", "D");
}
@Test
public void testValuesLengthSwitchMapRemoved() throws Exception {
// Make sure SwitchMap can still be removed with valuesLength optimization.
testForR8(parameters.getBackend())
.addKeepMainRule(Main.class)
.addInnerClasses(EnumValuesLengthTest.class)
.noMinification()
.setMinApi(parameters.getApiLevel())
.addOptionsModification(
opt -> {
opt.enableEnumValueOptimization = true;
})
.compile()
.inspect(this::assertSwitchMapRemoved)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("0", "2", "5", "a", "D", "c", "D");
}
private void assertSwitchMapRemoved(CodeInspector inspector) {
assertTrue(
inspector.allClasses().stream()
.noneMatch(c -> !c.getDexClass().isEnum() && !c.getFinalName().endsWith("Main")));
}
private void assertValuesLengthRemoved(CodeInspector inspector) {
for (FoundClassSubject clazz : inspector.allClasses()) {
clazz.forAllMethods(this::assertValuesLengthRemoved);
}
}
private void assertValuesLengthRemoved(FoundMethodSubject method) {
assertTrue(method.streamInstructions().noneMatch(InstructionSubject::isArrayLength));
assertTrue(
method
.streamInstructions()
.noneMatch(
instr ->
instr.isInvokeStatic() && instr.getMethod().name.toString().equals("values")));
}
public static class Main {
@NeverClassInline
enum E0 {}
@NeverClassInline
enum E2 {
A,
B
}
@NeverClassInline
enum E5 {
A,
B,
C,
D,
E
}
@NeverClassInline
enum EUnusedValues {
A,
B,
C
}
@NeverClassInline
enum ESwitch {
A,
B,
C,
D
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static void main(String[] args) {
EUnusedValues.values();
System.out.println(E0.values().length);
System.out.println(E2.values().length);
System.out.println(E5.values().length);
System.out.println(switchOn(ESwitch.A));
System.out.println(switchOn(ESwitch.B));
System.out.println(switchOn(ESwitch.C));
System.out.println(switchOn(ESwitch.D));
}
// SwitchMaps feature an array length on values, and some of them are not removed.
@NeverInline
static char switchOn(ESwitch e) {
switch (e) {
case A:
return 'a';
case C:
return 'c';
default:
return 'D';
}
}
}
}