diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinCompositeProviderFactory.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinCompositeProviderFactory.kt
new file mode 100644
index 00000000000..4e204e81bf0
--- /dev/null
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinCompositeProviderFactory.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010-2023 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.analysis.providers.impl
+
+import org.jetbrains.kotlin.analysis.providers.impl.util.mergeOnly
+
+/**
+ * A composite provider should only contain providers of the same base type as the composite provider itself, so implementations of
+ * [KotlinCompositeProvider] should always be a subtype of their type argument [P].
+ */
+public interface KotlinCompositeProvider
{
+ public val providers: List
+}
+
+/**
+ * [KotlinCompositeProviderFactory] is used by various composite providers to share code related to provider creation and flattening.
+ */
+public class KotlinCompositeProviderFactory
(
+ private val emptyProvider: P,
+ private val composeProviders: (List
) -> P,
+) {
+ public fun create(providers: List
): P = when (providers.size) {
+ 0 -> emptyProvider
+ 1 -> providers.single()
+ else -> composeProviders(providers)
+ }
+
+ public fun createFlattened(providers: List
): P =
+ create(if (providers.size > 1) flatten(providers) else providers)
+
+ public fun flatten(providers: List
): List
=
+ providers.flatMap { provider ->
+ // `KotlinCompositeProvider
` should always be a provider of type `P` itself, so the cast is legal. Still, suppressing the
+ // error is unfortunate, but to properly type this, we'd need to be able to restrict `KotlinCompositeProvider
` to be a
+ // subtype of `P`, which is not possible in Kotlin.
+ @Suppress("UNCHECKED_CAST")
+ when (provider) {
+ is KotlinCompositeProvider<*> -> (provider as KotlinCompositeProvider
).providers
+ else -> listOf(provider)
+ }
+ }
+}
+
+/**
+ * Uses the given [factory] to merge all providers of type [T] with the given [mergeTargets] strategy. Other providers (not of type [T]) are
+ * added to the resulting composite provider unmerged.
+ */
+public inline fun
List
.mergeSpecificProviders(
+ factory: KotlinCompositeProviderFactory
,
+ crossinline mergeTargets: (List) -> P,
+): P {
+ // We should flatten providers before merging so that the merger has access to all individual providers, and also after merging because
+ // composite providers may be created by the merger.
+ return factory.createFlattened(factory.flatten(this).mergeOnly<_, T> { mergeTargets(it) })
+}
diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinDeclarationProviderMergerBase.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinDeclarationProviderMergerBase.kt
deleted file mode 100644
index a52550ed03e..00000000000
--- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinDeclarationProviderMergerBase.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2010-2023 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.analysis.providers.impl
-
-import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
-import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderMerger
-import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.CompositeKotlinDeclarationProvider
-
-public abstract class KotlinDeclarationProviderMergerBase : KotlinDeclarationProviderMerger() {
- override fun mergeDeclarationProviders(declarationProviders: List): KotlinDeclarationProvider {
- // We should flatten declaration providers before merging so that the merger has access to all declaration providers, and also after
- // merging because composite declaration providers may be created by the merger.
- return CompositeKotlinDeclarationProvider.createFlattened(
- mergeToList(
- CompositeKotlinDeclarationProvider.flatten(declarationProviders)
- )
- )
- }
-
- protected abstract fun mergeToList(declarationProviders: List): List
-}
diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt
index 8998dc638a0..dbd62eb3fe8 100644
--- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt
@@ -20,7 +20,6 @@ import com.intellij.psi.stubs.StubElement
import com.intellij.util.indexing.FileContent
import com.intellij.util.indexing.FileContentImpl
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProvider
-import java.util.concurrent.ConcurrentHashMap
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInDecompiler
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInFileType
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
@@ -28,8 +27,9 @@ import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinClsStubBuilder
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory
+import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderMerger
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
-import org.jetbrains.kotlin.analysis.providers.impl.util.mergeOnly
+import org.jetbrains.kotlin.analysis.providers.impl.declarationProviders.CompositeKotlinDeclarationProvider
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.name.*
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.*
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
+import java.util.concurrent.ConcurrentHashMap
public class KotlinStaticDeclarationProvider internal constructor(
private val index: KotlinStaticDeclarationIndex,
@@ -373,9 +374,9 @@ public class KotlinFakeClsStubsCache {
}
}
-public class KotlinStaticDeclarationProviderMerger(private val project: Project) : KotlinDeclarationProviderMergerBase() {
- override fun mergeToList(declarationProviders: List): List =
- declarationProviders.mergeOnly<_, KotlinStaticDeclarationProvider> { providers ->
+public class KotlinStaticDeclarationProviderMerger(private val project: Project) : KotlinDeclarationProviderMerger() {
+ override fun mergeDeclarationProviders(declarationProviders: List): KotlinDeclarationProvider =
+ declarationProviders.mergeSpecificProviders<_, KotlinStaticDeclarationProvider>(CompositeKotlinDeclarationProvider.factory) { providers ->
val combinedScope = GlobalSearchScope.union(providers.map { it.scope })
project.createDeclarationProvider(combinedScope, module = null).apply {
check(this is KotlinStaticDeclarationProvider) {
diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt
index 298b319b79a..8472763b370 100644
--- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.analysis.providers.impl.declarationProviders
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
+import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProvider
+import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProviderFactory
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
@@ -13,8 +15,8 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
public class CompositeKotlinDeclarationProvider private constructor(
- public val providers: List
-) : KotlinDeclarationProvider() {
+ override val providers: List
+) : KotlinDeclarationProvider(), KotlinCompositeProvider {
override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? {
return providers.firstNotNullOfOrNull { it.getClassLikeDeclarationByClassId(classId) }
}
@@ -68,23 +70,11 @@ public class CompositeKotlinDeclarationProvider private constructor(
}
public companion object {
- public fun create(providers: List): KotlinDeclarationProvider {
- return when (providers.size) {
- 0 -> EmptyKotlinDeclarationProvider
- 1 -> providers.single()
- else -> CompositeKotlinDeclarationProvider(providers)
- }
- }
+ public val factory: KotlinCompositeProviderFactory = KotlinCompositeProviderFactory(
+ EmptyKotlinDeclarationProvider,
+ ::CompositeKotlinDeclarationProvider,
+ )
- public fun createFlattened(providers: List): KotlinDeclarationProvider =
- create(if (providers.size > 1) flatten(providers) else providers)
-
- public fun flatten(providers: List): List =
- providers.flatMap { provider ->
- when (provider) {
- is CompositeKotlinDeclarationProvider -> provider.providers
- else -> listOf(provider)
- }
- }
+ public fun create(providers: List): KotlinDeclarationProvider = factory.create(providers)
}
}