| // 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.kotlin; | |
| 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 static org.junit.Assert.assertTrue; | |
| import com.android.tools.r8.KotlinTestParameters; | |
| import com.android.tools.r8.TestParameters; | |
| import com.android.tools.r8.utils.BooleanUtils; | |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; | |
| import com.android.tools.r8.utils.codeinspector.FieldSubject; | |
| import com.android.tools.r8.utils.codeinspector.InstructionSubject; | |
| import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode; | |
| 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; | |
| import org.junit.runners.Parameterized.Parameters; | |
| @RunWith(Parameterized.class) | |
| public class KotlinUnusedSingletonTest extends AbstractR8KotlinTestBase { | |
| @Parameters(name = "{0}, {1}, allowAccessModification: {2}") | |
| public static Collection<Object[]> data() { | |
| return buildParameters( | |
| getTestParameters().withAllRuntimesAndApiLevels().build(), | |
| getKotlinTestParameters().withAllCompilersAndTargetVersions().build(), | |
| BooleanUtils.values()); | |
| } | |
| private static final String printlnSignature = | |
| "void java.io.PrintStream.println(java.lang.Object)"; | |
| public KotlinUnusedSingletonTest( | |
| TestParameters parameters, | |
| KotlinTestParameters kotlinParameters, | |
| boolean allowAccessModification) { | |
| super(parameters, kotlinParameters, allowAccessModification); | |
| } | |
| @Test | |
| public void b110196118() throws Exception { | |
| final String mainClassName = "unused_singleton.MainKt"; | |
| final String moduleName = "unused_singleton.TestModule"; | |
| runTest("unused_singleton", mainClassName) | |
| .inspect( | |
| inspector -> { | |
| ClassSubject main = inspector.clazz(mainClassName); | |
| assertThat(main, isPresent()); | |
| MethodSubject mainMethod = main.mainMethod(); | |
| assertThat(mainMethod, isPresent()); | |
| // The const-string from provideGreeting() has been propagated. | |
| assertTrue( | |
| mainMethod | |
| .iterateInstructions(i -> i.isConstString("Hello", JumboStringMode.ALLOW)) | |
| .hasNext()); | |
| // The method provideGreeting() is no longer being invoked -- i.e., we have been able | |
| // to determine that the class initialization of the enclosing class is trivial. | |
| ClassSubject module = inspector.clazz(moduleName); | |
| // TODO(b/179897889): Should probably check for module being present. | |
| assertThat(main, isPresent()); | |
| assertEquals( | |
| 0, | |
| mainMethod | |
| .streamInstructions() | |
| .filter(InstructionSubject::isInvoke) | |
| .map(i -> i.getMethod().toSourceString()) | |
| .filter( | |
| invokedMethod -> | |
| !invokedMethod.equals(checkParameterIsNotNullSignature) | |
| && !invokedMethod.equals(printlnSignature) | |
| && !invokedMethod.equals( | |
| throwParameterIsNotNullExceptionSignature)) | |
| .count()); | |
| // The field `INSTANCE` has been removed entirely. | |
| FieldSubject instance = module.uniqueFieldWithName("INSTANCE"); | |
| assertThat(instance, not(isPresent())); | |
| // The class initializer is no longer there. | |
| MethodSubject clinit = module.clinit(); | |
| assertThat(clinit, not(isPresent())); | |
| // Also, the instance initializer is no longer there, since it is only reachable from | |
| // the class initializer. | |
| MethodSubject init = module.init(ImmutableList.of()); | |
| assertThat(init, not(isPresent())); | |
| }); | |
| } | |
| } |