KAPT does not fail with default settings on JDK 16+
If KAPT process is executed on latest JDKs and module 'jdk.compiler' does not export required packages, KAPT will configure this module to export required packages. #KT-45545 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
31d7d341d4
commit
52e45062cf
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.base.kapt3.*
|
|||||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||||
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
|
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
|
||||||
import org.jetbrains.kotlin.kapt3.base.util.info
|
import org.jetbrains.kotlin.kapt3.base.util.info
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.doOpenInternalPackagesIfRequired
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
object Kapt {
|
object Kapt {
|
||||||
@@ -24,6 +25,7 @@ object Kapt {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun kapt(options: KaptOptions): Boolean {
|
fun kapt(options: KaptOptions): Boolean {
|
||||||
|
doOpenInternalPackagesIfRequired()
|
||||||
val logger = WriterBackedKaptLogger(options[KaptFlag.VERBOSE])
|
val logger = WriterBackedKaptLogger(options[KaptFlag.VERBOSE])
|
||||||
|
|
||||||
if (!Kapt.checkJavacComponentsAccess(logger)) {
|
if (!Kapt.checkJavacComponentsAccess(logger)) {
|
||||||
|
|||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.kapt3.util
|
||||||
|
|
||||||
|
import sun.misc.Unsafe
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.lang.invoke.MethodHandles
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
|
||||||
|
val REQUIRED_PACKAGES_TO_TEST_CLASSES = mapOf(
|
||||||
|
"com.sun.tools.javac.util" to "Context",
|
||||||
|
"com.sun.tools.javac.file" to "CacheFSInfo",
|
||||||
|
"com.sun.tools.javac.tree" to "TreeTranslator",
|
||||||
|
"com.sun.tools.javac.main" to "CommandLine",
|
||||||
|
"com.sun.tools.javac.jvm" to "ClassFile",
|
||||||
|
"com.sun.tools.javac.parser" to "Tokens\$TokenKind",
|
||||||
|
"com.sun.tools.javac.code" to "Source",
|
||||||
|
"com.sun.tools.javac.processing" to "PrintingProcessor",
|
||||||
|
"com.sun.tools.javac.comp" to "AttrContext",
|
||||||
|
"com.sun.tools.javac.api" to "DiagnosticFormatter\$PositionKind"
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun openPackages(packagesToOpen: Collection<String>) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun allModules(): Collection<Any>? {
|
||||||
|
// Actually it is similar to ModuleLayer.boot().modules()
|
||||||
|
try {
|
||||||
|
val boot = Class.forName("java.lang.ModuleLayer").getMethod("boot").invoke(null) ?: return null
|
||||||
|
return boot.javaClass.getMethod("modules").invoke(boot) as? Collection<Any>
|
||||||
|
} catch (_: Exception) {
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun getPackages(module: Any) =
|
||||||
|
// similar to module.packages
|
||||||
|
module.javaClass.getMethod("getPackages").invoke(module) as Collection<String>
|
||||||
|
val modules = allModules() ?: return
|
||||||
|
val unsafe = Unsafe::class.java.getDeclaredField("theUnsafe").apply {
|
||||||
|
isAccessible = true
|
||||||
|
}.get(null) as Unsafe
|
||||||
|
val implLookupField = MethodHandles.Lookup::class.java.getDeclaredField("IMPL_LOOKUP")
|
||||||
|
val lookup =
|
||||||
|
unsafe.getObject(
|
||||||
|
unsafe.staticFieldBase(implLookupField),
|
||||||
|
unsafe.staticFieldOffset(implLookupField)
|
||||||
|
) as MethodHandles.Lookup
|
||||||
|
val modifiers = lookup.findSetter(Method::class.java, "modifiers", Integer.TYPE)
|
||||||
|
|
||||||
|
val exportMethod: Method = Class.forName("java.lang.Module").getDeclaredMethod("implAddOpens", String::class.java)
|
||||||
|
modifiers.invokeExact(exportMethod, Modifier.PUBLIC)
|
||||||
|
|
||||||
|
modules.forEach { module ->
|
||||||
|
getPackages(module).filter { packagesToOpen.contains(it) }.forEach { name ->
|
||||||
|
exportMethod.invoke(module, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun unavailableRequiredPackages() = REQUIRED_PACKAGES_TO_TEST_CLASSES.filter { entry ->
|
||||||
|
try {
|
||||||
|
val classInstance = Class.forName("${entry.key}.${entry.value}")
|
||||||
|
if (classInstance.isEnum) {
|
||||||
|
classInstance.getMethod("values").invoke(null)
|
||||||
|
} else {
|
||||||
|
classInstance.getDeclaredConstructor().newInstance()
|
||||||
|
}
|
||||||
|
false
|
||||||
|
} catch (_: IllegalAccessException) {
|
||||||
|
true
|
||||||
|
} catch (_: Exception) {
|
||||||
|
// in old versions of JDK some classes could be unavailable
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}.keys
|
||||||
|
|
||||||
|
private var checkDone = false
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun doOpenInternalPackagesIfRequired() {
|
||||||
|
if (checkDone)
|
||||||
|
return
|
||||||
|
try {
|
||||||
|
checkDone = true
|
||||||
|
val unavailablePackages = unavailableRequiredPackages()
|
||||||
|
if (unavailablePackages.isNotEmpty()) {
|
||||||
|
openPackages(unavailablePackages)
|
||||||
|
val failedToOpen = unavailableRequiredPackages()
|
||||||
|
if (failedToOpen.isNotEmpty()) {
|
||||||
|
System.err.println(
|
||||||
|
"WARNING: Some required internal classes are unavailable. Please consider adding the following JVM arguments\n" +
|
||||||
|
"WARNING: ${failedToOpen.joinToString(" ") { "--add-opens jdk.compiler/$it=ALL-UNNAMED" }}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
System.err.println("WARNING: Failed to check for unavailable JDK packages. Reason: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.kapt.cli.KaptCliOption.*
|
|||||||
import org.jetbrains.kotlin.kapt3.base.Kapt
|
import org.jetbrains.kotlin.kapt3.base.Kapt
|
||||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||||
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedKaptLogger
|
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedKaptLogger
|
||||||
|
import org.jetbrains.kotlin.kapt3.util.doOpenInternalPackagesIfRequired
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
@@ -62,6 +63,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
|
|||||||
override val pluginOptions: Collection<AbstractCliOption> = values().asList()
|
override val pluginOptions: Collection<AbstractCliOption> = values().asList()
|
||||||
|
|
||||||
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
|
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
|
||||||
|
doOpenInternalPackagesIfRequired()
|
||||||
if (option !is KaptCliOption) {
|
if (option !is KaptCliOption) {
|
||||||
throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
||||||
}
|
}
|
||||||
@@ -158,6 +160,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
|
|||||||
|
|
||||||
class Kapt3ComponentRegistrar : ComponentRegistrar {
|
class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||||
|
doOpenInternalPackagesIfRequired()
|
||||||
val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
|
val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
|
||||||
|
|
||||||
val optionsBuilder = (configuration[KAPT_OPTIONS] ?: KaptOptions.Builder()).apply {
|
val optionsBuilder = (configuration[KAPT_OPTIONS] ?: KaptOptions.Builder()).apply {
|
||||||
|
|||||||
Reference in New Issue
Block a user