[kotlin] split org.jetbrains.kotlin.supportsKotlinK2Mode into different modes

- Now the support for K1 and K2 modes can be specified separately
- Introduce a marker class `SupportsKotlinPluginMode` to avoid errors in the plugin.xml
- Update existing usages of `<supportsKotlinK2Mode/>` -> `<supportsKotlinPluginMode supportsK2="false"/>` in monorepo

^KTIJ-30474 fixed

GitOrigin-RevId: e49c7e139ea9a2c4062d8b1cb801018cf59dd35e
This commit is contained in:
Ilya Kirillov
2024-07-05 21:03:13 +02:00
committed by intellij-monorepo-bot
parent 253436f3a9
commit fe5dfb560b
8 changed files with 130 additions and 29 deletions

View File

@@ -50,8 +50,10 @@ plugin.loading.error.short.incompatible.with.platform=Incompatible: requires hos
plugin.loading.error.long.incompatible.with.platform=Plugin ''{0}'' (version ''{1}'') is not compatible with the current host platform, because it requires {2} but the current platform is {3}
plugin.loading.error.short.custom.plugin.loading.disabled=Loading of custom plugins is disabled
plugin.loading.error.long.custom.plugin.loading.disabled=Plugin ''{0}'' wasn''t loaded because loading of custom plugins is explicitly disabled in the current instance of the IDE
plugin.loading.error.long.kotlin.k2.incompatible=Plugin ''{0}'' wasn''t loaded because it''s incompatible with the Kotlin plugin in K2 mode
plugin.loading.error.short.kotlin.k2.incompatible=Plugin is incompatible with the Kotlin plugin in K2 mode
plugin.loading.error.k1.mode="K1"
plugin.loading.error.k2.mode="K2"
plugin.loading.error.long.kotlin.incompatible=Plugin ''{0}'' wasn''t loaded because it''s incompatible with the Kotlin plugin in {1} mode
plugin.loading.error.short.kotlin.incompatible=Plugin is incompatible with the Kotlin plugin in {0} mode
plugin.loading.error.short.plugin.loading.disabled=Loading of plugins is disabled
plugin.loading.error.long.plugin.loading.disabled=Plugin ''{0}'' wasn''t loaded because loading of plugins is explicitly disabled in the current instance of the IDE
plugin.loading.error.short.marked.as.broken=Marked as incompatible

View File

