[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.*
|
||||
|
||||
/**
|
||||
* 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<KtClassOrObject>
|
||||
@@ -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>): KotlinDeclarationProvider
|
||||
|
||||
public abstract class KotlinDeclarationProviderMerger : KotlinComposableProviderMerger<KotlinDeclarationProvider> {
|
||||
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>): 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].
|
||||
* 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>): KotlinPackageProvider
|
||||
|
||||
public abstract class KotlinPackageProviderMerger : KotlinComposableProviderMerger<KotlinPackageProvider> {
|
||||
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>): KotlinPackageProvider =
|
||||
KotlinPackageProviderMerger.getInstance(this).mergePackageProviders(packageProviders)
|
||||
KotlinPackageProviderMerger.getInstance(this).merge(packageProviders)
|
||||
|
||||
+5
-11
@@ -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<P> {
|
||||
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>(
|
||||
public class KotlinCompositeProviderFactory<P : KotlinComposableProvider>(
|
||||
private val emptyProvider: 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
|
||||
* 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>,
|
||||
crossinline mergeTargets: (List<T>) -> P,
|
||||
): P {
|
||||
|
||||
+3
-3
@@ -375,9 +375,9 @@ public class KotlinFakeClsStubsCache {
|
||||
}
|
||||
|
||||
public class KotlinStaticDeclarationProviderMerger(private val project: Project) : KotlinDeclarationProviderMerger() {
|
||||
override fun mergeDeclarationProviders(declarationProviders: List<KotlinDeclarationProvider>): KotlinDeclarationProvider =
|
||||
declarationProviders.mergeSpecificProviders<_, KotlinStaticDeclarationProvider>(CompositeKotlinDeclarationProvider.factory) { providers ->
|
||||
val combinedScope = GlobalSearchScope.union(providers.map { it.scope })
|
||||
override fun merge(providers: List<KotlinDeclarationProvider>): 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."
|
||||
|
||||
+3
-3
@@ -54,9 +54,9 @@ public class KotlinStaticPackageProviderFactory(
|
||||
}
|
||||
|
||||
public class KotlinStaticPackageProviderMerger(private val project: Project) : KotlinPackageProviderMerger() {
|
||||
override fun mergePackageProviders(packageProviders: List<KotlinPackageProvider>): KotlinPackageProvider =
|
||||
packageProviders.mergeSpecificProviders<_, KotlinStaticPackageProvider>(CompositeKotlinPackageProvider.factory) { providers ->
|
||||
val combinedScope = GlobalSearchScope.union(providers.map { it.scope })
|
||||
override fun merge(providers: List<KotlinPackageProvider>): 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."
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user