[Plugins] Introduce new API for registering compiler plugins
Original `ComponentRegistrar` exposes Project to its registration method, so plugins should manually register extensions to it. To prepare for possible unbound compiler from Project API in future new `K2ComponentRegistrar` introduced which provides registration method without Project at all
This commit is contained in:
committed by
teamcity
parent
bb996c1b27
commit
8b42638afa
+24
-15
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
import org.jetbrains.kotlin.codegen.CodegenFactory
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
|
||||
@@ -87,21 +88,21 @@ object FirKotlinToJvmBytecodeCompiler {
|
||||
"ATTENTION!\n This build uses experimental K2 compiler: \n -Xuse-k2"
|
||||
)
|
||||
|
||||
projectConfiguration.get(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS)?.let { pluginComponentRegistrars ->
|
||||
val notSupportedPlugins = pluginComponentRegistrars.filter {
|
||||
!it.supportsK2 && it::class.java.canonicalName != CLICompiler.SCRIPT_PLUGIN_REGISTRAR_NAME
|
||||
}
|
||||
if (notSupportedPlugins.isNotEmpty()) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR,
|
||||
"""
|
||||
|There are some plugins incompatible with K2 compiler:
|
||||
|${notSupportedPlugins.joinToString(separator = "\n|") { " ${it::class.qualifiedName}" }}
|
||||
|Please remove -Xuse-k2
|
||||
""".trimMargin()
|
||||
)
|
||||
return false
|
||||
}
|
||||
val notSupportedPlugins = mutableListOf<String?>().apply {
|
||||
projectConfiguration.get(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS).collectIncompatiblePluginNamesTo(this, ComponentRegistrar::supportsK2)
|
||||
projectConfiguration.get(CompilerPluginRegistrar.COMPILER_PLUGIN_REGISTRARS).collectIncompatiblePluginNamesTo(this, CompilerPluginRegistrar::supportsK2)
|
||||
}
|
||||
|
||||
if (notSupportedPlugins.isNotEmpty()) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR,
|
||||
"""
|
||||
|There are some plugins incompatible with K2 compiler:
|
||||
|${notSupportedPlugins.joinToString(separator = "\n|") { " $it" }}
|
||||
|Please remove -Xuse-k2
|
||||
""".trimMargin()
|
||||
)
|
||||
return false
|
||||
}
|
||||
if (projectConfiguration.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) {
|
||||
messageCollector.report(
|
||||
@@ -153,6 +154,14 @@ object FirKotlinToJvmBytecodeCompiler {
|
||||
)
|
||||
}
|
||||
|
||||
private fun <T : Any> List<T>?.collectIncompatiblePluginNamesTo(
|
||||
destination: MutableList<String?>,
|
||||
supportsK2: T.() -> Boolean
|
||||
) {
|
||||
this?.filter { !it.supportsK2() && it::class.java.canonicalName != CLICompiler.SCRIPT_PLUGIN_REGISTRAR_NAME }
|
||||
?.mapTo(destination) { it::class.qualifiedName }
|
||||
}
|
||||
|
||||
private fun CompilationContext.compileModule(): Pair<FirResult, GenerationState>? {
|
||||
performanceManager?.notifyAnalysisStarted()
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
@@ -62,6 +62,8 @@ import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassFileFactoryFinalizerExtension
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
||||
import org.jetbrains.kotlin.compiler.plugin.registerInProject
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.extensions.*
|
||||
import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor
|
||||
@@ -637,12 +639,17 @@ class KotlinCoreEnvironment private constructor(
|
||||
}
|
||||
|
||||
internal fun registerExtensionsFromPlugins(project: MockProject, configuration: CompilerConfiguration) {
|
||||
fun createErrorMessage(extension: Any): String {
|
||||
return "The provided plugin ${extension.javaClass.name} is not compatible with this version of compiler"
|
||||
}
|
||||
|
||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
|
||||
for (registrar in configuration.getList(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS)) {
|
||||
try {
|
||||
registrar.registerProjectComponents(project, configuration)
|
||||
} catch (e: AbstractMethodError) {
|
||||
val message = "The provided plugin ${registrar.javaClass.name} is not compatible with this version of compiler"
|
||||
val message = createErrorMessage(registrar)
|
||||
// Since the scripting plugin is often discovered in the compiler environment, it is often taken from the incompatible
|
||||
// location, and in many cases this is not a fatal error, therefore strong warning is generated instead of exception
|
||||
if (registrar.javaClass.simpleName == "ScriptingCompilerConfigurationComponentRegistrar") {
|
||||
@@ -652,8 +659,13 @@ class KotlinCoreEnvironment private constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val extensionStorage = CompilerPluginRegistrar.ExtensionStorage()
|
||||
for (registrar in configuration.getList(CompilerPluginRegistrar.COMPILER_PLUGIN_REGISTRARS)) {
|
||||
with(registrar) { extensionStorage.registerExtensions(configuration) }
|
||||
}
|
||||
extensionStorage.registerInProject(project) { createErrorMessage(it) }
|
||||
}
|
||||
|
||||
private fun registerApplicationServicesForCLI(applicationEnvironment: KotlinCoreApplicationEnvironment) {
|
||||
// ability to get text from annotations xml files
|
||||
|
||||
@@ -69,6 +69,9 @@ object PluginCliParser {
|
||||
val componentRegistrars = ServiceLoaderLite.loadImplementations(ComponentRegistrar::class.java, classLoader)
|
||||
configuration.addAll(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, componentRegistrars)
|
||||
|
||||
val compilerPluginRegistrars = ServiceLoaderLite.loadImplementations(CompilerPluginRegistrar::class.java, classLoader)
|
||||
configuration.addAll(CompilerPluginRegistrar.COMPILER_PLUGIN_REGISTRARS, compilerPluginRegistrars)
|
||||
|
||||
processPluginOptions(pluginOptions, configuration, classLoader)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.cli.jvm.plugins.ServiceLoaderLite
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.daemon.common.CompileService
|
||||
import org.jetbrains.kotlin.daemon.common.CompilerId
|
||||
@@ -207,13 +208,12 @@ inline fun getValidId(counter: AtomicInteger, check: (Int) -> Boolean): Int {
|
||||
|
||||
fun CompilerConfiguration.configureScripting(compilerId: CompilerId) {
|
||||
val error = try {
|
||||
val componentRegistrars =
|
||||
(this::class.java.classLoader as? URLClassLoader)?.let {
|
||||
ServiceLoaderLite.loadImplementations(ComponentRegistrar::class.java, it)
|
||||
} ?: ServiceLoaderLite.loadImplementations(
|
||||
ComponentRegistrar::class.java, compilerId.compilerClasspath.map(::File), this::class.java.classLoader
|
||||
)
|
||||
val componentRegistrars = loadRegistrars<ComponentRegistrar>(compilerId)
|
||||
addAll(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, componentRegistrars)
|
||||
|
||||
val compilerPluginRegistrars = loadRegistrars<CompilerPluginRegistrar>(compilerId)
|
||||
addAll(CompilerPluginRegistrar.COMPILER_PLUGIN_REGISTRARS, compilerPluginRegistrars)
|
||||
|
||||
null
|
||||
} catch (e: NoClassDefFoundError) {
|
||||
e
|
||||
@@ -227,3 +227,11 @@ fun CompilerConfiguration.configureScripting(compilerId: CompilerId) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : Any> CompilerConfiguration.loadRegistrars(compilerId: CompilerId): List<T> {
|
||||
return (this::class.java.classLoader as? URLClassLoader)?.let {
|
||||
ServiceLoaderLite.loadImplementations(T::class.java, it)
|
||||
} ?: ServiceLoaderLite.loadImplementations(
|
||||
T::class.java, compilerId.compilerClasspath.map(::File), this::class.java.classLoader
|
||||
)
|
||||
}
|
||||
|
||||
-4
@@ -20,10 +20,6 @@ abstract class FirExtensionRegistrar : FirExtensionRegistrarAdapter() {
|
||||
return FirExtensionRegistrarAdapter.getInstances(project) as List<FirExtensionRegistrar>
|
||||
}
|
||||
|
||||
fun registerExtension(project: Project, extension: FirExtensionRegistrar) {
|
||||
FirExtensionRegistrarAdapter.registerExtension(project, extension)
|
||||
}
|
||||
|
||||
internal val AVAILABLE_EXTENSIONS = listOf(
|
||||
FirStatusTransformerExtension::class,
|
||||
FirDeclarationGenerationExtension::class,
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.compiler.plugin
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
|
||||
abstract class CompilerPluginRegistrar {
|
||||
companion object {
|
||||
val COMPILER_PLUGIN_REGISTRARS: CompilerConfigurationKey<MutableList<CompilerPluginRegistrar>> =
|
||||
CompilerConfigurationKey.create("Compiler plugin registrars")
|
||||
}
|
||||
|
||||
abstract fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration)
|
||||
|
||||
class ExtensionStorage {
|
||||
private val _registeredExtensions = mutableMapOf<ProjectExtensionDescriptor<*>, MutableList<Any>>()
|
||||
val registeredExtensions: Map<ProjectExtensionDescriptor<*>, List<Any>>
|
||||
get() = _registeredExtensions
|
||||
|
||||
fun <T : Any> ProjectExtensionDescriptor<T>.registerExtension(extension: T) {
|
||||
_registeredExtensions.getOrPut(this, ::mutableListOf).add(extension)
|
||||
}
|
||||
}
|
||||
|
||||
abstract val supportsK2: Boolean
|
||||
}
|
||||
|
||||
fun CompilerPluginRegistrar.ExtensionStorage.registerInProject(
|
||||
project: Project,
|
||||
errorMessage: (Any) -> String = { "Error while registering ${it.javaClass.name} "}
|
||||
) {
|
||||
for ((extensionPoint, extensions) in registeredExtensions) {
|
||||
for (extension in extensions) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
try {
|
||||
(extensionPoint as ProjectExtensionDescriptor<Any>).registerExtensionUnsafe(project, extension)
|
||||
} catch (e: AbstractMethodError) {
|
||||
throw IllegalStateException(errorMessage(extension), e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ProjectExtensionDescriptor<Any>.registerExtensionUnsafe(project: Project, extension: Any) {
|
||||
this.registerExtension(project, extension)
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun registerExtensionsForTest(
|
||||
project: Project,
|
||||
configuration: CompilerConfiguration,
|
||||
register: CompilerPluginRegistrar.ExtensionStorage.(CompilerConfiguration) -> Unit
|
||||
) {
|
||||
val extensionStorage = CompilerPluginRegistrar.ExtensionStorage().apply {
|
||||
register(configuration)
|
||||
}
|
||||
extensionStorage.registerInProject(project)
|
||||
}
|
||||
@@ -17,8 +17,8 @@
|
||||
package org.jetbrains.kotlin.compiler.plugin
|
||||
|
||||
import com.intellij.mock.MockProject
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
|
||||
interface ComponentRegistrar {
|
||||
companion object {
|
||||
|
||||
+6
-2
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.test.services
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar.ExtensionStorage
|
||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
@@ -22,7 +23,8 @@ abstract class AbstractEnvironmentConfigurator : ServicesAndDirectivesContainer
|
||||
|
||||
abstract fun provideAdditionalAnalysisFlags(directives: RegisteredDirectives, languageVersion: LanguageVersion): Map<AnalysisFlag<*>, Any?>
|
||||
|
||||
abstract fun registerCompilerExtensions(project: Project, module: TestModule, configuration: CompilerConfiguration)
|
||||
abstract fun legacyRegisterCompilerExtensions(project: Project, module: TestModule, configuration: CompilerConfiguration)
|
||||
abstract fun ExtensionStorage.registerCompilerExtensions( module: TestModule, configuration: CompilerConfiguration)
|
||||
}
|
||||
|
||||
class EnvironmentConfiguratorsProvider(internal val environmentConfigurators: List<AbstractEnvironmentConfigurator>) : TestService
|
||||
@@ -56,7 +58,9 @@ abstract class EnvironmentConfigurator(protected val testServices: TestServices)
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
override fun registerCompilerExtensions(project: Project, module: TestModule, configuration: CompilerConfiguration) {}
|
||||
override fun legacyRegisterCompilerExtensions(project: Project, module: TestModule, configuration: CompilerConfiguration) {}
|
||||
|
||||
override fun ExtensionStorage.registerCompilerExtensions(module: TestModule, configuration: CompilerConfiguration) {}
|
||||
}
|
||||
|
||||
class DirectiveToConfigurationKeyExtractor {
|
||||
|
||||
+10
-1
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
|
||||
import org.jetbrains.kotlin.compiler.plugin.registerInProject
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
@@ -44,7 +46,14 @@ abstract class CompilerConfigurationProvider(val testServices: TestServices) : T
|
||||
}
|
||||
|
||||
fun registerCompilerExtensions(project: Project, module: TestModule, configuration: CompilerConfiguration) {
|
||||
configurators.forEach { it.registerCompilerExtensions(project, module, configuration) }
|
||||
val extensionStorage = CompilerPluginRegistrar.ExtensionStorage()
|
||||
for (configurator in configurators) {
|
||||
configurator.legacyRegisterCompilerExtensions(project, module, configuration)
|
||||
with(configurator) {
|
||||
extensionStorage.registerCompilerExtensions(module, configuration)
|
||||
}
|
||||
}
|
||||
extensionStorage.registerInProject(project)
|
||||
}
|
||||
|
||||
open fun getPackagePartProviderFactory(module: TestModule): (GlobalSearchScope) -> JvmPackagePartProvider {
|
||||
|
||||
Reference in New Issue
Block a user