@@ -189,8 +189,7 @@ class ClassLoaderConfigurator(
val subDescriptor = dependency.subDescriptor ?: continue
if (!isKotlinPlugin(module.pluginId) &&
isKotlinPlugin(dependency.pluginId) &&
isKotlinPluginK2Mode() &&
!pluginCanWorkInK2Mode(module)
isIncompatibleWithKotlinPlugin(module)
) {
// disable dependencies which optionally deepened on Kotlin plugin which are incompatible with Kotlin Plugin K2 mode KTIJ-24797
continue

View File

@@ -386,12 +386,17 @@ class IdeaPluginDescriptorImpl(
}
if (isPluginWhichDependsOnKotlinPluginInK2ModeAndItDoesNotSupportK2Mode(this)) {
// disable plugins which are incompatible with the Kotlin Plugin K2 Mode KTIJ-24797
if (isPluginWhichDependsOnKotlinPluginAndItsIncompatibleWithIt(this)) {
// disable plugins which are incompatible with the Kotlin Plugin K1/K2 Modes KTIJ-24797, KTIJ-30474
val mode = if (isKotlinPluginK1Mode()) {
CoreBundle.message("plugin.loading.error.k1.mode")
} else {
CoreBundle.message("plugin.loading.error.k2.mode")
}
markAsIncompatible(PluginLoadingError(
plugin = this,
detailedMessageSupplier = { CoreBundle.message("plugin.loading.error.long.kotlin.k2.incompatible", getName()) },
shortMessageSupplier = { CoreBundle.message("plugin.loading.error.short.kotlin.k2.incompatible") },
detailedMessageSupplier = { CoreBundle.message("plugin.loading.error.long.kotlin.incompatible", getName(), mode) },
shortMessageSupplier = { CoreBundle.message("plugin.loading.error.short.kotlin.incompatible", mode) },
isNotifyUser = true,
))
return

View File

@@ -1,36 +1,94 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ide.plugins
import com.intellij.openapi.extensions.ExtensionDescriptor
import org.jetbrains.annotations.ApiStatus
private val pluginIdsToIgnoreK2KotlinCompatibility: List<String> =
System.getProperty("idea.kotlin.plugin.plugin.ids.to.ignore.k2.compatibility")?.split(',')?.map { it.trim() }.orEmpty() +
listOf("fleet.backend.kotlin", "fleet.backend.mercury", "fleet.backend.mercury.kotlin.macos")
/**
* See KTIJ-30474 for semantic
*/
internal fun pluginCanWorkInK2Mode(plugin: IdeaPluginDescriptorImpl): Boolean {
return plugin.epNameToExtensions["org.jetbrains.kotlin.supportsKotlinK2Mode"]?.isNotEmpty() == true
|| plugin.pluginId.idString in pluginIdsToIgnoreK2KotlinCompatibility
val supportKotlinPluginModeEPs = getSupportKotlinPluginModeEPs(plugin)
return when {
// explicitly disabled
supportKotlinPluginModeEPs.any { it.element?.attributes.orEmpty()[SUPPORTS_K2_ATTRIBUTE_NAME] == "false" } -> false
plugin.pluginId.idString in pluginIdsToIgnoreK2KotlinCompatibility -> true
// by default, the K2 mode is not supported
else -> supportKotlinPluginModeEPs.any { it.element?.attributes.orEmpty()[SUPPORTS_K2_ATTRIBUTE_NAME] == "true" }
}
}
/**
* See KTIJ-30474 for semantic
*/
internal fun pluginCanWorkInK1Mode(plugin: IdeaPluginDescriptorImpl): Boolean {
val supportKotlinPluginModeEPs = getSupportKotlinPluginModeEPs(plugin)
return when {
// explicitly disabled
supportKotlinPluginModeEPs.any { it.element?.attributes.orEmpty()[SUPPORTS_K1_ATTRIBUTE_NAME] == "false" } -> false
// by default, the K1 mode is supported
else -> true
}
}
private fun getSupportKotlinPluginModeEPs(plugin: IdeaPluginDescriptorImpl): List<ExtensionDescriptor> {
return plugin.epNameToExtensions[SUPPORTS_KOTLIN_PLUGIN_MODE_EP_NAME] ?: emptyList()
}
internal fun isKotlinPluginK2Mode(): Boolean {
return System.getProperty("idea.kotlin.plugin.use.k2", "false").toBoolean()
}
@ApiStatus.Internal
fun isPluginWhichDependsOnKotlinPluginInK2ModeAndItDoesNotSupportK2Mode(plugin: IdeaPluginDescriptorImpl, shouldCheckIfK2modeIsOn: Boolean = true): Boolean {
fun nonOptionallyDependsOnKotlinPlugin(): Boolean {
return plugin.pluginDependencies.any { (isKotlinPlugin(it.pluginId)) && !it.isOptional } ||
plugin.dependencies.plugins.any { isKotlinPlugin(it.id) }
fun isKotlinPluginK1Mode(): Boolean {
return !isKotlinPluginK2Mode()
}
internal fun isIncompatibleWithKotlinPlugin(plugin: IdeaPluginDescriptorImpl): Boolean {
if (isKotlinPluginK1Mode() && !pluginCanWorkInK1Mode(plugin)) {
return true
}
if (!shouldCheckIfK2modeIsOn || isKotlinPluginK2Mode()) {
if (!isKotlinPlugin(plugin.pluginId) && nonOptionallyDependsOnKotlinPlugin()) {
if (!pluginCanWorkInK2Mode(plugin)) {
return true
}
}
if (isKotlinPluginK2Mode() && !pluginCanWorkInK2Mode(plugin)) {
return true
}
return false
}
}
@ApiStatus.Internal
fun isPluginWhichDependsOnKotlinPluginAndItsIncompatibleWithIt(plugin: IdeaPluginDescriptorImpl): Boolean {
if (isKotlinPlugin(plugin.pluginId)) return false
if (!nonOptionallyDependsOnKotlinPlugin(plugin)) return false
return isIncompatibleWithKotlinPlugin(plugin)
}
@ApiStatus.Internal
fun isPluginWhichDependsOnKotlinPluginInK2ModeAndItDoesNotSupportK2Mode(plugin: IdeaPluginDescriptorImpl): Boolean {
if (isKotlinPlugin(plugin.pluginId)) return false
if (!nonOptionallyDependsOnKotlinPlugin(plugin)) return false
return !pluginCanWorkInK2Mode(plugin)
}
private fun nonOptionallyDependsOnKotlinPlugin(plugin: IdeaPluginDescriptorImpl): Boolean {
return plugin.pluginDependencies.any { (isKotlinPlugin(it.pluginId)) && !it.isOptional } ||
plugin.dependencies.plugins.any { isKotlinPlugin(it.id) }
}
private const val SUPPORTS_KOTLIN_PLUGIN_MODE_EP_NAME = "org.jetbrains.kotlin.supportsKotlinPluginMode"
private const val SUPPORTS_K1_ATTRIBUTE_NAME = "supportsK1"
private const val SUPPORTS_K2_ATTRIBUTE_NAME = "supportsK2"

View File

@@ -289,9 +289,10 @@ object DynamicPlugins {
return null
}
if (isPluginWhichDependsOnKotlinPluginInK2ModeAndItDoesNotSupportK2Mode(module)) {
// force restarting the IDE in the case the dynamic plugin is incompatible with Kotlin Plugin K2 mode KTIJ-24797
return "Plugin ${module.pluginId} depends on the Kotlin plugin in K2 Mode, but the plugin does not support K2 Mode"
if (isPluginWhichDependsOnKotlinPluginAndItsIncompatibleWithIt(module)) {
// force restarting the IDE in the case the dynamic plugin is incompatible with Kotlin Plugin K1/K2 modes KTIJ-24797
val mode = if (isKotlinPluginK1Mode()) "K1" else "K2"
return "Plugin ${module.pluginId} depends on the Kotlin plugin in $mode Mode, but the plugin does not support $mode Mode"
}
var dependencyMessage: String? = null

View File

@@ -0,0 +1,32 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.base.plugin
import com.intellij.util.xmlb.annotations.Attribute
/**
* Represents if the Kotlin plugin supports K1 or K2 mode. The following code to `plugin.xml` can be added to support both K1 and K2 modes:
* ```xml
* <extensions defaultExtensionNs="org.jetbrains.kotlin">
* <supportsKotlinPluginMode supportsK2="true"/>
* </extensions>
* ```
* Or the following to support only K2 mode:
* ```xml
* <extensions defaultExtensionNs="org.jetbrains.kotlin">
* <supportsKotlinPluginMode supportsK1="false" supportsK2="true"/>
* </extensions>
* ```
* To support only K1 mode (this is the default that will be used if no `<supportsKotlinPluginMode ... />` is specified):
* ```xml
* <extensions defaultExtensionNs="org.jetbrains.kotlin">
* <supportsKotlinPluginMode supportsK1="true" supportsK2="false"/>
* </extensions>
* ```
*/
class SupportsKotlinPluginMode {
@Attribute("supportsK1")
var supportsK1: Boolean = true
@Attribute("supportsK2")
var supportsK2: Boolean = false
}

View File

@@ -72,10 +72,7 @@ class EnableK2NotificationService {
private fun hasIncompatibleWithK2ModeThirdPartyPluginsEnabled(): Boolean {
val allEnabledThirdPartyPlugins = PluginManagerCore.getPluginSet().allPlugins.filter { !it.isBundled && it.isEnabled }
return allEnabledThirdPartyPlugins.any {
isPluginWhichDependsOnKotlinPluginInK2ModeAndItDoesNotSupportK2Mode(
it,
shouldCheckIfK2modeIsOn = false
)
isPluginWhichDependsOnKotlinPluginInK2ModeAndItDoesNotSupportK2Mode(it)
}
// Code for future: get all incompatible plugins:

View File

@@ -21,6 +21,13 @@
<module name="intellij.platform.collaborationTools"/>
</dependencies>
<extensionPoints>
<extensionPoint name="org.jetbrains.kotlin.supportsKotlinPluginMode" dynamic="true"
beanClass="org.jetbrains.kotlin.idea.base.plugin.SupportsKotlinPluginMode">
</extensionPoint>
</extensionPoints>
<!-- IJ/AS-INCOMPATIBLE-PLACEHOLDER -->
<xi:include href="kotlin.plugin.k1.xml" includeUnless="idea.kotlin.plugin.use.k2"/>