FIR IDE: abstract DeclarationProvider

This commit is contained in:
Ilya Kirillov
2021-06-14 17:05:53 +02:00
parent 7fe2adc37e
commit a483098303
10 changed files with 96 additions and 29 deletions
@@ -5,11 +5,9 @@
package org.jetbrains.kotlin.idea.fir.low.level.api package org.jetbrains.kotlin.idea.fir.low.level.api
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StringStubIndexExtension
import com.intellij.psi.stubs.StubIndex import com.intellij.psi.stubs.StubIndex
import com.intellij.psi.stubs.StubIndexKey import com.intellij.psi.stubs.StubIndexKey
import org.jetbrains.kotlin.idea.stubindex.* import org.jetbrains.kotlin.idea.stubindex.*
@@ -19,10 +17,8 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
/*
* Move to another module internal class DeclarationProviderByIndexesImpl(val project: Project, private val scope: GlobalSearchScope) : DeclarationProvider() {
*/
internal class IndexHelper(val project: Project, private val scope: GlobalSearchScope) {
private val stubIndex: StubIndex = StubIndex.getInstance() private val stubIndex: StubIndex = StubIndex.getInstance()
private inline fun <INDEX_KEY : Any, reified PSI : PsiElement> firstMatchingOrNull( private inline fun <INDEX_KEY : Any, reified PSI : PsiElement> firstMatchingOrNull(
@@ -43,12 +39,12 @@ internal class IndexHelper(val project: Project, private val scope: GlobalSearch
return result return result
} }
fun classFromIndexByClassId(classId: ClassId) = firstMatchingOrNull( override fun getClassByClassId(classId: ClassId) = firstMatchingOrNull(
KotlinFullClassNameIndex.KEY, KotlinFullClassNameIndex.KEY,
classId.asStringForIndexes(), classId.asStringForIndexes(),
) { candidate -> candidate.containingKtFile.packageFqName == classId.packageFqName } ) { candidate -> candidate.containingKtFile.packageFqName == classId.packageFqName }
fun typeAliasFromIndexByClassId(classId: ClassId): KtTypeAlias? = firstMatchingOrNull<String, KtTypeAlias>( override fun getTypeAliasByClassId(classId: ClassId): KtTypeAlias? = firstMatchingOrNull<String, KtTypeAlias>(
KotlinTopLevelTypeAliasFqNameIndex.KEY, KotlinTopLevelTypeAliasFqNameIndex.KEY,
key = classId.asStringForIndexes(), key = classId.asStringForIndexes(),
) { candidate -> candidate.containingKtFile.packageFqName == classId.packageFqName } ) { candidate -> candidate.containingKtFile.packageFqName == classId.packageFqName }
@@ -57,15 +53,14 @@ internal class IndexHelper(val project: Project, private val scope: GlobalSearch
key = classId.asString(), key = classId.asString(),
) )
override fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty> =
fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty> =
KotlinTopLevelPropertyFqnNameIndex.getInstance()[callableId.asStringForIndexes(), project, scope] KotlinTopLevelPropertyFqnNameIndex.getInstance()[callableId.asStringForIndexes(), project, scope]
fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction> = override fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction> =
KotlinTopLevelFunctionFqnNameIndex.getInstance()[callableId.asStringForIndexes(), project, scope] KotlinTopLevelFunctionFqnNameIndex.getInstance()[callableId.asStringForIndexes(), project, scope]
fun getClassNamesInPackage(packageFqName: FqName): Set<Name> = override fun getClassNamesInPackage(packageFqName: FqName): Set<Name> =
KotlinTopLevelClassByPackageIndex.getInstance() KotlinTopLevelClassByPackageIndex.getInstance()
.get(packageFqName.asStringForIndexes(), project, scope) .get(packageFqName.asStringForIndexes(), project, scope)
.mapNotNullTo(hashSetOf()) { it.nameAsName } .mapNotNullTo(hashSetOf()) { it.nameAsName }
@@ -80,7 +75,5 @@ internal class IndexHelper(val project: Project, private val scope: GlobalSearch
private fun ClassId.asStringForIndexes(): String = private fun ClassId.asStringForIndexes(): String =
asSingleFqName().asStringForIndexes() asSingleFqName().asStringForIndexes()
private fun getShortName(fqName: String) = Name.identifier(fqName.substringAfterLast('.'))
} }
} }
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2021 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.idea.fir.low.level.api
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtTypeAlias
abstract class DeclarationProvider {
abstract fun getClassByClassId(classId: ClassId): KtClassOrObject?
abstract fun getTypeAliasByClassId(classId: ClassId): KtTypeAlias?
abstract fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty>
abstract fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction>
abstract fun getClassNamesInPackage(packageFqName: FqName): Set<Name>
}
@@ -0,0 +1,7 @@
/*
* Copyright 2010-2021 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.idea.fir.low.level.api
@@ -0,0 +1,7 @@
/*
* Copyright 2010-2021 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.idea.fir.low.level.api
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2021 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.idea.fir.low.level.api.api
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.idea.fir.low.level.api.DeclarationProvider
abstract class FirModuleResolveStateConfigurator {
abstract fun createDeclarationProvider(scope: GlobalSearchScope): DeclarationProvider
}
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2021 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.idea.fir.low.level.api.api
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.idea.fir.low.level.api.DeclarationProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.DeclarationProviderByIndexesImpl
class FirModuleResolveStateConfiguratorIdeImpl(private val project: Project) : FirModuleResolveStateConfigurator() {
override fun createDeclarationProvider(scope: GlobalSearchScope): DeclarationProvider =
DeclarationProviderByIndexesImpl(project, scope)
}
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.providers
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.NoMutableState import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.ThreadSafeMutableState import org.jetbrains.kotlin.fir.ThreadSafeMutableState
@@ -21,7 +20,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper import org.jetbrains.kotlin.idea.fir.low.level.api.DeclarationProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveStateConfigurator import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveStateConfigurator
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
@@ -37,18 +36,17 @@ internal class FirIdeProvider(
val kotlinScopeProvider: FirKotlinScopeProvider, val kotlinScopeProvider: FirKotlinScopeProvider,
firFileBuilder: FirFileBuilder, firFileBuilder: FirFileBuilder,
val cache: ModuleFileCache, val cache: ModuleFileCache,
searchScope: GlobalSearchScope, private val declarationProvider: DeclarationProvider,
) : FirProvider() { ) : FirProvider() {
override val symbolProvider: FirSymbolProvider = SymbolProvider() override val symbolProvider: FirSymbolProvider = SymbolProvider()
private val indexHelper = IndexHelper(project, searchScope)
private val packageExistenceChecker = ServiceManager.getService(project, FirModuleResolveStateConfigurator::class.java) private val packageExistenceChecker = ServiceManager.getService(project, FirModuleResolveStateConfigurator::class.java)
.createPackageExistingCheckerForModule(moduleInfo) .createPackageExistingCheckerForModule(moduleInfo)
private val providerHelper = FirProviderHelper( private val providerHelper = FirProviderHelper(
cache, cache,
firFileBuilder, firFileBuilder,
indexHelper, declarationProvider,
packageExistenceChecker, packageExistenceChecker,
) )
@@ -103,7 +101,7 @@ internal class FirIdeProvider(
} }
override fun getClassNamesInPackage(fqName: FqName): Set<Name> = override fun getClassNamesInPackage(fqName: FqName): Set<Name> =
indexHelper.getClassNamesInPackage(fqName) declarationProvider.getClassNamesInPackage(fqName)
@NoMutableState @NoMutableState
private inner class SymbolProvider : FirSymbolProvider(session) { private inner class SymbolProvider : FirSymbolProvider(session) {
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper import org.jetbrains.kotlin.idea.fir.low.level.api.DeclarationProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.PackageExistenceChecker import org.jetbrains.kotlin.idea.fir.low.level.api.PackageExistenceChecker
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
@@ -28,15 +28,15 @@ import java.util.*
internal class FirProviderHelper( internal class FirProviderHelper(
private val cache: ModuleFileCache, private val cache: ModuleFileCache,
private val firFileBuilder: FirFileBuilder, private val firFileBuilder: FirFileBuilder,
private val indexHelper: IndexHelper, private val declarationProvider: DeclarationProvider,
private val packageExistenceChecker: PackageExistenceChecker, private val packageExistenceChecker: PackageExistenceChecker,
) { ) {
fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>? { fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration<*>? {
if (classId.isLocal) return null if (classId.isLocal) return null
return executeOrReturnDefaultValueOnPCE(null) { return executeOrReturnDefaultValueOnPCE(null) {
cache.classifierByClassId.computeIfAbsent(classId) { cache.classifierByClassId.computeIfAbsent(classId) {
val ktClass = when (val klass = indexHelper.classFromIndexByClassId(classId)) { val ktClass = when (val klass = declarationProvider.getClassByClassId(classId)) {
null -> indexHelper.typeAliasFromIndexByClassId(classId) null -> declarationProvider.getTypeAliasByClassId(classId)
else -> if (klass.getClassId() == null) null else klass else -> if (klass.getClassId() == null) null else klass
} ?: return@computeIfAbsent Optional.empty() } ?: return@computeIfAbsent Optional.empty()
val firFile = firFileBuilder.buildRawFirFileWithCaching(ktClass.containingKtFile, cache, preferLazyBodies = true) val firFile = firFileBuilder.buildRawFirFileWithCaching(ktClass.containingKtFile, cache, preferLazyBodies = true)
@@ -55,8 +55,8 @@ internal class FirProviderHelper(
return executeOrReturnDefaultValueOnPCE(emptyList()) { return executeOrReturnDefaultValueOnPCE(emptyList()) {
cache.callableByCallableId.computeIfAbsent(callableId) { cache.callableByCallableId.computeIfAbsent(callableId) {
val files = Sets.newIdentityHashSet<KtFile>().apply { val files = Sets.newIdentityHashSet<KtFile>().apply {
indexHelper.getTopLevelFunctions(callableId).mapTo(this) { it.containingKtFile } declarationProvider.getTopLevelFunctions(callableId).mapTo(this) { it.containingKtFile }
indexHelper.getTopLevelProperties(callableId).mapTo(this) { it.containingKtFile } declarationProvider.getTopLevelProperties(callableId).mapTo(this) { it.containingKtFile }
} }
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
buildList { buildList {
@@ -29,10 +29,10 @@ import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.session.* import org.jetbrains.kotlin.fir.session.*
import org.jetbrains.kotlin.idea.caches.project.* import org.jetbrains.kotlin.idea.caches.project.*
import org.jetbrains.kotlin.idea.caches.resolve.IDEPackagePartProvider import org.jetbrains.kotlin.idea.caches.resolve.IDEPackagePartProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.*
import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner
import org.jetbrains.kotlin.idea.fir.low.level.api.IdeFirPhaseManager import org.jetbrains.kotlin.idea.fir.low.level.api.IdeFirPhaseManager
import org.jetbrains.kotlin.idea.fir.low.level.api.IdeSessionComponents import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveStateConfigurator
import org.jetbrains.kotlin.idea.fir.low.level.api.SealedClassInheritorsProviderIdeImpl
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCacheImpl import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCacheImpl
import org.jetbrains.kotlin.idea.fir.low.level.api.fir.caches.FirThreadSafeCachesFactory import org.jetbrains.kotlin.idea.fir.low.level.api.fir.caches.FirThreadSafeCachesFactory
@@ -58,6 +58,7 @@ import java.nio.file.Paths
internal object FirIdeSessionFactory { internal object FirIdeSessionFactory {
fun createSourcesSession( fun createSourcesSession(
project: Project, project: Project,
configurator: FirModuleResolveStateConfigurator,
moduleInfo: ModuleSourceInfo, moduleInfo: ModuleSourceInfo,
builtinsAndCloneableSession: FirIdeBuiltinsAndCloneableSession, builtinsAndCloneableSession: FirIdeBuiltinsAndCloneableSession,
firPhaseRunner: FirPhaseRunner, firPhaseRunner: FirPhaseRunner,
@@ -97,7 +98,7 @@ internal object FirIdeSessionFactory {
scopeProvider, scopeProvider,
firFileBuilder, firFileBuilder,
cache, cache,
searchScope configurator.createDeclarationProvider(searchScope),
) )
register(FirProvider::class, provider) register(FirProvider::class, provider)
@@ -130,6 +131,7 @@ internal object FirIdeSessionFactory {
.mapTo(this) { .mapTo(this) {
createSourcesSession( createSourcesSession(
project, project,
configurator,
it, it,
builtinsAndCloneableSession, builtinsAndCloneableSession,
firPhaseRunner, firPhaseRunner,
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.sessions package org.jetbrains.kotlin.idea.fir.low.level.api.sessions
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import kotlinx.collections.immutable.PersistentMap import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.session.FirModuleInfoBasedModuleData import org.jetbrains.kotlin.fir.session.FirModuleInfoBasedModuleData
import org.jetbrains.kotlin.idea.caches.project.LibraryModificationTracker import org.jetbrains.kotlin.idea.caches.project.LibraryModificationTracker
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveStateConfigurator
import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner
import org.jetbrains.kotlin.idea.fir.low.level.api.util.addValueFor import org.jetbrains.kotlin.idea.fir.low.level.api.util.addValueFor
import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE
@@ -25,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap
internal class FirIdeSessionProviderStorage(private val project: Project) { internal class FirIdeSessionProviderStorage(private val project: Project) {
private val sessionsCache = ConcurrentHashMap<ModuleSourceInfo, FromModuleViewSessionCache>() private val sessionsCache = ConcurrentHashMap<ModuleSourceInfo, FromModuleViewSessionCache>()
private val configurator = ServiceManager.getService(project, FirModuleResolveStateConfigurator::class.java)
private val librariesCache by cachedValue(project, LibraryModificationTracker.getInstance(project)) { LibrariesCache() } private val librariesCache by cachedValue(project, LibraryModificationTracker.getInstance(project)) { LibrariesCache() }
@@ -42,6 +45,7 @@ internal class FirIdeSessionProviderStorage(private val project: Project) {
val session = executeWithoutPCE { val session = executeWithoutPCE {
FirIdeSessionFactory.createSourcesSession( FirIdeSessionFactory.createSourcesSession(
project, project,
configurator,
rootModule, rootModule,
builtinsAndCloneableSession, builtinsAndCloneableSession,
firPhaseRunner, firPhaseRunner,