[AA] Add abstraction for composable Kotlin providers
This further improves the `KotlinCompositeProvider` abstraction: - Pulling the abstraction's interfaces outside the `impl` package allows us to write consolidated documentation on composable Kotlin providers. - The addition of `KotlinComposableProvider` allows more specific bounds for the type parameters of `KotlinCompositeProvider` and `KotlinCompositeProviderFactory`. It also clarifies to Analysis API implementors which providers can be composed at all, as providers like `KotlinDeclarationProvider` extend this interface. - `KotlinComposableProviderMerger` provides a unified interface for provider mergers. ^KT-61791
This commit is contained in:
committed by
Space Team
parent
c289da6cf3
commit
a62ac940c4
+38
@@ -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<P : KotlinComposableProvider> : KotlinComposableProvider {
|
||||||
|
public val providers: List<P>
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface KotlinComposableProviderMerger<P : KotlinComposableProvider> {
|
||||||
|
/**
|
||||||
|
* 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>): P
|
||||||
|
}
|
||||||
+6
-13
@@ -15,10 +15,11 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A declaration provider for a given scope. Can be created via [KotlinDeclarationProviderFactory].
|
* A declaration provider for a given scope. It can be created via [KotlinDeclarationProviderFactory].
|
||||||
* May be called frequently, so for implementations it is better to cache results.
|
*
|
||||||
|
* 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 getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration?
|
||||||
|
|
||||||
public abstract fun getAllClassesByClassId(classId: ClassId): Collection<KtClassOrObject>
|
public abstract fun getAllClassesByClassId(classId: ClassId): Collection<KtClassOrObject>
|
||||||
@@ -66,15 +67,7 @@ public abstract class KotlinDeclarationProviderFactory {
|
|||||||
* [createDeclarationProvider]. [KotlinDeclarationProviderMerger] should implement proper merging logic that takes these concerns into
|
* [createDeclarationProvider]. [KotlinDeclarationProviderMerger] should implement proper merging logic that takes these concerns into
|
||||||
* account.
|
* account.
|
||||||
*/
|
*/
|
||||||
public abstract class KotlinDeclarationProviderMerger {
|
public abstract class KotlinDeclarationProviderMerger : KotlinComposableProviderMerger<KotlinDeclarationProvider> {
|
||||||
/**
|
|
||||||
* 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>): KotlinDeclarationProvider
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public fun getInstance(project: Project): KotlinDeclarationProviderMerger =
|
public fun getInstance(project: Project): KotlinDeclarationProviderMerger =
|
||||||
project.getService(KotlinDeclarationProviderMerger::class.java)
|
project.getService(KotlinDeclarationProviderMerger::class.java)
|
||||||
@@ -85,4 +78,4 @@ public fun Project.createDeclarationProvider(scope: GlobalSearchScope, module: K
|
|||||||
KotlinDeclarationProviderFactory.getInstance(this).createDeclarationProvider(scope, module)
|
KotlinDeclarationProviderFactory.getInstance(this).createDeclarationProvider(scope, module)
|
||||||
|
|
||||||
public fun Project.mergeDeclarationProviders(declarationProviders: List<KotlinDeclarationProvider>): KotlinDeclarationProvider =
|
public fun Project.mergeDeclarationProviders(declarationProviders: List<KotlinDeclarationProvider>): KotlinDeclarationProvider =
|
||||||
KotlinDeclarationProviderMerger.getInstance(this).mergeDeclarationProviders(declarationProviders)
|
KotlinDeclarationProviderMerger.getInstance(this).merge(declarationProviders)
|
||||||
|
|||||||
+3
-9
@@ -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].
|
* 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.
|
* 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].
|
* 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 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).
|
* package providers which do not operate based on scopes (e.g. resolve extension package providers).
|
||||||
*/
|
*/
|
||||||
public abstract class KotlinPackageProviderMerger {
|
public abstract class KotlinPackageProviderMerger : KotlinComposableProviderMerger<KotlinPackageProvider> {
|
||||||
/**
|
|
||||||
* 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>): KotlinPackageProvider
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public fun getInstance(project: Project): KotlinPackageProviderMerger = project.getService(KotlinPackageProviderMerger::class.java)
|
public fun getInstance(project: Project): KotlinPackageProviderMerger = project.getService(KotlinPackageProviderMerger::class.java)
|
||||||
}
|
}
|
||||||
@@ -99,4 +93,4 @@ public fun Project.createPackageProvider(searchScope: GlobalSearchScope): Kotlin
|
|||||||
.createPackageProvider(searchScope)
|
.createPackageProvider(searchScope)
|
||||||
|
|
||||||
public fun Project.mergePackageProviders(packageProviders: List<KotlinPackageProvider>): KotlinPackageProvider =
|
public fun Project.mergePackageProviders(packageProviders: List<KotlinPackageProvider>): KotlinPackageProvider =
|
||||||
KotlinPackageProviderMerger.getInstance(this).mergePackageProviders(packageProviders)
|
KotlinPackageProviderMerger.getInstance(this).merge(packageProviders)
|
||||||
|
|||||||
+5
-11
@@ -5,20 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.providers.impl
|
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
|
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
|
* [KotlinCompositeProviderFactory] is used by various [KotlinCompositeProvider]s to share code related to provider creation and flattening.
|
||||||
* [KotlinCompositeProvider] should always be a subtype of their type argument [P].
|
|
||||||
*/
|
*/
|
||||||
public interface KotlinCompositeProvider<P> {
|
public class KotlinCompositeProviderFactory<P : KotlinComposableProvider>(
|
||||||
public val providers: List<P>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [KotlinCompositeProviderFactory] is used by various composite providers to share code related to provider creation and flattening.
|
|
||||||
*/
|
|
||||||
public class KotlinCompositeProviderFactory<P>(
|
|
||||||
private val emptyProvider: P,
|
private val emptyProvider: P,
|
||||||
private val composeProviders: (List<P>) -> P,
|
private val composeProviders: (List<P>) -> P,
|
||||||
) {
|
) {
|
||||||
@@ -48,7 +42,7 @@ public class KotlinCompositeProviderFactory<P>(
|
|||||||
* Uses the given [factory] to merge all providers of type [T] with the given [mergeTargets] strategy. Other providers (not of type [T]) are
|
* 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.
|
* added to the resulting composite provider unmerged.
|
||||||
*/
|
*/
|
||||||
public inline fun <P : Any, reified T : P> List<P>.mergeSpecificProviders(
|
public inline fun <P : KotlinComposableProvider, reified T : P> List<P>.mergeSpecificProviders(
|
||||||
factory: KotlinCompositeProviderFactory<P>,
|
factory: KotlinCompositeProviderFactory<P>,
|
||||||
crossinline mergeTargets: (List<T>) -> P,
|
crossinline mergeTargets: (List<T>) -> P,
|
||||||
): P {
|
): P {
|
||||||
|
|||||||
+3
-3
@@ -375,9 +375,9 @@ public class KotlinFakeClsStubsCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class KotlinStaticDeclarationProviderMerger(private val project: Project) : KotlinDeclarationProviderMerger() {
|
public class KotlinStaticDeclarationProviderMerger(private val project: Project) : KotlinDeclarationProviderMerger() {
|
||||||
override fun mergeDeclarationProviders(declarationProviders: List<KotlinDeclarationProvider>): KotlinDeclarationProvider =
|
override fun merge(providers: List<KotlinDeclarationProvider>): KotlinDeclarationProvider =
|
||||||
declarationProviders.mergeSpecificProviders<_, KotlinStaticDeclarationProvider>(CompositeKotlinDeclarationProvider.factory) { providers ->
|
providers.mergeSpecificProviders<_, KotlinStaticDeclarationProvider>(CompositeKotlinDeclarationProvider.factory) { targetProviders ->
|
||||||
val combinedScope = GlobalSearchScope.union(providers.map { it.scope })
|
val combinedScope = GlobalSearchScope.union(targetProviders.map { it.scope })
|
||||||
project.createDeclarationProvider(combinedScope, module = null).apply {
|
project.createDeclarationProvider(combinedScope, module = null).apply {
|
||||||
check(this is KotlinStaticDeclarationProvider) {
|
check(this is KotlinStaticDeclarationProvider) {
|
||||||
"`KotlinStaticDeclarationProvider` can only be merged into a combined declaration provider of the same type."
|
"`KotlinStaticDeclarationProvider` can only be merged into a combined declaration provider of the same type."
|
||||||
|
|||||||
+3
-3
@@ -54,9 +54,9 @@ public class KotlinStaticPackageProviderFactory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class KotlinStaticPackageProviderMerger(private val project: Project) : KotlinPackageProviderMerger() {
|
public class KotlinStaticPackageProviderMerger(private val project: Project) : KotlinPackageProviderMerger() {
|
||||||
override fun mergePackageProviders(packageProviders: List<KotlinPackageProvider>): KotlinPackageProvider =
|
override fun merge(providers: List<KotlinPackageProvider>): KotlinPackageProvider =
|
||||||
packageProviders.mergeSpecificProviders<_, KotlinStaticPackageProvider>(CompositeKotlinPackageProvider.factory) { providers ->
|
providers.mergeSpecificProviders<_, KotlinStaticPackageProvider>(CompositeKotlinPackageProvider.factory) { targetProviders ->
|
||||||
val combinedScope = GlobalSearchScope.union(providers.map { it.scope })
|
val combinedScope = GlobalSearchScope.union(targetProviders.map { it.scope })
|
||||||
project.createPackageProvider(combinedScope).apply {
|
project.createPackageProvider(combinedScope).apply {
|
||||||
check(this is KotlinStaticPackageProvider) {
|
check(this is KotlinStaticPackageProvider) {
|
||||||
"`${KotlinStaticPackageProvider::class.simpleName}` can only be merged into a combined package provider of the same type."
|
"`${KotlinStaticPackageProvider::class.simpleName}` can only be merged into a combined package provider of the same type."
|
||||||
|
|||||||
+1
-1
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.providers.impl.declarationProviders
|
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.KotlinDeclarationProvider
|
||||||
import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProvider
|
|
||||||
import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProviderFactory
|
import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProviderFactory
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
|||||||
+1
-1
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.providers.impl.packageProviders
|
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.KotlinPackageProvider
|
||||||
import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProvider
|
|
||||||
import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProviderFactory
|
import org.jetbrains.kotlin.analysis.providers.impl.KotlinCompositeProviderFactory
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|||||||
Reference in New Issue
Block a user