| // 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.ToolHelper.KotlinTargetVersion; | |
| import com.android.tools.r8.naming.MemberNaming.MethodSignature; | |
| import com.android.tools.r8.utils.InternalOptions; | |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; | |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; | |
| import com.android.tools.r8.utils.codeinspector.InstructionSubject; | |
| import com.android.tools.r8.utils.codeinspector.MethodSubject; | |
| import com.google.common.collect.ImmutableList; | |
| import org.junit.Test; | |
| public class SimplifyIfNotNullKotlinTest extends AbstractR8KotlinTestBase { | |
| private static final String FOLDER = "non_null"; | |
| private static final String STRING = "java.lang.String"; | |
| public SimplifyIfNotNullKotlinTest( | |
| KotlinTargetVersion targetVersion, boolean allowAccessModification) { | |
| super(targetVersion, 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 = | |
| keepMainMethod(mainClassName) + neverInlineMethod(mainClassName, testMethodSignature); | |
| runTest(FOLDER, mainClassName, extraRules, | |
| InternalOptions::enableCallSiteOptimizationInfoPropagation, | |
| app -> { | |
| CodeInspector codeInspector = new CodeInspector(app); | |
| ClassSubject clazz = checkClassIsKept(codeInspector, ex1.getClassName()); | |
| MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature); | |
| long ifzCount = | |
| testMethod.streamInstructions().filter(i -> i.isIfEqz() || i.isIfNez()).count(); | |
| long paramNullCheckCount = | |
| countCall(testMethod, "ArrayIteratorKt", "checkParameterIsNotNull"); | |
| // One after Iterator#hasNext, and another in the filter predicate: sinceYear != null. | |
| assertEquals(2, ifzCount); | |
| assertEquals(allowAccessModification ? 0 : 5, 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 = | |
| keepMainMethod(mainClassName) + neverInlineMethod(mainClassName, testMethodSignature); | |
| runTest(FOLDER, mainClassName, extraRules, | |
| InternalOptions::enableCallSiteOptimizationInfoPropagation, | |
| app -> { | |
| CodeInspector codeInspector = new CodeInspector(app); | |
| ClassSubject clazz = checkClassIsKept(codeInspector, ex2.getClassName()); | |
| MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature); | |
| long ifzCount = testMethod.streamInstructions().filter(InstructionSubject::isIfEqz).count(); | |
| long paramNullCheckCount = | |
| countCall(testMethod, "Intrinsics", "checkParameterIsNotNull"); | |
| // ?: in aOrDefault | |
| assertEquals(1, ifzCount); | |
| assertEquals(allowAccessModification ? 0 : 1, 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 = | |
| keepMainMethod(mainClassName) + neverInlineMethod(mainClassName, testMethodSignature); | |
| runTest(FOLDER, mainClassName, extraRules, | |
| InternalOptions::enableCallSiteOptimizationInfoPropagation, | |
| app -> { | |
| CodeInspector codeInspector = new CodeInspector(app); | |
| ClassSubject clazz = checkClassIsKept(codeInspector, ex3.getClassName()); | |
| MethodSubject testMethod = checkMethodIsKept(clazz, testMethodSignature); | |
| long ifzCount = testMethod.streamInstructions().filter(InstructionSubject::isIfEqz).count(); | |
| // !! operator inside explicit null check should be gone. | |
| // One explicit null-check as well as 4 bar? accesses. | |
| assertEquals(5, ifzCount); | |
| }); | |
| } | |
| } |