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.WriterBackedKaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.base.util.info
|
||||
import org.jetbrains.kotlin.kapt3.util.doOpenInternalPackagesIfRequired
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
object Kapt {
|
||||
@@ -24,6 +25,7 @@ object Kapt {
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
fun kapt(options: KaptOptions): Boolean {
|
||||
doOpenInternalPackagesIfRequired()
|
||||
val logger = WriterBackedKaptLogger(options[KaptFlag.VERBOSE])
|
||||
|
||||
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.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.util.MessageCollectorBackedKaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.util.doOpenInternalPackagesIfRequired
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
@@ -62,6 +63,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
|
||||
override val pluginOptions: Collection<AbstractCliOption> = values().asList()
|
||||
|
||||
override fun processOption(option: AbstractCliOption, value: String, configuration: CompilerConfiguration) {
|
||||
doOpenInternalPackagesIfRequired()
|
||||
if (option !is KaptCliOption) {
|
||||
throw CliOptionProcessingException("Unknown option: ${option.optionName}")
|
||||
}
|
||||
@@ -158,6 +160,7 @@ class Kapt3CommandLineProcessor : CommandLineProcessor {
|
||||
|
||||
class Kapt3ComponentRegistrar : ComponentRegistrar {
|
||||
override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) {
|
||||
doOpenInternalPackagesIfRequired()
|
||||
val contentRoots = configuration[CLIConfigurationKeys.CONTENT_ROOTS] ?: emptyList()
|
||||
|
||||
val optionsBuilder = (configuration[KAPT_OPTIONS] ?: KaptOptions.Builder()).apply {
|
||||
|
||||
Reference in New Issue
Block a user