mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
IJPL-310 reduce plugin model memory size, simplify read code
GitOrigin-RevId: a89598d83a2a7dd727ed55b59da3905575a002c6
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a88836f417
commit
ef1fc7b5ff
@@ -1,8 +1,12 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplaceGetOrSet")
|
||||
|
||||
package com.intellij.ide.plugins
|
||||
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import kotlinx.collections.immutable.mutate
|
||||
import kotlinx.collections.immutable.persistentHashMapOf
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
private const val moduleNamePrefix = "com.intellij.platform."
|
||||
@@ -36,20 +40,22 @@ enum class IdeaPluginPlatform {
|
||||
};
|
||||
|
||||
val moduleId: PluginId = PluginId.getId(moduleNamePrefix + name.lowercase())
|
||||
|
||||
abstract fun isHostPlatform(): Boolean
|
||||
|
||||
companion object {
|
||||
private val directory: Map<PluginId, IdeaPluginPlatform> = values().associateBy { it.moduleId }
|
||||
private val directory = persistentHashMapOf<PluginId, IdeaPluginPlatform>().mutate {
|
||||
map -> entries.associateByTo(map) { it.moduleId }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getHostPlatformModuleIds(): List<PluginId> =
|
||||
values().mapNotNull { it.takeIf { it.isHostPlatform() }?.moduleId }
|
||||
fun getHostPlatformModuleIds(): List<PluginId> = entries.mapNotNull { it.takeIf { it.isHostPlatform() }?.moduleId }
|
||||
|
||||
@JvmStatic
|
||||
fun fromModuleId(moduleId: PluginId): IdeaPluginPlatform? =
|
||||
directory[moduleId] ?: Unknown.takeIf { looksLikePlatformId(moduleId.idString) }
|
||||
fun fromModuleId(moduleId: PluginId): IdeaPluginPlatform? {
|
||||
return directory.get(moduleId) ?: Unknown.takeIf { looksLikePlatformId(moduleId.idString) }
|
||||
}
|
||||
|
||||
private fun looksLikePlatformId(idString: String): Boolean =
|
||||
idString.startsWith(moduleNamePrefix) && idString != "com.intellij.platform.images"
|
||||
private fun looksLikePlatformId(idString: String): Boolean {
|
||||
return idString.startsWith(moduleNamePrefix) && idString != "com.intellij.platform.images"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2023 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.components.ComponentConfig
|
||||
@@ -6,22 +6,25 @@ import com.intellij.openapi.components.ServiceDescriptor
|
||||
import com.intellij.openapi.extensions.ExtensionDescriptor
|
||||
import com.intellij.openapi.extensions.ExtensionPointDescriptor
|
||||
import com.intellij.util.messages.ListenerDescriptor
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.PersistentMap
|
||||
import kotlinx.collections.immutable.persistentHashMapOf
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.util.*
|
||||
|
||||
@ApiStatus.Internal
|
||||
class ContainerDescriptor {
|
||||
private var _services: MutableList<ServiceDescriptor>? = null
|
||||
val services: List<ServiceDescriptor>
|
||||
get() = _services ?: Collections.emptyList()
|
||||
get() = _services ?: persistentListOf()
|
||||
|
||||
@JvmField var components: MutableList<ComponentConfig>? = null
|
||||
@JvmField var components: PersistentList<ComponentConfig> = persistentListOf()
|
||||
@JvmField var listeners: MutableList<ListenerDescriptor>? = null
|
||||
|
||||
@JvmField var extensionPoints: MutableList<ExtensionPointDescriptor>? = null
|
||||
@JvmField var extensionPoints: PersistentList<ExtensionPointDescriptor> = persistentListOf()
|
||||
|
||||
@Transient var distinctExtensionPointCount: Int = -1
|
||||
@Transient @JvmField var extensions: Map<String, MutableList<ExtensionDescriptor>>? = null
|
||||
@Transient @JvmField var extensions: PersistentMap<String, PersistentList<ExtensionDescriptor>> = persistentHashMapOf()
|
||||
|
||||
fun addService(serviceDescriptor: ServiceDescriptor) {
|
||||
if (_services == null) {
|
||||
@@ -30,17 +33,8 @@ class ContainerDescriptor {
|
||||
_services!!.add(serviceDescriptor)
|
||||
}
|
||||
|
||||
internal fun getComponentListToAdd(): MutableList<ComponentConfig> {
|
||||
var result = components
|
||||
if (result == null) {
|
||||
result = ArrayList()
|
||||
components = result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
if (_services == null && components == null && extensionPoints == null && extensions == null && listeners == null) {
|
||||
if (_services == null && components.isEmpty() && extensionPoints.isEmpty() && extensions.isEmpty() && listeners == null) {
|
||||
return "ContainerDescriptor(empty)"
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplaceGetOrSet", "ReplaceNegatedIsEmptyWithIsNotEmpty", "OVERRIDE_DEPRECATION")
|
||||
@file:Suppress("ReplaceGetOrSet", "ReplaceNegatedIsEmptyWithIsNotEmpty", "OVERRIDE_DEPRECATION", "ReplacePutWithAssignment")
|
||||
package com.intellij.ide.plugins
|
||||
|
||||
import com.intellij.AbstractBundle
|
||||
@@ -10,6 +10,7 @@ import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.ExtensionDescriptor
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.extensions.impl.ExtensionPointImpl
|
||||
import kotlinx.collections.immutable.*
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.annotations.NonNls
|
||||
@@ -68,7 +69,7 @@ class IdeaPluginDescriptorImpl(raw: RawPluginDescriptor,
|
||||
private var category: String? = raw.category
|
||||
@JvmField internal val url: String? = raw.url
|
||||
@JvmField val pluginDependencies: List<PluginDependency>
|
||||
@JvmField val incompatibilities: List<PluginId> = raw.incompatibilities ?: Collections.emptyList()
|
||||
@JvmField val incompatibilities: PersistentList<PluginId> = raw.incompatibilities
|
||||
|
||||
init {
|
||||
// https://youtrack.jetbrains.com/issue/IDEA-206274
|
||||
@@ -97,15 +98,37 @@ class IdeaPluginDescriptorImpl(raw: RawPluginDescriptor,
|
||||
@JvmField val actions: List<RawPluginDescriptor.ActionDescriptor> = raw.actions ?: Collections.emptyList()
|
||||
|
||||
// extension point name -> list of extension descriptors
|
||||
val epNameToExtensions: Map<String, MutableList<ExtensionDescriptor>>? = raw.epNameToExtensions
|
||||
@JvmField val epNameToExtensions: PersistentMap<String, PersistentList<ExtensionDescriptor>> = raw.epNameToExtensions.let { rawMap ->
|
||||
if (rawMap.size < 2 || !rawMap.containsKey(registryEpName)) {
|
||||
rawMap.toPersistentHashMap()
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* What's going on:
|
||||
* See [com.intellij.ide.plugins.DynamicPluginsTest]#`registry access of key from same plugin`
|
||||
* This is an ad-hoc solution to the problem, it doesn't fix the root cause. This may also break if this map gets copied
|
||||
* or transformed into a HashMap somewhere, but it seems it's not the case right now.
|
||||
* TODO: one way to make a better fix is to introduce loadingOrder on extension points (as it is made for extensions).
|
||||
*/
|
||||
persistentMapOf<String, PersistentList<ExtensionDescriptor>>().mutate {
|
||||
val keys = rawMap.keys.toTypedArray()
|
||||
keys.sortWith(extensionPointNameComparator)
|
||||
for (key in keys) {
|
||||
it.put(key, rawMap.get(key)!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField val appContainerDescriptor: ContainerDescriptor = raw.appContainerDescriptor
|
||||
@JvmField val projectContainerDescriptor: ContainerDescriptor = raw.projectContainerDescriptor
|
||||
@JvmField val moduleContainerDescriptor: ContainerDescriptor = raw.moduleContainerDescriptor
|
||||
|
||||
@JvmField val content: PluginContentDescriptor = raw.contentModules?.let { PluginContentDescriptor(it) } ?: PluginContentDescriptor.EMPTY
|
||||
@JvmField val content: PluginContentDescriptor = raw.contentModules.takeIf { it.isNotEmpty() }?.let { PluginContentDescriptor(it) }
|
||||
?: PluginContentDescriptor.EMPTY
|
||||
|
||||
@JvmField val dependencies: ModuleDependenciesDescriptor = raw.dependencies
|
||||
@JvmField var modules: List<PluginId> = raw.modules ?: Collections.emptyList()
|
||||
@JvmField var modules: PersistentList<PluginId> = raw.modules
|
||||
|
||||
private val descriptionChildText = raw.description
|
||||
|
||||
@@ -192,7 +215,7 @@ class IdeaPluginDescriptorImpl(raw: RawPluginDescriptor,
|
||||
|
||||
if (!isSub) {
|
||||
if (id == PluginManagerCore.CORE_ID) {
|
||||
modules = modules + IdeaPluginPlatform.getHostPlatformModuleIds()
|
||||
modules = modules.addAll(IdeaPluginPlatform.getHostPlatformModuleIds())
|
||||
}
|
||||
|
||||
if (context.isPluginDisabled(id)) {
|
||||
@@ -346,58 +369,55 @@ class IdeaPluginDescriptorImpl(raw: RawPluginDescriptor,
|
||||
fun registerExtensions(nameToPoint: Map<String, ExtensionPointImpl<*>>,
|
||||
containerDescriptor: ContainerDescriptor,
|
||||
listenerCallbacks: MutableList<in Runnable>?) {
|
||||
containerDescriptor.extensions?.let {
|
||||
if (!it.isEmpty()) {
|
||||
@Suppress("JavaMapForEach")
|
||||
it.forEach { name, list ->
|
||||
nameToPoint.get(name)?.registerExtensions(descriptors = list, pluginDescriptor = this, listenerCallbacks = listenerCallbacks)
|
||||
}
|
||||
if (!containerDescriptor.extensions.isEmpty()) {
|
||||
for ((name, list) in containerDescriptor.extensions) {
|
||||
nameToPoint.get(name)?.registerExtensions(descriptors = list, pluginDescriptor = this, listenerCallbacks = listenerCallbacks)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
val unsortedMap = epNameToExtensions ?: return
|
||||
val map = epNameToExtensions
|
||||
|
||||
// app container: in most cases will be only app-level extensions - to reduce map copying, assume that all extensions are app-level and then filter out
|
||||
// project container: rest of extensions wil be mostly project level
|
||||
// module container: just use rest, area will not register unrelated extension anyway as no registered point
|
||||
|
||||
if (containerDescriptor == appContainerDescriptor) {
|
||||
val registeredCount = doRegisterExtensions(unsortedMap, nameToPoint, listenerCallbacks)
|
||||
if (containerDescriptor === appContainerDescriptor) {
|
||||
val registeredCount = doRegisterExtensions(map = map, nameToPoint = nameToPoint, listenerCallbacks = listenerCallbacks)
|
||||
containerDescriptor.distinctExtensionPointCount = registeredCount
|
||||
|
||||
if (registeredCount == unsortedMap.size) {
|
||||
projectContainerDescriptor.extensions = Collections.emptyMap()
|
||||
moduleContainerDescriptor.extensions = Collections.emptyMap()
|
||||
if (registeredCount == map.size) {
|
||||
projectContainerDescriptor.extensions = persistentHashMapOf()
|
||||
moduleContainerDescriptor.extensions = persistentHashMapOf()
|
||||
}
|
||||
}
|
||||
else if (containerDescriptor == projectContainerDescriptor) {
|
||||
val registeredCount = doRegisterExtensions(unsortedMap, nameToPoint, listenerCallbacks)
|
||||
else if (containerDescriptor === projectContainerDescriptor) {
|
||||
val registeredCount = doRegisterExtensions(map = map, nameToPoint = nameToPoint, listenerCallbacks = listenerCallbacks)
|
||||
containerDescriptor.distinctExtensionPointCount = registeredCount
|
||||
|
||||
if (registeredCount == unsortedMap.size) {
|
||||
containerDescriptor.extensions = unsortedMap
|
||||
moduleContainerDescriptor.extensions = Collections.emptyMap()
|
||||
if (registeredCount == map.size) {
|
||||
containerDescriptor.extensions = map
|
||||
moduleContainerDescriptor.extensions = persistentHashMapOf()
|
||||
}
|
||||
else if (registeredCount == (unsortedMap.size - appContainerDescriptor.distinctExtensionPointCount)) {
|
||||
moduleContainerDescriptor.extensions = Collections.emptyMap()
|
||||
else if (registeredCount == (map.size - appContainerDescriptor.distinctExtensionPointCount)) {
|
||||
moduleContainerDescriptor.extensions = persistentHashMapOf()
|
||||
}
|
||||
}
|
||||
else {
|
||||
val registeredCount = doRegisterExtensions(unsortedMap, nameToPoint, listenerCallbacks)
|
||||
val registeredCount = doRegisterExtensions(map = map, nameToPoint = nameToPoint, listenerCallbacks = listenerCallbacks)
|
||||
if (registeredCount == 0) {
|
||||
moduleContainerDescriptor.extensions = Collections.emptyMap()
|
||||
moduleContainerDescriptor.extensions = persistentHashMapOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doRegisterExtensions(unsortedMap: Map<String, MutableList<ExtensionDescriptor>>,
|
||||
private fun doRegisterExtensions(map: PersistentMap<String, PersistentList<ExtensionDescriptor>>,
|
||||
nameToPoint: Map<String, ExtensionPointImpl<*>>,
|
||||
listenerCallbacks: MutableList<in Runnable>?): Int {
|
||||
var registeredCount = 0
|
||||
for (entry in unsortedMap) {
|
||||
for (entry in map) {
|
||||
val point = nameToPoint.get(entry.key) ?: continue
|
||||
point.registerExtensions(entry.value, this, listenerCallbacks)
|
||||
point.registerExtensions(descriptors = entry.value, pluginDescriptor = this, listenerCallbacks = listenerCallbacks)
|
||||
registeredCount++
|
||||
}
|
||||
return registeredCount
|
||||
@@ -479,11 +499,6 @@ class IdeaPluginDescriptorImpl(raw: RawPluginDescriptor,
|
||||
this.category = category
|
||||
}
|
||||
|
||||
val unsortedEpNameToExtensionElements: Map<String, List<ExtensionDescriptor>>
|
||||
get() {
|
||||
return Collections.unmodifiableMap(epNameToExtensions ?: return Collections.emptyMap())
|
||||
}
|
||||
|
||||
override fun getVendorEmail(): String? = vendorEmail
|
||||
|
||||
override fun getVendorUrl(): String? = vendorUrl
|
||||
@@ -547,3 +562,20 @@ private fun checkCycle(descriptor: IdeaPluginDescriptorImpl, configFile: String,
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
private const val registryEpName = "com.intellij.registryKey"
|
||||
|
||||
private val extensionPointNameComparator = Comparator<String> { o1, o2 ->
|
||||
if (o1 == registryEpName) {
|
||||
return@Comparator if (o2 == registryEpName) {
|
||||
0
|
||||
}
|
||||
else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
if (o2 == registryEpName) {
|
||||
return@Comparator 1
|
||||
}
|
||||
o1.compareTo(o2)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2023 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.PluginId
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.util.*
|
||||
|
||||
@@ -25,7 +26,7 @@ class ModuleDependenciesDescriptor(@JvmField val modules: List<ModuleReference>,
|
||||
@ApiStatus.Internal
|
||||
class PluginContentDescriptor(@JvmField val modules: List<ModuleItem>) {
|
||||
companion object {
|
||||
@JvmField val EMPTY: PluginContentDescriptor = PluginContentDescriptor(Collections.emptyList())
|
||||
@JvmField val EMPTY: PluginContentDescriptor = PluginContentDescriptor(persistentListOf())
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
|
||||
@@ -5,6 +5,10 @@ import com.intellij.openapi.extensions.ExtensionDescriptor
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.util.xml.dom.XmlElement
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.PersistentMap
|
||||
import kotlinx.collections.immutable.persistentHashMapOf
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.time.LocalDate
|
||||
|
||||
@@ -39,20 +43,20 @@ class RawPluginDescriptor {
|
||||
@JvmField internal var releaseDate: LocalDate? = null
|
||||
@JvmField internal var releaseVersion: Int = 0
|
||||
|
||||
@JvmField internal var modules: MutableList<PluginId>? = null
|
||||
@JvmField internal var modules: PersistentList<PluginId> = persistentListOf()
|
||||
|
||||
@JvmField internal var depends: MutableList<PluginDependency>? = null
|
||||
@JvmField internal var actions: MutableList<ActionDescriptor>? = null
|
||||
|
||||
@JvmField var incompatibilities: MutableList<PluginId>? = null
|
||||
@JvmField var incompatibilities: PersistentList<PluginId> = persistentListOf()
|
||||
|
||||
@JvmField val appContainerDescriptor: ContainerDescriptor = ContainerDescriptor()
|
||||
@JvmField val projectContainerDescriptor: ContainerDescriptor = ContainerDescriptor()
|
||||
@JvmField val moduleContainerDescriptor: ContainerDescriptor = ContainerDescriptor()
|
||||
|
||||
@JvmField var epNameToExtensions: MutableMap<String, MutableList<ExtensionDescriptor>>? = null
|
||||
@JvmField var epNameToExtensions: PersistentMap<String, PersistentList<ExtensionDescriptor>> = persistentHashMapOf()
|
||||
|
||||
@JvmField internal var contentModules: MutableList<PluginContentDescriptor.ModuleItem>? = null
|
||||
@JvmField internal var contentModules: PersistentList<PluginContentDescriptor.ModuleItem> = persistentListOf()
|
||||
@JvmField internal var dependencies: ModuleDependenciesDescriptor = ModuleDependenciesDescriptor.EMPTY
|
||||
|
||||
sealed class ActionDescriptor(
|
||||
|
||||
@@ -18,6 +18,10 @@ import com.intellij.util.xml.dom.NoOpXmlInterner
|
||||
import com.intellij.util.xml.dom.XmlInterner
|
||||
import com.intellij.util.xml.dom.createNonCoalescingXmlStreamReader
|
||||
import com.intellij.util.xml.dom.readXmlAsModel
|
||||
import kotlinx.collections.immutable.mutate
|
||||
import kotlinx.collections.immutable.persistentHashMapOf
|
||||
import kotlinx.collections.immutable.persistentHashSetOf
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.codehaus.stax2.XMLStreamReader2
|
||||
import org.codehaus.stax2.typed.TypedXMLStreamException
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
@@ -162,20 +166,19 @@ private fun readRootAttributes(reader: XMLStreamReader2, descriptor: RawPluginDe
|
||||
/**
|
||||
* Keep in sync with KotlinPluginUtil.KNOWN_KOTLIN_PLUGIN_IDS
|
||||
*/
|
||||
private val KNOWN_KOTLIN_PLUGIN_IDS = hashSetOf(
|
||||
private val KNOWN_KOTLIN_PLUGIN_IDS = persistentHashSetOf(
|
||||
"org.jetbrains.kotlin",
|
||||
"com.intellij.appcode.kmm",
|
||||
"org.jetbrains.kotlin.native.appcode"
|
||||
)
|
||||
|
||||
private val K2_ALLOWED_PLUGIN_IDS = hashSetOf(
|
||||
*KNOWN_KOTLIN_PLUGIN_IDS.toTypedArray(),
|
||||
private val K2_ALLOWED_PLUGIN_IDS = KNOWN_KOTLIN_PLUGIN_IDS.addAll(persistentHashSetOf(
|
||||
"fleet.backend.mercury",
|
||||
"fleet.backend.mercury.kotlin",
|
||||
"org.jetbrains.android",
|
||||
"androidx.compose.plugins.idea",
|
||||
"org.jetbrains.compose.desktop.ide",
|
||||
)
|
||||
))
|
||||
|
||||
private fun readRootElementChild(reader: XMLStreamReader2,
|
||||
descriptor: RawPluginDescriptor,
|
||||
@@ -215,19 +218,7 @@ private fun readRootElementChild(reader: XMLStreamReader2,
|
||||
"product-descriptor" -> readProduct(reader, descriptor)
|
||||
"module" -> {
|
||||
findAttributeValue(reader, "value")?.let { moduleName ->
|
||||
var modules = descriptor.modules
|
||||
if (modules == null) {
|
||||
descriptor.modules = Collections.singletonList(PluginId.getId(moduleName))
|
||||
}
|
||||
else {
|
||||
if (modules.size == 1) {
|
||||
val singleton = modules
|
||||
modules = ArrayList(4)
|
||||
modules.addAll(singleton)
|
||||
descriptor.modules = modules
|
||||
}
|
||||
modules.add(PluginId.getId(moduleName))
|
||||
}
|
||||
descriptor.modules = descriptor.modules.add(PluginId.getId(moduleName))
|
||||
}
|
||||
reader.skipElement()
|
||||
}
|
||||
@@ -251,12 +242,7 @@ private fun readRootElementChild(reader: XMLStreamReader2,
|
||||
}
|
||||
"incompatible-with" -> {
|
||||
getNullifiedContent(reader)?.let {
|
||||
var list = descriptor.incompatibilities
|
||||
if (list == null) {
|
||||
list = ArrayList()
|
||||
descriptor.incompatibilities = list
|
||||
}
|
||||
list.add(PluginId.getId(it))
|
||||
descriptor.incompatibilities = descriptor.incompatibilities.add(PluginId.getId(it))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,7 +300,11 @@ private fun readRootElementChild(reader: XMLStreamReader2,
|
||||
}
|
||||
}
|
||||
|
||||
private val actionNameToEnum = ActionDescriptorName.values().let { it.associateByTo(HashMap(it.size), ActionDescriptorName::name) }
|
||||
private val actionNameToEnum = run {
|
||||
persistentHashMapOf<String, ActionDescriptorName>().mutate { map ->
|
||||
ActionDescriptorName.entries.associateByTo(map, ActionDescriptorName::name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun readActions(descriptor: RawPluginDescriptor, reader: XMLStreamReader2, readContext: ReadModuleContext) {
|
||||
var actionElements = descriptor.actions
|
||||
@@ -459,43 +449,17 @@ private fun readExtensions(reader: XMLStreamReader2, descriptor: RawPluginDescri
|
||||
}
|
||||
}
|
||||
|
||||
var map: MutableMap<String, MutableList<ExtensionDescriptor>>? = descriptor.epNameToExtensions
|
||||
if (map == null) {
|
||||
/**
|
||||
* What's going on:
|
||||
* See [com.intellij.ide.plugins.DynamicPluginsTest]#`registry access of key from same plugin`
|
||||
* This is an ad-hoc solution to the problem, it doesn't fix the root cause. This may also break if this map gets copied
|
||||
* or transformed into a HashMap somewhere, but it seems it's not the case right now.
|
||||
* TODO: one way to make a better fix is to introduce loadingOrder on extension points (as it is made for extensions).
|
||||
*/
|
||||
map = sortedMapOf(kotlin.Comparator { o1, o2 ->
|
||||
val registryKey = "com.intellij.registryKey"
|
||||
if (o1 == registryKey) {
|
||||
return@Comparator if (o2 == registryKey) { 0 } else { -1 }
|
||||
}
|
||||
if (o2 == registryKey) {
|
||||
return@Comparator 1
|
||||
}
|
||||
o1.compareTo(o2)
|
||||
})
|
||||
descriptor.epNameToExtensions = map
|
||||
}
|
||||
val extensionDescriptor = ExtensionDescriptor(implementation = implementation,
|
||||
os = os,
|
||||
orderId = orderId,
|
||||
order = order,
|
||||
element = element,
|
||||
hasExtraAttributes = hasExtraAttributes)
|
||||
|
||||
val extensionDescriptor = ExtensionDescriptor(implementation, os, orderId, order, element, hasExtraAttributes)
|
||||
|
||||
val list = map.get(qualifiedExtensionPointName)
|
||||
if (list == null) {
|
||||
map.put(qualifiedExtensionPointName, Collections.singletonList(extensionDescriptor))
|
||||
}
|
||||
else if (list.size == 1) {
|
||||
val l = ArrayList<ExtensionDescriptor>(4)
|
||||
l.add(list.get(0))
|
||||
l.add(extensionDescriptor)
|
||||
map.put(qualifiedExtensionPointName, l)
|
||||
}
|
||||
else {
|
||||
list.add(extensionDescriptor)
|
||||
}
|
||||
val list = descriptor.epNameToExtensions.get(qualifiedExtensionPointName)
|
||||
@Suppress("IfThenToElvis")
|
||||
descriptor.epNameToExtensions = descriptor.epNameToExtensions
|
||||
.put(qualifiedExtensionPointName, if (list == null) persistentListOf(extensionDescriptor) else list.add(extensionDescriptor))
|
||||
|
||||
assert(reader.isEndElement)
|
||||
return@consumeChildElements
|
||||
@@ -596,13 +560,7 @@ private fun readExtensionPoints(reader: XMLStreamReader2,
|
||||
}
|
||||
}
|
||||
|
||||
var result = containerDescriptor.extensionPoints
|
||||
if (result == null) {
|
||||
result = ArrayList()
|
||||
containerDescriptor.extensionPoints = result
|
||||
}
|
||||
|
||||
result.add(ExtensionPointDescriptor(
|
||||
containerDescriptor.extensionPoints = containerDescriptor.extensionPoints.add(ExtensionPointDescriptor(
|
||||
name = qualifiedName ?: name ?: throw RuntimeException("`name` attribute not specified for extension point at ${reader.location}"),
|
||||
isNameQualified = qualifiedName != null,
|
||||
className = `interface` ?: beanClass!!,
|
||||
@@ -616,14 +574,9 @@ private fun readExtensionPoints(reader: XMLStreamReader2,
|
||||
private inline fun applyPartialContainer(from: RawPluginDescriptor,
|
||||
to: RawPluginDescriptor,
|
||||
crossinline extractor: (RawPluginDescriptor) -> ContainerDescriptor) {
|
||||
extractor(from).extensionPoints?.let {
|
||||
extractor(from).extensionPoints.takeIf { it.isNotEmpty() }?.let {
|
||||
val toContainer = extractor(to)
|
||||
if (toContainer.extensionPoints == null) {
|
||||
toContainer.extensionPoints = it
|
||||
}
|
||||
else {
|
||||
toContainer.extensionPoints!!.addAll(it)
|
||||
}
|
||||
toContainer.extensionPoints = toContainer.extensionPoints.addAll(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,6 +608,7 @@ private fun readServiceDescriptor(reader: XMLStreamReader2, os: ExtensionDescrip
|
||||
}
|
||||
}
|
||||
"client" -> {
|
||||
@Suppress("DEPRECATION")
|
||||
when (reader.getAttributeValue(i)) {
|
||||
"local" -> client = ClientKind.LOCAL
|
||||
"guest" -> client = ClientKind.GUEST
|
||||
@@ -692,7 +646,6 @@ private fun readProduct(reader: XMLStreamReader2, descriptor: RawPluginDescripto
|
||||
}
|
||||
|
||||
private fun readComponents(reader: XMLStreamReader2, containerDescriptor: ContainerDescriptor) {
|
||||
val result = containerDescriptor.getComponentListToAdd()
|
||||
reader.consumeChildElements("component") {
|
||||
var isApplicableForDefaultProject = false
|
||||
var interfaceClass: String? = null
|
||||
@@ -753,20 +706,19 @@ private fun readComponents(reader: XMLStreamReader2, containerDescriptor: Contai
|
||||
}
|
||||
assert(reader.isEndElement)
|
||||
|
||||
result.add(ComponentConfig(interfaceClass, implementationClass, headlessImplementationClass, isApplicableForDefaultProject,
|
||||
os, overrides, options))
|
||||
containerDescriptor.components = containerDescriptor.components.add(ComponentConfig(interfaceClass,
|
||||
implementationClass,
|
||||
headlessImplementationClass,
|
||||
isApplicableForDefaultProject,
|
||||
os,
|
||||
overrides,
|
||||
options))
|
||||
}
|
||||
}
|
||||
|
||||
private fun readContent(reader: XMLStreamReader2,
|
||||
descriptor: RawPluginDescriptor,
|
||||
readContext: ReadModuleContext) {
|
||||
var items = descriptor.contentModules
|
||||
if (items == null) {
|
||||
items = ArrayList()
|
||||
descriptor.contentModules = items
|
||||
}
|
||||
|
||||
reader.consumeChildElements { elementName ->
|
||||
when (elementName) {
|
||||
"module" -> {
|
||||
@@ -787,7 +739,7 @@ private fun readContent(reader: XMLStreamReader2,
|
||||
configFile = "${name.substring(0, index)}.${name.substring(index + 1)}.xml"
|
||||
}
|
||||
|
||||
items.add(PluginContentDescriptor.ModuleItem(name = name, configFile = configFile))
|
||||
descriptor.contentModules = descriptor.contentModules.add(PluginContentDescriptor.ModuleItem(name = name, configFile = configFile))
|
||||
}
|
||||
else -> throw RuntimeException("Unknown content item type: $elementName")
|
||||
}
|
||||
@@ -797,8 +749,8 @@ private fun readContent(reader: XMLStreamReader2,
|
||||
}
|
||||
|
||||
private fun readDependencies(reader: XMLStreamReader2, descriptor: RawPluginDescriptor, readContext: ReadModuleContext) {
|
||||
var modules: MutableList<ModuleDependenciesDescriptor.ModuleReference>? = null
|
||||
var plugins: MutableList<ModuleDependenciesDescriptor.PluginReference>? = null
|
||||
var modules = persistentListOf<ModuleDependenciesDescriptor.ModuleReference>()
|
||||
var plugins = persistentListOf<ModuleDependenciesDescriptor.PluginReference>()
|
||||
reader.consumeChildElements { elementName ->
|
||||
when (elementName) {
|
||||
"module" -> {
|
||||
@@ -809,10 +761,7 @@ private fun readDependencies(reader: XMLStreamReader2, descriptor: RawPluginDesc
|
||||
}
|
||||
}
|
||||
|
||||
if (modules == null) {
|
||||
modules = ArrayList()
|
||||
}
|
||||
modules!!.add(ModuleDependenciesDescriptor.ModuleReference(name!!))
|
||||
modules = modules.add(ModuleDependenciesDescriptor.ModuleReference(name!!))
|
||||
}
|
||||
"plugin" -> {
|
||||
var id: String? = null
|
||||
@@ -822,16 +771,13 @@ private fun readDependencies(reader: XMLStreamReader2, descriptor: RawPluginDesc
|
||||
}
|
||||
}
|
||||
|
||||
if (plugins == null) {
|
||||
plugins = ArrayList()
|
||||
}
|
||||
plugins!!.add(ModuleDependenciesDescriptor.PluginReference(PluginId.getId(id!!)))
|
||||
plugins = plugins.add(ModuleDependenciesDescriptor.PluginReference(PluginId.getId(id!!)))
|
||||
}
|
||||
else -> throw RuntimeException("Unknown content item type: $elementName")
|
||||
}
|
||||
reader.skipElement()
|
||||
}
|
||||
descriptor.dependencies = ModuleDependenciesDescriptor(modules ?: Collections.emptyList(), plugins ?: Collections.emptyList())
|
||||
descriptor.dependencies = ModuleDependenciesDescriptor(modules, plugins)
|
||||
assert(reader.isEndElement)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplaceGetOrSet", "ReplacePutWithAssignment")
|
||||
package com.intellij.serviceContainer
|
||||
|
||||
@@ -7,42 +7,51 @@ import com.intellij.ide.plugins.IdeaPluginDescriptorImpl
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.extensions.ExtensionDescriptor
|
||||
import com.intellij.openapi.extensions.ExtensionPointDescriptor
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.PersistentMap
|
||||
import kotlinx.collections.immutable.persistentHashMapOf
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
class PrecomputedExtensionModel(
|
||||
@JvmField val extensionPoints: List<List<ExtensionPointDescriptor>>,
|
||||
@JvmField val pluginDescriptors: List<IdeaPluginDescriptor>,
|
||||
@JvmField val extensionPoints: PersistentList<PersistentList<ExtensionPointDescriptor>>,
|
||||
@JvmField val pluginDescriptors: PersistentList<IdeaPluginDescriptor>,
|
||||
@JvmField val extensionPointTotalCount: Int,
|
||||
|
||||
@JvmField val nameToExtensions: Map<String, MutableList<Pair<IdeaPluginDescriptor, List<ExtensionDescriptor>>>>
|
||||
@JvmField val nameToExtensions: PersistentMap<String, PersistentList<Pair<IdeaPluginDescriptor, PersistentList<ExtensionDescriptor>>>>
|
||||
)
|
||||
|
||||
fun precomputeExtensionModel(): PrecomputedExtensionModel {
|
||||
val extensionPointDescriptors = ArrayList<List<ExtensionPointDescriptor>>()
|
||||
val pluginDescriptors = ArrayList<IdeaPluginDescriptor>()
|
||||
var extensionPointDescriptors = persistentListOf<PersistentList<ExtensionPointDescriptor>>()
|
||||
var pluginDescriptors = persistentListOf<IdeaPluginDescriptor>()
|
||||
var extensionPointTotalCount = 0
|
||||
val nameToExtensions = HashMap<String, MutableList<Pair<IdeaPluginDescriptor, List<ExtensionDescriptor>>>>()
|
||||
val nameToExtensions = persistentHashMapOf<String, PersistentList<Pair<IdeaPluginDescriptor, PersistentList<ExtensionDescriptor>>>>()
|
||||
|
||||
// step 1 - collect container level extension points
|
||||
val modules = PluginManagerCore.getPluginSet().getEnabledModules()
|
||||
executeRegisterTask(modules) { pluginDescriptor ->
|
||||
pluginDescriptor.moduleContainerDescriptor.extensionPoints?.let {
|
||||
extensionPointDescriptors.add(it)
|
||||
pluginDescriptors.add(pluginDescriptor)
|
||||
extensionPointTotalCount += it.size
|
||||
val list = pluginDescriptor.moduleContainerDescriptor.extensionPoints
|
||||
if (list.isEmpty()) {
|
||||
return@executeRegisterTask
|
||||
}
|
||||
|
||||
for (descriptor in it) {
|
||||
nameToExtensions.put(descriptor.getQualifiedName(pluginDescriptor), mutableListOf())
|
||||
}
|
||||
extensionPointDescriptors = extensionPointDescriptors.add(list)
|
||||
pluginDescriptors = pluginDescriptors.add(pluginDescriptor)
|
||||
extensionPointTotalCount += list.size
|
||||
|
||||
for (descriptor in list) {
|
||||
nameToExtensions.put(descriptor.getQualifiedName(pluginDescriptor), persistentListOf())
|
||||
}
|
||||
}
|
||||
|
||||
// step 2 - collect container level extensions
|
||||
executeRegisterTask(modules) { pluginDescriptor ->
|
||||
val unsortedMap = pluginDescriptor.epNameToExtensions ?: return@executeRegisterTask
|
||||
for ((name, list) in unsortedMap.entries) {
|
||||
nameToExtensions.get(name)?.add(pluginDescriptor to list)
|
||||
val map = pluginDescriptor.epNameToExtensions
|
||||
for ((name, list) in map.entries) {
|
||||
nameToExtensions.get(name)?.let {
|
||||
nameToExtensions.put(name, it.add(pluginDescriptor to list))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,19 +24,19 @@ internal class BeanExtensionPoint<T : Any>(
|
||||
override fun createAdapter(descriptor: ExtensionDescriptor,
|
||||
pluginDescriptor: PluginDescriptor,
|
||||
componentManager: ComponentManager): ExtensionComponentAdapter {
|
||||
return if (componentManager.isInjectionForExtensionSupported) {
|
||||
SimpleConstructorInjectionAdapter(implementationClassName = className,
|
||||
pluginDescriptor = pluginDescriptor,
|
||||
descriptor = descriptor,
|
||||
implementationClassResolver = this)
|
||||
if (componentManager.isInjectionForExtensionSupported) {
|
||||
return SimpleConstructorInjectionAdapter(implementationClassName = className,
|
||||
pluginDescriptor = pluginDescriptor,
|
||||
descriptor = descriptor,
|
||||
implementationClassResolver = this)
|
||||
}
|
||||
else {
|
||||
XmlExtensionAdapter(implementationClassName = className,
|
||||
pluginDescriptor = pluginDescriptor,
|
||||
orderId = descriptor.orderId,
|
||||
order = descriptor.order,
|
||||
extensionElement = descriptor.element,
|
||||
implementationClassResolver = this)
|
||||
return XmlExtensionAdapter(implementationClassName = className,
|
||||
pluginDescriptor = pluginDescriptor,
|
||||
orderId = descriptor.orderId,
|
||||
order = descriptor.order,
|
||||
extensionElement = descriptor.element,
|
||||
implementationClassResolver = this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.annotations.TestOnly
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.function.BiPredicate
|
||||
import java.util.function.Predicate
|
||||
import kotlin.concurrent.Volatile
|
||||
@@ -36,24 +35,22 @@ sealed class ExtensionPointImpl<T : Any>(val name: String,
|
||||
val componentManager: ComponentManager,
|
||||
private var extensionClass: Class<T>?,
|
||||
private val isDynamic: Boolean) : ExtensionPoint<T> {
|
||||
// immutable list, never modified in-place, only swapped atomically
|
||||
@Volatile
|
||||
private var cachedExtensions: PersistentList<T>? = null
|
||||
|
||||
@Volatile
|
||||
private var cachedExtensionsAsArray: Array<T>? = null
|
||||
|
||||
// guarded by this
|
||||
@Volatile
|
||||
private var adapters = persistentListOf<ExtensionComponentAdapter>()
|
||||
|
||||
@Volatile
|
||||
private var adaptersAreSorted = true
|
||||
|
||||
// guarded by this
|
||||
private var listeners = persistentListOf<ExtensionPointListener<T>>()
|
||||
|
||||
private val keyMapperToCacheRef = AtomicReference<ConcurrentMap<*, Map<*, *>>>()
|
||||
@Volatile
|
||||
private var keyMapperToCache: ConcurrentMap<*, Map<*, *>>? = null
|
||||
|
||||
companion object {
|
||||
fun setCheckCanceledAction(checkCanceled: Runnable) {
|
||||
@@ -72,9 +69,15 @@ sealed class ExtensionPointImpl<T : Any>(val name: String,
|
||||
}
|
||||
|
||||
fun <CACHE_KEY : Any?, V : Any?> getCacheMap(): ConcurrentMap<CACHE_KEY, V> {
|
||||
var keyMapperToCache = keyMapperToCacheRef.get()
|
||||
var keyMapperToCache = keyMapperToCache
|
||||
if (keyMapperToCache == null) {
|
||||
keyMapperToCache = keyMapperToCacheRef.updateAndGet { prev -> prev ?: ConcurrentHashMap<Any?, Map<*, *>>() }
|
||||
synchronized(this) {
|
||||
keyMapperToCache = this.keyMapperToCache
|
||||
if (keyMapperToCache == null) {
|
||||
keyMapperToCache = ConcurrentHashMap<Any?, Map<*, *>>()
|
||||
this.keyMapperToCache = keyMapperToCache
|
||||
}
|
||||
}
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return keyMapperToCache as ConcurrentMap<CACHE_KEY, V>
|
||||
@@ -216,7 +219,7 @@ sealed class ExtensionPointImpl<T : Any>(val name: String,
|
||||
}
|
||||
}
|
||||
}
|
||||
return array!!
|
||||
return array!!.clone()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,20 +282,11 @@ sealed class ExtensionPointImpl<T : Any>(val name: String,
|
||||
}
|
||||
|
||||
private fun createSequence(): Sequence<T> {
|
||||
val size: Int
|
||||
val adapters = sortedAdapters
|
||||
size = adapters.size
|
||||
if (size == 0) {
|
||||
return emptySequence()
|
||||
}
|
||||
else {
|
||||
return adapters.asSequence().mapNotNull(::processAdapter)
|
||||
}
|
||||
return if (adapters.isEmpty()) emptySequence() else adapters.asSequence().mapNotNull(::processAdapter)
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
return cachedExtensions?.size ?: adapters.size
|
||||
}
|
||||
override fun size(): Int = adapters.size
|
||||
|
||||
val sortedAdapters: List<ExtensionComponentAdapter>
|
||||
get() {
|
||||
@@ -454,15 +448,16 @@ sealed class ExtensionPointImpl<T : Any>(val name: String,
|
||||
|
||||
cachedExtensions = newList.toPersistentList()
|
||||
cachedExtensionsAsArray = null
|
||||
val result = if (newList.isEmpty()) {
|
||||
persistentListOf<ExtensionComponentAdapter>()
|
||||
adapters = if (newList.isEmpty()) {
|
||||
persistentListOf()
|
||||
}
|
||||
else {
|
||||
newList.map {
|
||||
ObjectComponentAdapter(instance = it, pluginDescriptor = extensionPointPluginDescriptor, loadingOrder = LoadingOrder.ANY)
|
||||
}.toPersistentList()
|
||||
adapters.mutate { list ->
|
||||
newList.mapTo(list) {
|
||||
ObjectComponentAdapter(instance = it, pluginDescriptor = extensionPointPluginDescriptor, loadingOrder = LoadingOrder.ANY)
|
||||
}
|
||||
}
|
||||
}
|
||||
adapters = result
|
||||
adaptersAreSorted = true
|
||||
|
||||
POINTS_IN_READONLY_MODE!!.add(this)
|
||||
@@ -761,8 +756,7 @@ sealed class ExtensionPointImpl<T : Any>(val name: String,
|
||||
}
|
||||
|
||||
fun clearUserCache() {
|
||||
val map = keyMapperToCacheRef.get()
|
||||
map?.clear()
|
||||
keyMapperToCache?.clear()
|
||||
}
|
||||
|
||||
private fun clearCache() {
|
||||
@@ -790,19 +784,20 @@ sealed class ExtensionPointImpl<T : Any>(val name: String,
|
||||
* `adapters` is modified directly without copying - method must be called only during start-up.
|
||||
*/
|
||||
@Synchronized
|
||||
fun registerExtensions(descriptors: List<ExtensionDescriptor>,
|
||||
fun registerExtensions(descriptors: PersistentList<ExtensionDescriptor>,
|
||||
pluginDescriptor: PluginDescriptor,
|
||||
listenerCallbacks: MutableList<in Runnable>?) {
|
||||
adaptersAreSorted = false
|
||||
|
||||
val oldSize = adapters.size
|
||||
for (extensionElement in descriptors) {
|
||||
if (extensionElement.os == null || componentManager.isSuitableForOs(extensionElement.os)) {
|
||||
adapters = adapters.add(createAdapter(descriptor = extensionElement,
|
||||
for (descriptor in descriptors) {
|
||||
if (descriptor.os == null || componentManager.isSuitableForOs(descriptor.os)) {
|
||||
adapters = adapters.add(createAdapter(descriptor = descriptor,
|
||||
pluginDescriptor = pluginDescriptor,
|
||||
componentManager = componentManager))
|
||||
}
|
||||
}
|
||||
|
||||
val newSize = adapters.size
|
||||
|
||||
clearCache()
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.extensions.ExtensionPoint
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import java.util.AbstractMap.SimpleImmutableEntry
|
||||
@@ -82,7 +83,7 @@ object ExtensionProcessingHelper {
|
||||
cache = prev
|
||||
}
|
||||
}
|
||||
return cache.get(key) ?: emptyList()
|
||||
return cache.get(key) ?: persistentListOf()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,9 +14,9 @@ internal class InterfaceExtensionPoint<T : Any>(
|
||||
dynamic: Boolean,
|
||||
private val hasAttributes: Boolean,
|
||||
) : ExtensionPointImpl<T>(name, className, pluginDescriptor, componentManager, clazz, dynamic) {
|
||||
public override fun createAdapter(descriptor: ExtensionDescriptor,
|
||||
pluginDescriptor: PluginDescriptor,
|
||||
componentManager: ComponentManager): ExtensionComponentAdapter {
|
||||
override fun createAdapter(descriptor: ExtensionDescriptor,
|
||||
pluginDescriptor: PluginDescriptor,
|
||||
componentManager: ComponentManager): ExtensionComponentAdapter {
|
||||
val implementationClassName = descriptor.implementation
|
||||
?: throw componentManager.createError(
|
||||
"Attribute \"implementation\" is not specified for \"$name\" extension",
|
||||
|
||||
@@ -249,7 +249,7 @@ object DynamicPlugins {
|
||||
}
|
||||
|
||||
val epNameToExtensions = module.epNameToExtensions
|
||||
if (epNameToExtensions != null) {
|
||||
if (!epNameToExtensions.isEmpty()) {
|
||||
doCheckExtensionsCanUnloadWithoutRestart(
|
||||
extensions = epNameToExtensions,
|
||||
descriptor = module,
|
||||
@@ -352,11 +352,8 @@ object DynamicPlugins {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun allowLoadUnloadSynchronously(module: IdeaPluginDescriptorImpl): Boolean {
|
||||
val extensions = (module.unsortedEpNameToExtensionElements.takeIf { it.isNotEmpty() } ?: module.appContainerDescriptor.extensions)
|
||||
if (extensions != null && !extensions.all {
|
||||
it.key == UIThemeProvider.EP_NAME.name ||
|
||||
it.key == BundledKeymapBean.EP_NAME.name
|
||||
}) {
|
||||
val extensions = (module.epNameToExtensions.takeIf { it.isNotEmpty() } ?: module.appContainerDescriptor.extensions)
|
||||
if (!extensions.all { it.key == UIThemeProvider.EP_NAME.name || it.key == BundledKeymapBean.EP_NAME.name }) {
|
||||
return false
|
||||
}
|
||||
return checkNoComponentsOrServiceOverrides(module) == null && module.actions.isEmpty()
|
||||
@@ -709,15 +706,20 @@ object DynamicPlugins {
|
||||
val appExtensionArea = app.extensionArea
|
||||
val priorityUnloadListeners = mutableListOf<Runnable>()
|
||||
val unloadListeners = mutableListOf<Runnable>()
|
||||
unregisterUnknownLevelExtensions(module.unsortedEpNameToExtensionElements, module, appExtensionArea, openedProjects,
|
||||
unregisterUnknownLevelExtensions(module.epNameToExtensions, module, appExtensionArea, openedProjects,
|
||||
priorityUnloadListeners, unloadListeners)
|
||||
for (epName in (module.appContainerDescriptor.extensions?.keys ?: emptySet())) {
|
||||
appExtensionArea.unregisterExtensions(epName, module, priorityUnloadListeners, unloadListeners)
|
||||
for (epName in module.appContainerDescriptor.extensions.keys) {
|
||||
appExtensionArea.unregisterExtensions(extensionPointName = epName,
|
||||
pluginDescriptor = module,
|
||||
priorityListenerCallbacks = priorityUnloadListeners,
|
||||
listenerCallbacks = unloadListeners)
|
||||
}
|
||||
for (epName in (module.projectContainerDescriptor.extensions?.keys ?: emptySet())) {
|
||||
for (epName in module.projectContainerDescriptor.extensions.keys) {
|
||||
for (project in openedProjects) {
|
||||
(project.extensionArea as ExtensionsAreaImpl).unregisterExtensions(epName, module, priorityUnloadListeners,
|
||||
unloadListeners)
|
||||
(project.extensionArea as ExtensionsAreaImpl).unregisterExtensions(extensionPointName = epName,
|
||||
pluginDescriptor = module,
|
||||
priorityListenerCallbacks = priorityUnloadListeners,
|
||||
listenerCallbacks = unloadListeners)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,15 +798,15 @@ object DynamicPlugins {
|
||||
private inline fun processExtensionPoints(pluginDescriptor: IdeaPluginDescriptorImpl,
|
||||
projects: List<Project>,
|
||||
processor: (points: List<ExtensionPointDescriptor>, area: ExtensionsAreaImpl) -> Unit) {
|
||||
pluginDescriptor.appContainerDescriptor.extensionPoints?.let {
|
||||
pluginDescriptor.appContainerDescriptor.extensionPoints.let {
|
||||
processor(it, ApplicationManager.getApplication().extensionArea as ExtensionsAreaImpl)
|
||||
}
|
||||
pluginDescriptor.projectContainerDescriptor.extensionPoints?.let { extensionPoints ->
|
||||
pluginDescriptor.projectContainerDescriptor.extensionPoints.let { extensionPoints ->
|
||||
for (project in projects) {
|
||||
processor(extensionPoints, project.extensionArea as ExtensionsAreaImpl)
|
||||
}
|
||||
}
|
||||
pluginDescriptor.moduleContainerDescriptor.extensionPoints?.let { extensionPoints ->
|
||||
pluginDescriptor.moduleContainerDescriptor.extensionPoints.let { extensionPoints ->
|
||||
for (project in projects) {
|
||||
for (module in ModuleManager.getInstance(project).modules) {
|
||||
processor(extensionPoints, module.extensionArea as ExtensionsAreaImpl)
|
||||
@@ -1300,7 +1302,7 @@ private fun doCheckExtensionsCanUnloadWithoutRestart(
|
||||
|
||||
private fun findPluginExtensionPoint(pluginDescriptor: IdeaPluginDescriptorImpl, epName: String): ExtensionPointDescriptor? {
|
||||
fun findContainerExtensionPoint(containerDescriptor: ContainerDescriptor): ExtensionPointDescriptor? {
|
||||
return containerDescriptor.extensionPoints?.find { it.nameEquals(epName, pluginDescriptor) }
|
||||
return containerDescriptor.extensionPoints.find { it.nameEquals(epName, pluginDescriptor) }
|
||||
}
|
||||
|
||||
return findContainerExtensionPoint(pluginDescriptor.appContainerDescriptor)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplaceNegatedIsEmptyWithIsNotEmpty", "ReplaceGetOrSet", "ReplacePutWithAssignment")
|
||||
@file:Suppress("ReplaceNegatedIsEmptyWithIsNotEmpty", "ReplaceGetOrSet", "ReplacePutWithAssignment", "LeakingThis")
|
||||
|
||||
package com.intellij.serviceContainer
|
||||
|
||||
@@ -424,9 +424,10 @@ abstract class ComponentManagerImpl(
|
||||
}
|
||||
|
||||
if (extensionPoints != null) {
|
||||
containerDescriptor.extensionPoints?.let {
|
||||
createExtensionPoints(points = it, componentManager = this, result = extensionPoints, pluginDescriptor = module)
|
||||
}
|
||||
createExtensionPoints(points = containerDescriptor.extensionPoints,
|
||||
componentManager = this,
|
||||
result = extensionPoints,
|
||||
pluginDescriptor = module)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -499,7 +500,7 @@ abstract class ComponentManagerImpl(
|
||||
registerComponents2(pluginDescriptor, containerDescriptor, headless)
|
||||
return
|
||||
}
|
||||
for (descriptor in (containerDescriptor.components ?: return)) {
|
||||
for (descriptor in (containerDescriptor.components)) {
|
||||
var implementationClassName = descriptor.implementationClass
|
||||
if (headless && descriptor.headlessImplementationClass != null) {
|
||||
if (descriptor.headlessImplementationClass.isEmpty()) {
|
||||
@@ -560,16 +561,15 @@ abstract class ComponentManagerImpl(
|
||||
private fun registerComponents2Inner(pluginDescriptor: IdeaPluginDescriptor,
|
||||
containerDescriptor: ContainerDescriptor,
|
||||
headless: Boolean) {
|
||||
val configs = containerDescriptor.components ?: return
|
||||
val components = containerDescriptor.components
|
||||
if (components.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val pluginClassLoader = pluginDescriptor.pluginClassLoader
|
||||
val registrationScope = if (pluginClassLoader is PluginAwareClassLoader) {
|
||||
pluginClassLoader.pluginCoroutineScope
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
val registrationScope = if (pluginClassLoader is PluginAwareClassLoader) pluginClassLoader.pluginCoroutineScope else null
|
||||
val registrar = componentContainer.startRegistration(registrationScope)
|
||||
for (descriptor in configs) {
|
||||
for (descriptor in components) {
|
||||
if (descriptor.os != null && !isSuitableForOs(descriptor.os)) {
|
||||
continue
|
||||
}
|
||||
@@ -960,26 +960,28 @@ abstract class ComponentManagerImpl(
|
||||
LOG.error("$key it is a service, use getService instead of getComponent")
|
||||
}
|
||||
|
||||
if (adapter is BaseComponentAdapter) {
|
||||
check(!useInstanceContainer)
|
||||
if (parent != null && adapter.componentManager !== this) {
|
||||
LOG.error("getComponent must be called on appropriate container (current: $this, expected: ${adapter.componentManager})")
|
||||
}
|
||||
when (adapter) {
|
||||
is BaseComponentAdapter -> {
|
||||
check(!useInstanceContainer)
|
||||
if (parent != null && adapter.componentManager !== this) {
|
||||
LOG.error("getComponent must be called on appropriate container (current: $this, expected: ${adapter.componentManager})")
|
||||
}
|
||||
|
||||
if (containerState.get() == ContainerState.DISPOSE_COMPLETED) {
|
||||
adapter.throwAlreadyDisposedError(this)
|
||||
if (containerState.get() == ContainerState.DISPOSE_COMPLETED) {
|
||||
adapter.throwAlreadyDisposedError(this)
|
||||
}
|
||||
return adapter.getInstance(adapter.componentManager, key)
|
||||
}
|
||||
is HolderAdapter -> {
|
||||
check(useInstanceContainer)
|
||||
// TODO asserts
|
||||
val holder = adapter.holder
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return holder.getOrCreateInstanceBlocking(key.name, key) as T
|
||||
}
|
||||
else -> {
|
||||
return null
|
||||
}
|
||||
return adapter.getInstance(adapter.componentManager, key)
|
||||
}
|
||||
else if (adapter is HolderAdapter) {
|
||||
check(useInstanceContainer)
|
||||
// TODO asserts
|
||||
val holder = adapter.holder
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return holder.getOrCreateInstanceBlocking(key.name, key) as T
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1131,7 +1133,7 @@ abstract class ComponentManagerImpl(
|
||||
return messageBus
|
||||
}
|
||||
|
||||
@Suppress("RetrievingService")
|
||||
@Suppress("RetrievingService", "SimplifiableServiceRetrieving")
|
||||
messageBus = getApplication()!!.getService(MessageBusFactory::class.java).createMessageBus(this, parent?.messageBus) as MessageBusImpl
|
||||
if (StartUpMeasurer.isMeasuringPluginStartupCosts()) {
|
||||
messageBus.setMessageDeliveryListener { topic, messageName, handler, duration ->
|
||||
|
||||
@@ -46,10 +46,9 @@ internal class CollectFUStatisticsAction : GotoActionBase(), DumbAware {
|
||||
override fun gotoActionPerformed(e: AnActionEvent) {
|
||||
val project = e.project ?: return
|
||||
|
||||
val projectCollectors = UsageCollectors.PROJECT_EP_NAME.extensionList
|
||||
val applicationCollectors = UsageCollectors.APPLICATION_EP_NAME.extensionList
|
||||
|
||||
val collectors = (projectCollectors + applicationCollectors).map(UsageCollectorBean::getCollector)
|
||||
val collectors = (UsageCollectors.PROJECT_EP_NAME.lazySequence() + UsageCollectors.APPLICATION_EP_NAME.lazySequence())
|
||||
.map(UsageCollectorBean::getCollector)
|
||||
.toList()
|
||||
|
||||
val ids = collectors.mapTo(HashMultiset.create()) { it.group.id }
|
||||
val items = collectors
|
||||
|
||||
@@ -41,9 +41,11 @@ object UsageCollectors {
|
||||
}
|
||||
|
||||
internal fun getProjectCollectors(invoker: UsagesCollectorConsumer): Collection<ProjectUsagesCollector> {
|
||||
if (isCalledFromPlugin(invoker)) return emptyList()
|
||||
if (isCalledFromPlugin(invoker)) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return PROJECT_EP_NAME.extensions.asSequence()
|
||||
return PROJECT_EP_NAME.extensionList.asSequence()
|
||||
.map { it.collector as ProjectUsagesCollector }
|
||||
.filter { isValidCollector(it) }
|
||||
.toList()
|
||||
|
||||
Reference in New Issue
Block a user