blob: c14b3573fa5c3bc1860a92b6b023cd52dbe40b1e [file] [log] [blame]
// Copyright (c) 2018, 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.kotlin;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class SimplifyIfNotNullKotlinTest extends AbstractR8KotlinTestBase {
private static final String FOLDER = "non_null";
private static final String STRING = "java.lang.String";
@Parameterized.Parameters(name = "{0}, {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values());
}
public SimplifyIfNotNullKotlinTest(
TestParameters parameters,
KotlinTestParameters kotlinParameters,
boolean allowAccessModification) {
super(parameters, kotlinParameters, allowAccessModification);
}
@Test
public void test_example1() throws Exception {
final TestKotlinClass ex1 = new TestKotlinClass("non_null.Example1Kt");
final MethodSignature testMethodSignature =
new MethodSignature("forMakeAndModel", "java.util.SortedMap",
ImmutableList.of("java.util.Collection", STRING, STRING, "java.lang.Integer"));
final String mainClassName = ex1.getClassName();
final String extraRules =
StringUtils.lines(
neverInlineMethod(mainClassName, testMethodSignature),
// TODO(b/173398086): uniqueMethodWithName() does not work with argument removal.
"-keepclassmembers,allowoptimization,allowshrinking class non_null.Example1Kt {",
" *** forMakeAndModel(...);",
"}");
runTest(
FOLDER,
mainClassName,
testBuilder -> testBuilder.addKeepRules(extraRules).allowAccessModification())
.inspect(
inspector -> {
ClassSubject clazz = checkClassIsKept(inspector, ex1.getClassName());
// Verify forMakeAndModel(...) is present in the input.
checkMethodPresenceInInput(clazz.getOriginalName(), testMethodSignature, true);
// Find forMakeAndModel(...) after parameter removal.
MethodSubject testMethod = clazz.uniqueMethodWithName(testMethodSignature.name);
long ifzCount =
testMethod
.streamInstructions()
.filter(i -> i.isIfEqz() || i.isIfNez() || i.isIfNonNull())
.count();
long paramNullCheckCount =
countCall(testMethod, "Intrinsics", "checkParameterIsNotNull");
// TODO(b/214496607): Should be one after Iterator#hasNext, and another in the filter
// predicate: sinceYear != null.
assertEquals(testParameters.isCfRuntime() ? 5 : 2, ifzCount);
assertEquals(0, paramNullCheckCount);
});
}
@Test
public void test_example2() throws Exception {
final TestKotlinClass ex2 = new TestKotlinClass("non_null.Example2Kt");
final MethodSignature testMethodSignature =
new MethodSignature("aOrDefault", STRING, ImmutableList.of(STRING, STRING));
final String mainClassName = ex2.getClassName();
final String extraRules = neverInlineMethod(mainClassName, testMethodSignature);
runTest(FOLDER, mainClassName, testBuilder -> testBuilder.addKeepRules(extraRules))
.inspect(
inspector -> {
ClassSubject clazz = checkClassIsKept(inspector, ex2.getClassName());
MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature);
long ifzCount =
testMethod
.streamInstructions()
.filter(i -> i.isIfEqz() || i.isIfNez() || i.isIfNull() || i.isIfNonNull())
.count();
long paramNullCheckCount =
countCall(testMethod, "Intrinsics", "checkParameterIsNotNull");
// ?: in aOrDefault
assertEquals(1, ifzCount);
assertEquals(0, paramNullCheckCount);
});
}
@Test
public void test_example3() throws Exception {
final TestKotlinClass ex3 = new TestKotlinClass("non_null.Example3Kt");
final MethodSignature testMethodSignature =
new MethodSignature("neverThrowNPE", "void", ImmutableList.of("non_null.Foo"));
final String mainClassName = ex3.getClassName();
final String extraRules = neverInlineMethod(mainClassName, testMethodSignature);
runTest(FOLDER, mainClassName, testBuilder -> testBuilder.addKeepRules(extraRules))
.inspect(
inspector -> {
ClassSubject clazz = checkClassIsKept(inspector, ex3.getClassName());
MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature);
long ifzCount =
testMethod
.streamInstructions()
.filter(i -> i.isIfEqz() || i.isIfNez() || i.isIfNull() || i.isIfNonNull())
.count();
// !! operator inside explicit null check should be gone.
// One explicit null-check as well as 4 bar? accesses.
assertEquals(5, ifzCount);
});
}
}