From 0cdfe89a26e16a44c93219ee666d2d4c7f98456d Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Thu, 29 Aug 2019 16:59:42 +0200 Subject: [PATCH] KT-33052: Fix KAPT stub generation for enums on JDK11 When using JDK11, generating stubs for enums is broken. This commit handles the faulty generation by JDK11 by fully printing enums in custom implementation of tree printing. Test: added JDK11 tests for KAPT stub generation --- .../kotlin/test/KotlinTestUtils.java | 9 +++++++++ .../kotlin/kapt3/base/util/java9Utils.kt | 10 ++++++++++ .../jetbrains/kotlin/kapt3/Kapt3Extension.kt | 10 +++++++++- .../kapt3/test/AbstractKotlinKapt3Test.kt | 3 ++- .../kapt3/test/KotlinKapt3IntegrationTests.kt | 2 +- .../kotlin/kapt3/test/java9TestUtils.kt | 19 ++++++++++++++----- 6 files changed, 45 insertions(+), 8 deletions(-) diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java index ff69ad0e316..203468b2f18 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/KotlinTestUtils.java @@ -605,6 +605,15 @@ public class KotlinTestUtils { return new File(jdk9); } + @NotNull + public static File getJdk11Home() { + String jdk11 = System.getenv("JDK_11"); + if (jdk11 == null) { + throw new AssertionError("Environment variable JDK_11 is not set!"); + } + return new File(jdk11); + } + public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException { List roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration()); if (roots.isEmpty()) return; diff --git a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/util/java9Utils.kt b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/util/java9Utils.kt index 7ec4ca1baad..f7e9d8991bb 100644 --- a/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/util/java9Utils.kt +++ b/plugins/kapt3/kapt3-base/src/org/jetbrains/kotlin/kapt3/base/util/java9Utils.kt @@ -24,6 +24,16 @@ import com.sun.tools.javac.util.List as JavacList import org.jetbrains.kotlin.kapt3.base.plus fun isJava9OrLater(): Boolean = !System.getProperty("java.version").startsWith("1.") +fun isJava11OrLater(): Boolean { + val majorVersion = System.getProperty("java.version").substringBefore(".", "") + if (majorVersion.isEmpty()) return false + + return try { + majorVersion.toInt() >= 11 + } catch (ignored: Throwable) { + false + } +} fun Options.putJavacOption(jdk8Name: String, jdk9Name: String, value: String) { val option = if (isJava9OrLater()) { diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt index 41273dd0ede..397f6effdfb 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/Kapt3Extension.kt @@ -50,6 +50,7 @@ import org.jetbrains.kotlin.kapt3.base.stubs.KaptStubLineInformation.Companion.K import org.jetbrains.kotlin.kapt3.base.util.KaptBaseError import org.jetbrains.kotlin.kapt3.base.util.getPackageNameJava9Aware import org.jetbrains.kotlin.kapt3.base.util.info +import org.jetbrains.kotlin.kapt3.base.util.isJava11OrLater import org.jetbrains.kotlin.kapt3.diagnostic.KaptError import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter.KaptStub @@ -358,8 +359,15 @@ private class PrettyWithWorkarounds(private val context: Context, val out: Write if ((tree.mods.flags and ENUM) != 0L) { // Pretty does not print annotations for enum values for some reason printExpr(TreeMaker.instance(context).Modifiers(0, tree.mods.annotations)) - } + if (isJava11OrLater()) { + // Print enums fully, there is an issue when using Pretty in JDK 11. + // See https://youtrack.jetbrains.com/issue/KT-33052. + print("/*public static final*/ ${tree.name}") + tree.init?.let { print(" /* = $it */") } + return + } + } super.visitVarDef(tree) } } diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index 64c7c297a3d..76d1beede6b 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -219,7 +219,7 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() { wholeFile: File) } -open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(), Java9TestLauncher { +open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(), CustomJdkTestLauncher { companion object { private val KOTLIN_METADATA_GROUP = "[a-z0-9]+ = (\\{.+?\\}|[0-9]+)" private val KOTLIN_METADATA_REGEX = "@kotlin\\.Metadata\\(($KOTLIN_METADATA_GROUP)(, $KOTLIN_METADATA_GROUP)*\\)".toRegex() @@ -261,6 +261,7 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test( super.doTest(filePath) doTestWithJdk9(AbstractClassFileToSourceStubConverterTest::class.java, filePath) + doTestWithJdk11(AbstractClassFileToSourceStubConverterTest::class.java, filePath) } override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List, txtFile: File, wholeFile: File) { diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt index 296e7a03162..93138f2e5b1 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/KotlinKapt3IntegrationTests.kt @@ -30,7 +30,7 @@ import javax.lang.model.element.ExecutableElement import javax.lang.model.element.TypeElement import kotlin.system.exitProcess -class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9TestLauncher { +class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), CustomJdkTestLauncher { override fun test( name: String, vararg supportedAnnotations: String, diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/java9TestUtils.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/java9TestUtils.kt index cf6d699de63..9b4909f59de 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/java9TestUtils.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/java9TestUtils.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.kapt3.test import com.intellij.openapi.application.PathManager import com.intellij.openapi.util.SystemInfoRt +import org.jetbrains.kotlin.kapt3.base.util.isJava11OrLater import org.jetbrains.kotlin.kapt3.base.util.isJava9OrLater import org.jetbrains.kotlin.test.KotlinTestUtils import java.io.File @@ -25,17 +26,25 @@ import java.net.URL import java.net.URLClassLoader import java.util.concurrent.TimeUnit -interface Java9TestLauncher { +interface CustomJdkTestLauncher { fun doTestWithJdk9(mainClass: Class<*>, arg: String) { // Already under Java 9 if (isJava9OrLater()) return + doTestCustomJdk(mainClass, arg, KotlinTestUtils.getJdk9Home()) + } + + fun doTestWithJdk11(mainClass: Class<*>, arg: String) { + if (isJava9OrLater()) return + doTestCustomJdk(mainClass, arg, KotlinTestUtils.getJdk11Home()) + } + + private fun doTestCustomJdk(mainClass: Class<*>, arg: String, javaHome: File) { //TODO unmute after investigation (tests are failing on TeamCity) if (SystemInfoRt.isWindows) return - val jdk9Home = KotlinTestUtils.getJdk9Home() - val javaExe = File(jdk9Home, "bin/java.exe").takeIf { it.exists() } ?: File(jdk9Home, "bin/java") - assert(javaExe.exists()) { "Can't find 'java' executable in $jdk9Home" } + val javaExe = File(javaHome, "bin/java.exe").takeIf { it.exists() } ?: File(javaHome, "bin/java") + assert(javaExe.exists()) { "Can't find 'java' executable in $javaHome" } val currentJavaHome = System.getProperty("java.home") @@ -60,7 +69,7 @@ interface Java9TestLauncher { process.waitFor(3, TimeUnit.MINUTES) if (process.exitValue() != 0) { - throw AssertionError("Java 9 test process exited with exit code ${process.exitValue()} \n") + throw AssertionError("Java $javaHome test process exited with exit code ${process.exitValue()} \n") } }