| // 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.cf.bootstrap; | |
| import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; | |
| import static org.junit.Assert.assertTrue; | |
| import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler; | |
| import com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion; | |
| import com.android.tools.r8.KotlinTestParameters; | |
| import com.android.tools.r8.TestParameters; | |
| import com.android.tools.r8.ToolHelper; | |
| import com.android.tools.r8.internal.CompilationTestBase; | |
| import com.android.tools.r8.utils.AndroidApp; | |
| import com.android.tools.r8.utils.DescriptorUtils; | |
| import com.google.common.collect.ImmutableList; | |
| import java.nio.file.Files; | |
| import java.nio.file.Path; | |
| import java.nio.file.Paths; | |
| import java.util.List; | |
| import org.junit.Ignore; | |
| 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 KotlinCompilerTreeShakingTest extends CompilationTestBase { | |
| private static final String PKG_NAME = KotlinCompilerTreeShakingTest.class.getPackage().getName(); | |
| private static final Path HELLO_KT = | |
| Paths.get( | |
| ToolHelper.TESTS_DIR, | |
| "java", | |
| DescriptorUtils.getBinaryNameFromJavaType(PKG_NAME), | |
| "Hello.kt"); | |
| private static final int MAX_SIZE = (int) (31361268 * 0.4); | |
| private final TestParameters parameters; | |
| private final KotlinTestParameters kotlinTestParameters; | |
| @Parameters(name = "{0}, kotlinc: {1}") | |
| public static List<Object[]> data() { | |
| return buildParameters( | |
| getTestParameters().withCfRuntimes().build(), | |
| getKotlinTestParameters().withAllCompilersAndTargetVersions().build()); | |
| } | |
| public KotlinCompilerTreeShakingTest( | |
| TestParameters parameters, KotlinTestParameters kotlinTestParameters) { | |
| this.parameters = parameters; | |
| this.kotlinTestParameters = kotlinTestParameters; | |
| } | |
| @Test | |
| public void testForRuntime() throws Exception { | |
| // Compile Hello.kt and make sure it works as expected. | |
| Path classPathBefore = | |
| kotlinc( | |
| parameters.getRuntime().asCf(), | |
| kotlinTestParameters.getCompiler(), | |
| kotlinTestParameters.getTargetVersion()) | |
| .addSourceFiles(HELLO_KT) | |
| .setOutputPath(temp.newFolder().toPath()) | |
| .compile(); | |
| testForJvm() | |
| .addRunClasspathFiles(kotlinTestParameters.getCompiler().getKotlinStdlibJar()) | |
| .addClasspath(classPathBefore) | |
| .run(parameters.getRuntime(), PKG_NAME + ".HelloKt") | |
| .assertSuccessWithOutputLines("I'm Woody. Howdy, howdy, howdy."); | |
| } | |
| @Ignore( | |
| "b/136457753: assertion error in static class merger; " | |
| + "b/144877828: assertion error in method naming state during interface method renaming; " | |
| + "b/144859533: umbrella" | |
| ) | |
| @Test | |
| public void test() throws Exception { | |
| KotlinCompiler kotlinc = kotlinTestParameters.getCompiler(); | |
| List<Path> libs = | |
| ImmutableList.of( | |
| kotlinc.getKotlinStdlibJar(), | |
| kotlinc.getKotlinReflectJar(), | |
| kotlinc.getKotlinScriptRuntime()); | |
| // Process kotlin-compiler.jar. | |
| Path r8ProcessedKotlinc = | |
| testForR8(parameters.getBackend()) | |
| .addLibraryFiles(libs) | |
| .addLibraryFiles(ToolHelper.getJava8RuntimeJar()) | |
| .addProgramFiles(kotlinc.getCompiler()) | |
| .addKeepAttributes("*Annotation*") | |
| .addKeepClassAndMembersRules(ToolHelper.K2JVMCompiler) | |
| .addKeepClassAndMembersRules("**.K2JVMCompilerArguments") | |
| .addKeepClassAndMembersRules("**.*Argument*") | |
| .addKeepClassAndMembersRules("**.Freezable") | |
| .addKeepRules( | |
| "-keepclassmembers class * {", " *** parseCommandLineArguments(...);", "}") | |
| .addKeepRules( | |
| "-keepclassmembers,allowoptimization enum * {", | |
| " public static **[] values();", | |
| " public static ** valueOf(java.lang.String);", | |
| "}") | |
| .addOptionsModification( | |
| o -> { | |
| // Ignore com.sun.tools.javac.main.JavaCompiler and others | |
| // Resulting jar may not be able to deal with .java source files, though. | |
| o.ignoreMissingClasses = true; | |
| // b/144861100: invoke-static on interface is allowed up to JDK 8. | |
| o.testing.allowInvokeErrors = true; | |
| }) | |
| .compile() | |
| .writeToZip(); | |
| // Copy libraries used by kotlin-compiler.jar so that Preloader can load them. | |
| Path dir = r8ProcessedKotlinc.getParent(); | |
| for (Path lib : libs) { | |
| Path newLib = dir.resolve(lib.getFileName()); | |
| Files.copy(lib, newLib, REPLACE_EXISTING); | |
| } | |
| // TODO(b/144859533): passing `dir` as -kotlin-home. | |
| // Compile Hello.kt again with r8-processed kotlin-compiler.jar | |
| Path classPathAfter = | |
| kotlinc( | |
| parameters.getRuntime().asCf(), | |
| new KotlinCompiler( | |
| "r8ProcessedKotlinc", r8ProcessedKotlinc, kotlinc.getCompilerVersion()), | |
| KotlinTargetVersion.JAVA_8) | |
| .addSourceFiles(HELLO_KT) | |
| .setOutputPath(temp.newFolder().toPath()) | |
| .compile(); | |
| testForJvm() | |
| .addRunClasspathFiles(kotlinc.getKotlinStdlibJar()) | |
| .addClasspath(classPathAfter) | |
| .run(parameters.getRuntime(), PKG_NAME + ".HelloKt") | |
| .assertSuccessWithOutputLines("I'm Woody. Howdy, howdy, howdy."); | |
| int size = AndroidApp.builder().addProgramFile(r8ProcessedKotlinc).build().applicationSize(); | |
| assertTrue(size <= MAX_SIZE); | |
| } | |
| } |