[AA] KT-58580 Add KotlinDeclarationProviderMerger
- A proper merging strategy for declaration providers is required for cases where the main declaration provider created by `createDeclarationProvider` can't provide all declarations that the original declaration providers can provide. Then, only a sublist of the declaration providers should be merged, while keeping the unmergeable declaration providers intact. ^KT-58580 fixed
This commit is contained in:
committed by
Space Team
parent
fba0648005
commit
915c412929
+35
-4
@@ -49,9 +49,40 @@ public abstract class KotlinDeclarationProvider {
|
||||
|
||||
public abstract class KotlinDeclarationProviderFactory {
|
||||
public abstract fun createDeclarationProvider(scope: GlobalSearchScope, contextualModule: KtModule?): KotlinDeclarationProvider
|
||||
|
||||
public companion object {
|
||||
public fun getInstance(project: Project): KotlinDeclarationProviderFactory =
|
||||
project.getService(KotlinDeclarationProviderFactory::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
public fun Project.createDeclarationProvider(scope: GlobalSearchScope, module: KtModule?): KotlinDeclarationProvider {
|
||||
return getService(KotlinDeclarationProviderFactory::class.java)
|
||||
.createDeclarationProvider(scope, module)
|
||||
}
|
||||
/**
|
||||
* While the main declaration provider created via [createDeclarationProvider] is scope-based, there are other declaration providers which
|
||||
* are not, such as file-based declaration providers. Not all declarations provided by such declaration providers can be provided by the
|
||||
* main declaration provider, even if the correct scope is provided (such as a file-based scope). For example, the main declaration provider
|
||||
* may be based on an index which doesn't contain the declarations provided by file-based declaration providers.
|
||||
*
|
||||
* Hence, [KotlinDeclarationProvider]s cannot just be combined by combining the scopes of all declaration providers and calling
|
||||
* [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 companion object {
|
||||
public fun getInstance(project: Project): KotlinDeclarationProviderMerger =
|
||||
project.getService(KotlinDeclarationProviderMerger::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
public fun Project.createDeclarationProvider(scope: GlobalSearchScope, module: KtModule?): KotlinDeclarationProvider =
|
||||
KotlinDeclarationProviderFactory.getInstance(this).createDeclarationProvider(scope, module)
|
||||
|
||||
public fun Project.mergeDeclarationProviders(declarationProviders: List<KotlinDeclarationProvider>): KotlinDeclarationProvider =
|
||||
KotlinDeclarationProviderMerger.getInstance(this).mergeDeclarationProviders(declarationProviders)
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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>): 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<KotlinDeclarationProvider>): List<KotlinDeclarationProvider>
|
||||
}
|
||||
+15
-3
@@ -21,13 +21,14 @@ import com.intellij.util.containers.CollectionFactory
|
||||
import com.intellij.util.indexing.FileContent
|
||||
import com.intellij.util.indexing.FileContentImpl
|
||||
import com.intellij.util.io.URLUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInDecompiler
|
||||
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
|
||||
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.createDeclarationProvider
|
||||
import org.jetbrains.kotlin.analysis.providers.impl.util.mergeOnly
|
||||
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.name.*
|
||||
@@ -39,7 +40,7 @@ import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerial
|
||||
|
||||
public class KotlinStaticDeclarationProvider internal constructor(
|
||||
private val index: KotlinStaticDeclarationIndex,
|
||||
private val scope: GlobalSearchScope,
|
||||
public val scope: GlobalSearchScope,
|
||||
) : KotlinDeclarationProvider() {
|
||||
|
||||
private val KtElement.inScope: Boolean
|
||||
@@ -118,7 +119,6 @@ public class KotlinStaticDeclarationProvider internal constructor(
|
||||
getTopLevelProperties(callableId).mapTo(this) { it.containingKtFile }
|
||||
getTopLevelFunctions(callableId).mapTo(this) { it.containingKtFile }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class KotlinStaticDeclarationProviderFactory(
|
||||
@@ -368,3 +368,15 @@ public class KotlinFakeClsStubsCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class KotlinStaticDeclarationProviderMerger(private val project: Project) : KotlinDeclarationProviderMergerBase() {
|
||||
override fun mergeToList(declarationProviders: List<KotlinDeclarationProvider>): List<KotlinDeclarationProvider> =
|
||||
declarationProviders.mergeOnly<_, KotlinStaticDeclarationProvider> { providers ->
|
||||
val combinedScope = GlobalSearchScope.union(providers.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."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
public class CompositeKotlinDeclarationProvider private constructor(
|
||||
private val providers: List<KotlinDeclarationProvider>
|
||||
public val providers: List<KotlinDeclarationProvider>
|
||||
) : KotlinDeclarationProvider() {
|
||||
override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? {
|
||||
return providers.firstNotNullOfOrNull { it.getClassLikeDeclarationByClassId(classId) }
|
||||
@@ -75,5 +75,16 @@ public class CompositeKotlinDeclarationProvider private constructor(
|
||||
else -> CompositeKotlinDeclarationProvider(providers)
|
||||
}
|
||||
}
|
||||
|
||||
public fun createFlattened(providers: List<KotlinDeclarationProvider>): KotlinDeclarationProvider =
|
||||
create(if (providers.size > 1) flatten(providers) else providers)
|
||||
|
||||
public fun flatten(providers: List<KotlinDeclarationProvider>): List<KotlinDeclarationProvider> =
|
||||
providers.flatMap { provider ->
|
||||
when (provider) {
|
||||
is CompositeKotlinDeclarationProvider -> provider.providers
|
||||
else -> listOf(provider)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user