diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinComposableProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinComposableProvider.kt
new file mode 100644
index 00000000000..968b34f52c6
--- /dev/null
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinComposableProvider.kt
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+/**
+ * A marker interface for a provider that can be composed, i.e. multiple instances of the same provider can be composed into a single
+ * provider.
+ *
+ * Composable providers share certain traits: There is a notion of a sequentially composed [KotlinCompositeProvider] of that kind, and there
+ * is usually a merge function which allows to create a single provider from a list of providers. Mergers of composable providers may
+ * produce a merged provider which is more efficient than the naive sequential composite provider.
+ *
+ * @see KotlinDeclarationProvider
+ * @see KotlinPackageProvider
+ */
+public interface KotlinComposableProvider
+
+/**
+ * A [KotlinCompositeProvider] is the sequential composition of a specific kind of composable provider [P].
+ *
+ * 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]. (This is not enforceable in the Kotlin type system.)
+ */
+public interface KotlinCompositeProvider
: KotlinComposableProvider {
+ public val providers: List
+}
+
+public interface KotlinComposableProviderMerger
{
+ /**
+ * Merges the given [providers] into a single provider. When possible, mergers will try to create a provider that is more efficient
+ * compared to the naive sequential composite provider. Not all providers might be mergeable, or there might be multiple separate sets
+ * of providers that can be merged individually, so the resulting provider may be a composite provider.
+ */
+ public fun merge(providers: List
): P
+}
diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt
index e847e7ecd49..8fd660dc5f8 100644
--- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt
@@ -15,10 +15,11 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
/**
- * A declaration provider for a given scope. Can be created via [KotlinDeclarationProviderFactory].
- * May be called frequently, so for implementations it is better to cache results.
+ * A declaration provider for a given scope. It can be created via [KotlinDeclarationProviderFactory].
+ *
+ * It may be called frequently, so implementations should cache the results.
*/
-public abstract class KotlinDeclarationProvider {
+public abstract class KotlinDeclarationProvider : KotlinComposableProvider {
public abstract fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration?
public abstract fun getAllClassesByClassId(classId: ClassId): Collection
@@ -66,15 +67,7 @@ public abstract class KotlinDeclarationProviderFactory {
* [createDeclarationProvider]. [KotlinDeclarationProviderMerger] should implement proper merging logic that takes these concerns into
* account.
*/
-public abstract class KotlinDeclarationProviderMerger {
- /**
- * Merges [declarationProviders] if possible, creating a combined declaration provider that should be more efficient compared to calling
- * separate declaration providers. Not all given declaration providers might be mergeable, or there might be multiple separate sets of
- * declaration providers which can be merged individually, so the resulting declaration provider may be a composite Kotlin declaration
- * provider.
- */
- public abstract fun mergeDeclarationProviders(declarationProviders: List): KotlinDeclarationProvider
-
+public abstract class KotlinDeclarationProviderMerger : KotlinComposableProviderMerger {
public companion object {
public fun getInstance(project: Project): KotlinDeclarationProviderMerger =
project.getService(KotlinDeclarationProviderMerger::class.java)
@@ -85,4 +78,4 @@ public fun Project.createDeclarationProvider(scope: GlobalSearchScope, module: K
KotlinDeclarationProviderFactory.getInstance(this).createDeclarationProvider(scope, module)
public fun Project.mergeDeclarationProviders(declarationProviders: List): KotlinDeclarationProvider =
- KotlinDeclarationProviderMerger.getInstance(this).mergeDeclarationProviders(declarationProviders)
+ KotlinDeclarationProviderMerger.getInstance(this).merge(declarationProviders)
diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt
index 61c46d00cce..63f8766db9e 100644
--- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinPackageProvider.kt
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform
* Provides information about packages that are visible to Kotlin in the given scope. Can be constructed via [KotlinPackageProviderFactory].
* The FIR compiler calls [doesKotlinOnlyPackageExist] very often, so the implementations should consider caching the results.
*/
-public abstract class KotlinPackageProvider {
+public abstract class KotlinPackageProvider : KotlinComposableProvider {
/**
* Checks if a package with given [FqName] exists in current [GlobalSearchScope] with a view from a given [platform].
*
@@ -82,13 +82,7 @@ public abstract class KotlinPackageProviderFactory {
* Package providers should not be naively merged by combining scopes and calling [createPackageProvider], because there may be additional
* package providers which do not operate based on scopes (e.g. resolve extension package providers).
*/
-public abstract class KotlinPackageProviderMerger {
- /**
- * Merges [packageProviders] if possible, creating a combined package provider that should be more efficient compared to invoking
- * separate package providers.
- */
- public abstract fun mergePackageProviders(packageProviders: List): KotlinPackageProvider
-
+public abstract class KotlinPackageProviderMerger : KotlinComposableProviderMerger {
public companion object {
public fun getInstance(project: Project): KotlinPackageProviderMerger = project.getService(KotlinPackageProviderMerger::class.java)
}
@@ -99,4 +93,4 @@ public fun Project.createPackageProvider(searchScope: GlobalSearchScope): Kotlin
.createPackageProvider(searchScope)
public fun Project.mergePackageProviders(packageProviders: List): KotlinPackageProvider =
- KotlinPackageProviderMerger.getInstance(this).mergePackageProviders(packageProviders)
+ KotlinPackageProviderMerger.getInstance(this).merge(packageProviders)
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
index 4e204e81bf0..8763135247d 100644
--- 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
@@ -5,20 +5,14 @@
package org.jetbrains.kotlin.analysis.providers.impl
+import org.jetbrains.kotlin.analysis.providers.KotlinComposableProvider
+import org.jetbrains.kotlin.analysis.providers.KotlinCompositeProvider
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].
+ * [KotlinCompositeProviderFactory] is used by various [KotlinCompositeProvider]s to share code related to provider creation and flattening.
*/
-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
(
+public class KotlinCompositeProviderFactory
(
private val emptyProvider: P,
private val composeProviders: (List
) -> P,
) {
@@ -48,7 +42,7 @@ public class KotlinCompositeProviderFactory
(
* 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(
+public inline fun
List
.mergeSpecificProviders(
factory: KotlinCompositeProviderFactory
,
crossinline mergeTargets: (List) -> P,
): P {
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 dbd62eb3fe8..f8efbfa2c57 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
@@ -375,9 +375,9 @@ public class KotlinFakeClsStubsCache {
}
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 })
+ override fun merge(providers: List): KotlinDeclarationProvider =
+ providers.mergeSpecificProviders<_, KotlinStaticDeclarationProvider>(CompositeKotlinDeclarationProvider.factory) { targetProviders ->
+ val combinedScope = GlobalSearchScope.union(targetProviders.map { it.scope })
project.createDeclarationProvider(combinedScope, module = null).apply {
check(this is KotlinStaticDeclarationProvider) {
"`KotlinStaticDeclarationProvider` can only be merged into a combined declaration provider of the same type."
diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt
index 275bb6abdc2..0597b772222 100644
--- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticPackageProvider.kt
@@ -54,9 +54,9 @@ public class KotlinStaticPackageProviderFactory(
}
public class KotlinStaticPackageProviderMerger(private val project: Project) : KotlinPackageProviderMerger() {
- override fun mergePackageProviders(packageProviders: List): KotlinPackageProvider =
- packageProviders.mergeSpecificProviders<_, KotlinStaticPackageProvider>(CompositeKotlinPackageProvider.factory) { providers ->
- val combinedScope = GlobalSearchScope.union(providers.map { it.scope })
+ override fun merge(providers: List): KotlinPackageProvider =
+ providers.mergeSpecificProviders<_, KotlinStaticPackageProvider>(CompositeKotlinPackageProvider.factory) { targetProviders ->
+ val combinedScope = GlobalSearchScope.union(targetProviders.map { it.scope })
project.createPackageProvider(combinedScope).apply {
check(this is KotlinStaticPackageProvider) {
"`${KotlinStaticPackageProvider::class.simpleName}` can only be merged into a combined package provider of the same type."
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 8472763b370..de023ba7773 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
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.analysis.providers.impl.declarationProviders
+import org.jetbrains.kotlin.analysis.providers.KotlinCompositeProvider
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
diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/packageProviders/CompositeKotlinPackageProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/packageProviders/CompositeKotlinPackageProvider.kt
index ea511ee506d..9e17fba8e8c 100644
--- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/packageProviders/CompositeKotlinPackageProvider.kt
+++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/packageProviders/CompositeKotlinPackageProvider.kt
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.analysis.providers.impl.packageProviders
+import org.jetbrains.kotlin.analysis.providers.KotlinCompositeProvider
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
-import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProvider
import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProviderFactory
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name