[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:
Dmitriy Novozhilov
2022-06-07 10:23:09 +03:00
committed by teamcity
parent bb996c1b27
commit 8b42638afa
56 changed files with 392 additions and 191 deletions
@@ -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)
}