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
This commit is contained in:
Ivan Gavrilovic
2019-08-29 16:59:42 +02:00
committed by Yan Zhulanow
parent 58efa34a33
commit 0cdfe89a26
6 changed files with 45 additions and 8 deletions
@@ -605,6 +605,15 @@ public class KotlinTestUtils {
return new File(jdk9); 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 { public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration()); List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
if (roots.isEmpty()) return; if (roots.isEmpty()) return;
@@ -24,6 +24,16 @@ import com.sun.tools.javac.util.List as JavacList
import org.jetbrains.kotlin.kapt3.base.plus import org.jetbrains.kotlin.kapt3.base.plus
fun isJava9OrLater(): Boolean = !System.getProperty("java.version").startsWith("1.") 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) { fun Options.putJavacOption(jdk8Name: String, jdk9Name: String, value: String) {
val option = if (isJava9OrLater()) { val option = if (isJava9OrLater()) {
@@ -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.KaptBaseError
import org.jetbrains.kotlin.kapt3.base.util.getPackageNameJava9Aware import org.jetbrains.kotlin.kapt3.base.util.getPackageNameJava9Aware
import org.jetbrains.kotlin.kapt3.base.util.info 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.diagnostic.KaptError
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter
import org.jetbrains.kotlin.kapt3.stubs.ClassFileToSourceStubConverter.KaptStub 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) { if ((tree.mods.flags and ENUM) != 0L) {
// Pretty does not print annotations for enum values for some reason // Pretty does not print annotations for enum values for some reason
printExpr(TreeMaker.instance(context).Modifiers(0, tree.mods.annotations)) 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) super.visitVarDef(tree)
} }
} }
@@ -219,7 +219,7 @@ abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
wholeFile: File) wholeFile: File)
} }
open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(), Java9TestLauncher { open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test(), CustomJdkTestLauncher {
companion object { companion object {
private val KOTLIN_METADATA_GROUP = "[a-z0-9]+ = (\\{.+?\\}|[0-9]+)" private val KOTLIN_METADATA_GROUP = "[a-z0-9]+ = (\\{.+?\\}|[0-9]+)"
private val KOTLIN_METADATA_REGEX = "@kotlin\\.Metadata\\(($KOTLIN_METADATA_GROUP)(, $KOTLIN_METADATA_GROUP)*\\)".toRegex() 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) super.doTest(filePath)
doTestWithJdk9(AbstractClassFileToSourceStubConverterTest::class.java, filePath) doTestWithJdk9(AbstractClassFileToSourceStubConverterTest::class.java, filePath)
doTestWithJdk11(AbstractClassFileToSourceStubConverterTest::class.java, filePath)
} }
override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List<File>, txtFile: File, wholeFile: File) { override fun check(kaptContext: KaptContextForStubGeneration, javaFiles: List<File>, txtFile: File, wholeFile: File) {
@@ -30,7 +30,7 @@ import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.TypeElement import javax.lang.model.element.TypeElement
import kotlin.system.exitProcess import kotlin.system.exitProcess
class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), Java9TestLauncher { class KotlinKapt3IntegrationTests : AbstractKotlinKapt3IntegrationTest(), CustomJdkTestLauncher {
override fun test( override fun test(
name: String, name: String,
vararg supportedAnnotations: String, vararg supportedAnnotations: String,
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.kapt3.test
import com.intellij.openapi.application.PathManager import com.intellij.openapi.application.PathManager
import com.intellij.openapi.util.SystemInfoRt 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.kapt3.base.util.isJava9OrLater
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File import java.io.File
@@ -25,17 +26,25 @@ import java.net.URL
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
interface Java9TestLauncher { interface CustomJdkTestLauncher {
fun doTestWithJdk9(mainClass: Class<*>, arg: String) { fun doTestWithJdk9(mainClass: Class<*>, arg: String) {
// Already under Java 9 // Already under Java 9
if (isJava9OrLater()) return 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) //TODO unmute after investigation (tests are failing on TeamCity)
if (SystemInfoRt.isWindows) return if (SystemInfoRt.isWindows) return
val jdk9Home = KotlinTestUtils.getJdk9Home() val javaExe = File(javaHome, "bin/java.exe").takeIf { it.exists() } ?: File(javaHome, "bin/java")
val javaExe = File(jdk9Home, "bin/java.exe").takeIf { it.exists() } ?: File(jdk9Home, "bin/java") assert(javaExe.exists()) { "Can't find 'java' executable in $javaHome" }
assert(javaExe.exists()) { "Can't find 'java' executable in $jdk9Home" }
val currentJavaHome = System.getProperty("java.home") val currentJavaHome = System.getProperty("java.home")
@@ -60,7 +69,7 @@ interface Java9TestLauncher {
process.waitFor(3, TimeUnit.MINUTES) process.waitFor(3, TimeUnit.MINUTES)
if (process.exitValue() != 0) { 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")
} }
} }