diff --git a/platform/core-impl/src/com/intellij/ide/plugins/ContainerDescriptor.kt b/platform/core-impl/src/com/intellij/ide/plugins/ContainerDescriptor.kt index 862d851febd2..972a93c3bcab 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/ContainerDescriptor.kt +++ b/platform/core-impl/src/com/intellij/ide/plugins/ContainerDescriptor.kt @@ -23,7 +23,7 @@ class ContainerDescriptor { @JvmField var extensionPoints: PersistentList = persistentListOf() @Transient var distinctExtensionPointCount: Int = -1 - @Transient @JvmField var extensions: Map> = Java11Shim.INSTANCE.emptyMap() + @Transient @JvmField var extensions: Map> = Java11Shim.INSTANCE.mapOf() fun addService(serviceDescriptor: ServiceDescriptor) { if (_services == null) { diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.kt b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.kt index 0e6a5d3ee662..ba015034e1ea 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.kt +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/ExtensionPointImpl.kt @@ -15,7 +15,10 @@ import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.util.Disposer import com.intellij.util.Java11Shim import com.intellij.util.ThreeState -import kotlinx.collections.immutable.* +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.mutate +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.TestOnly @@ -193,8 +196,10 @@ sealed class ExtensionPointImpl(@JvmField val name: String, } else { message += " (adapter=$adapter)" - throw componentManager.createError(message, null, adapter.pluginDescriptor.pluginId, - persistentHashMapOf("threadDump" to ThreadDumper.dumpThreadsToString())) + throw componentManager.createError(/* message = */ message, + /* error = */ null, + /* pluginId = */ adapter.pluginDescriptor.pluginId, + /* attachments = */ Java11Shim.INSTANCE.mapOf("threadDump", ThreadDumper.dumpThreadsToString())) } } @@ -347,15 +352,15 @@ sealed class ExtensionPointImpl(@JvmField val name: String, listeners = listeners, result = null, duplicates = null, - extensionClassForCheck = extensionClass, adapters = adapters) ?: return Java11Shim.INSTANCE.listOf() + extensionClassForCheck = extensionClass, + adapters = adapters) ?: return Java11Shim.INSTANCE.listOf() return Java11Shim.INSTANCE.listOf(extension) } val duplicates = if (this is BeanExtensionPoint<*>) null else Collections.newSetFromMap(IdentityHashMap(totalSize)) val listeners = listeners - @Suppress("UNCHECKED_CAST") - val result = java.lang.reflect.Array.newInstance(extensionClass, totalSize) as Array + val result = arrayOfNulls(totalSize) var index = 0 for (adapter in adapters) { val extension = processAdapter(adapter = adapter, @@ -368,22 +373,13 @@ sealed class ExtensionPointImpl(@JvmField val name: String, result[index++] = extension } } - - // do not count ProcessCanceledException as a valid action to measure (later special category can be introduced if needed) - if (result.size == index) { - return Java11Shim.INSTANCE.listOf(result) - } - else { - @Suppress("UNCHECKED_CAST") - val newResult = java.lang.reflect.Array.newInstance(extensionClass, index) as Array - System.arraycopy(result, 0, newResult, 0, index) - return Java11Shim.INSTANCE.listOf(newResult) - } + @Suppress("UNCHECKED_CAST") + return Java11Shim.INSTANCE.listOf(result, index) as List } private fun processAdapter(adapter: ExtensionComponentAdapter, listeners: List>?, - result: Array?, + result: Array<*>?, duplicates: MutableSet?, extensionClassForCheck: Class, adapters: List): T? { diff --git a/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.kt b/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.kt index 2f55aa697c1f..d38dda90d3ea 100644 --- a/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.kt +++ b/platform/extensions/src/com/intellij/openapi/extensions/impl/InterfaceExtensionPoint.kt @@ -25,10 +25,10 @@ internal class InterfaceExtensionPoint( if (hasAttributes) { val customAttributes = if (descriptor.hasExtraAttributes) { - descriptor.element?.attributes ?: Java11Shim.INSTANCE.emptyMap() + descriptor.element?.attributes ?: Java11Shim.INSTANCE.mapOf() } else { - Java11Shim.INSTANCE.emptyMap() + Java11Shim.INSTANCE.mapOf() } return AdapterWithCustomAttributes(implementationClassName = implementationClassName, pluginDescriptor = pluginDescriptor, diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java index e3a0f86ded76..149d21fb73c9 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java @@ -44,7 +44,7 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModelE private final List myContributors; protected ContributorsBasedGotoByModel(@NotNull Project project, ChooseByNameContributor @NotNull [] contributors) { - this(project, Java11Shim.INSTANCE.listOf(contributors)); + this(project, List.of(contributors)); } protected ContributorsBasedGotoByModel(@NotNull Project project, @NotNull List contributors) { diff --git a/platform/platform-impl/src/com/intellij/platform/ide/bootstrap/Java11ShimImpl.kt b/platform/platform-impl/src/com/intellij/platform/ide/bootstrap/Java11ShimImpl.kt new file mode 100644 index 000000000000..58627fe2e648 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/platform/ide/bootstrap/Java11ShimImpl.kt @@ -0,0 +1,60 @@ +// 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.platform.ide.bootstrap + +import com.intellij.concurrency.ConcurrentCollectionFactory +import com.intellij.util.Java11Shim +import com.intellij.util.containers.ConcurrentLongObjectMap +import org.jetbrains.annotations.VisibleForTesting + +@VisibleForTesting +@Suppress("ReplaceJavaStaticMethodWithKotlinAnalog") +class Java11ShimImpl : Java11Shim() { + override fun copyOf(map: Map): Map = java.util.Map.copyOf(map) + + override fun mapOf(k: K, v: V): Map = java.util.Map.of(k, v) + + override fun copyOf(collection: Collection): Set = java.util.Set.copyOf(collection) + + override fun mapOf(): Map = java.util.Map.of() + + override fun mapOf(k: K, v: V, k2: K, v2: V): Map = java.util.Map.of(k, v, k2, v2) + + override fun createConcurrentLongObjectMap(): ConcurrentLongObjectMap { + return ConcurrentCollectionFactory.createConcurrentLongObjectMap() + } + + override fun listOf(): List = java.util.List.of() + + override fun listOf(element: E): List = java.util.List.of(element) + + override fun listOf(e1: E, e2: E): List = java.util.List.of(e1, e2) + + override fun listOf(array: Array, size: Int): List { + return when (size) { + 1 -> java.util.List.of(array[0]) + 2 -> java.util.List.of(array[0], array[1]) + 3 -> java.util.List.of(array[0], array[1], array[2]) + 4 -> java.util.List.of(array[0], array[1], array[2], array[3]) + 5 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4]) + 6 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5]) + 7 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6]) + 8 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7]) + 9 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8]) + 10 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8], array[9]) + 11 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8], array[9], array[10]) + 12 -> java.util.List.of(array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8], array[9], array[10], + array[11]) + else -> { + if (array.size == size) { + java.util.List.of(*array) + } + else { + val newResult = arrayOfNulls(size) + System.arraycopy(array, 0, newResult, 0, size) + @Suppress("UNCHECKED_CAST", "KotlinConstantConditions") + return java.util.List.of(*newResult) as List + } + } + } + } +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/platform/ide/bootstrap/main.kt b/platform/platform-impl/src/com/intellij/platform/ide/bootstrap/main.kt index 30249044c637..1ace172acf2b 100644 --- a/platform/platform-impl/src/com/intellij/platform/ide/bootstrap/main.kt +++ b/platform/platform-impl/src/com/intellij/platform/ide/bootstrap/main.kt @@ -6,7 +6,6 @@ package com.intellij.platform.ide.bootstrap import com.intellij.BundleBase import com.intellij.accessibility.enableScreenReaderSupportIfNecessary -import com.intellij.concurrency.ConcurrentCollectionFactory import com.intellij.diagnostic.* import com.intellij.ide.* import com.intellij.ide.bootstrap.* @@ -35,7 +34,6 @@ import com.intellij.ui.mac.screenmenu.Menu import com.intellij.ui.scale.JBUIScale import com.intellij.ui.svg.SvgCacheManager import com.intellij.util.* -import com.intellij.util.containers.ConcurrentLongObjectMap import com.intellij.util.containers.SLRUMap import com.intellij.util.io.* import com.intellij.util.lang.ZipFilePool @@ -44,7 +42,6 @@ import io.opentelemetry.sdk.OpenTelemetrySdkBuilder import kotlinx.coroutines.* import kotlinx.coroutines.debug.internal.DebugProbesImpl import org.jetbrains.annotations.ApiStatus.Internal -import org.jetbrains.annotations.VisibleForTesting import java.awt.Toolkit import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType @@ -725,24 +722,3 @@ interface AppStarter { fun importFinished(newConfigDir: Path) {} } -@VisibleForTesting -@Suppress("ReplaceJavaStaticMethodWithKotlinAnalog") -class Java11ShimImpl : Java11Shim() { - override fun copyOf(map: Map) = java.util.Map.copyOf(map) - - override fun mapOf(k: K, v: V): Map = java.util.Map.of(k, v) - - override fun copyOf(collection: Collection): Set = java.util.Set.copyOf(collection) - - override fun emptyMap(): Map = java.util.Map.of() - - override fun createConcurrentLongObjectMap(): ConcurrentLongObjectMap { - return ConcurrentCollectionFactory.createConcurrentLongObjectMap() - } - - override fun listOf(): List = java.util.List.of() - - override fun listOf(element: E): List = java.util.List.of(element) - - override fun listOf(array: Array): List = java.util.List.of(*array) -} diff --git a/platform/util/src/com/intellij/util/Java11Shim.kt b/platform/util/src/com/intellij/util/Java11Shim.kt index ca638938326d..38ac04a10415 100644 --- a/platform/util/src/com/intellij/util/Java11Shim.kt +++ b/platform/util/src/com/intellij/util/Java11Shim.kt @@ -1,4 +1,6 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +@file:Suppress("ReplacePutWithAssignment", "ReplaceJavaStaticMethodWithKotlinAnalog") + package com.intellij.util import com.intellij.util.containers.ConcurrentLongObjectMap @@ -15,19 +17,28 @@ abstract class Java11Shim { override fun mapOf(k: K, v: V): Map = Collections.singletonMap(k, v) + override fun mapOf(k: K, v: V, k2: K, v2: V): Map { + val map = HashMap(2) + map.put(k, v) + map.put(k2, v2) + return map + } + override fun copyOf(collection: Collection): Set = Collections.unmodifiableSet(HashSet(collection)) override fun createConcurrentLongObjectMap(): ConcurrentLongObjectMap { return ConcurrentLongObjectHashMap() } - override fun emptyMap(): Map = Collections.emptyMap() + override fun mapOf(): Map = Collections.emptyMap() override fun listOf(): List = Collections.emptyList() override fun listOf(element: E): List = Collections.singletonList(element) - override fun listOf(array: Array) = array.asList() + override fun listOf(e1: E, e2: E): List = Arrays.asList(e1, e2) + + override fun listOf(array: Array, size: Int) = if (array.size == size) array.asList() else array.asList().subList(0, size) } } @@ -35,7 +46,9 @@ abstract class Java11Shim { abstract fun mapOf(k: K, v: V): Map - abstract fun emptyMap(): Map + abstract fun mapOf(k: K, v: V, k2: K, v2: V): Map + + abstract fun mapOf(): Map abstract fun copyOf(collection: Collection): Set @@ -43,7 +56,9 @@ abstract class Java11Shim { abstract fun listOf(element: E): List - abstract fun listOf(array: Array): List + abstract fun listOf(e1: E, e2: E): List + + abstract fun listOf(array: Array, size: Int): List abstract fun createConcurrentLongObjectMap(): ConcurrentLongObjectMap } diff --git a/platform/util/src/com/intellij/util/containers/util.kt b/platform/util/src/com/intellij/util/containers/util.kt index 3ebf51346975..6f7aad278410 100644 --- a/platform/util/src/com/intellij/util/containers/util.kt +++ b/platform/util/src/com/intellij/util/containers/util.kt @@ -1,7 +1,10 @@ // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +@file:Suppress("ReplacePutWithAssignment") + package com.intellij.util.containers import com.intellij.openapi.diagnostic.Logger +import com.intellij.util.Java11Shim import com.intellij.util.SmartList import com.intellij.util.lang.CompoundRuntimeException import org.jetbrains.annotations.ApiStatus.Experimental @@ -18,6 +21,62 @@ fun MutableMap>.remove(key: K, value: V) { } } +/** + * Do not use it for a concurrent map (doesn't make sense). + */ +@Internal +@Experimental +fun Map.without(key: K): Map { + if (!containsKey(key)) { + return this + } + else if (size == 1) { + return Java11Shim.INSTANCE.mapOf() + } + else { + val result = HashMap(size, 0.5f) + result.putAll(this) + result.remove(key) + return result + } +} + +/** + * Do not use it for a concurrent map (doesn't make sense). + */ +@Internal +@Experimental +fun Map.with(key: K, value: V): Map { + val size = size + if (size == 0) { + return Java11Shim.INSTANCE.mapOf(key, value) + } + + // do not use a java-immutable map, same as ours UnmodifiableHashMap and fastutil it uses open addressing hashing + // - https://stackoverflow.com/a/16303438 + val result = HashMap(size + 1, 0.5f) + result.putAll(this) + result.put(key, value) + return result +} + +/** + * Do not use it for a concurrent map (doesn't make sense). + */ +@Internal +@Experimental +fun Map.withAll(otherMap: Map): Map { + val totalSize = size + otherMap.size + if (totalSize == 0) { + return Java11Shim.INSTANCE.mapOf() + } + + val result = HashMap(totalSize, 0.5f) + result.putAll(this) + result.putAll(otherMap) + return result +} + fun MutableMap>.putValue(key: K, value: V) { val list = get(key) if (list == null) {