FIR IDE: introduce FirIdeAllSourceDependenciesSymbolProvider

Co-authored-by: Simon Ogorodnik <simon.ogorodnik@jetbrains.com>
This commit is contained in:
Ilya Kirillov
2020-07-20 16:42:11 +03:00
parent 7d8ef5c7a2
commit cfc46b0cc8
2 changed files with 86 additions and 21 deletions
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2020 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 com.intellij.openapi.module.impl.scopes.ModuleScopeProviderImpl
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtElement
internal class FirIdeAllSourceDependenciesSymbolProvider(
project: Project,
moduleInfo: ModuleSourceInfo,
private val sessionProvider: FirIdeSessionProvider,
private val firBuilder: FirBuilder,
) : FirSymbolProvider() {
private val scope = ModuleScopeProviderImpl(moduleInfo.module).moduleWithDependenciesScope
private val indexHelper = IndexHelper(project)
private val packageExistenceChecker = PackageExistenceCheckerForMultipleModules(project, moduleInfo.dependencies())
private val cache = PsiToFirCacheImpl()
override fun getClassLikeSymbolByFqName(classId: ClassId): FirClassLikeSymbol<*>? {
return executeOrReturnDefaultValueOnPCE(null) {
val ktClass = indexHelper.firstMatchingOrNull(
KotlinFullClassNameIndex.KEY,
classId.asSingleFqName().asString(),
scope
) { candidate -> candidate.containingKtFile.packageFqName == classId.packageFqName } ?: return null
(ktClass.toFir() as FirClassLikeDeclaration<*>).symbol
}
}
@OptIn(ExperimentalStdlibApi::class)
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> {
val callableId = CallableId(packageFqName, name)
return executeOrReturnDefaultValueOnPCE(emptyList()) {
buildList {
indexHelper.getTopLevelFunctions(callableId, scope).mapTo(this) { (it.toFir() as FirCallableDeclaration<*>).symbol }
indexHelper.getTopLevelProperties(callableId, scope).mapTo(this) { (it.toFir() as FirCallableDeclaration<*>).symbol }
}
}
}
private fun KtElement.toFir(): FirElement =
getOrBuildFir(cache, firBuilder, sessionProvider, FirResolvePhase.RAW_FIR)
override fun getNestedClassifierScope(classId: ClassId): FirScope? {
val classifier = getClassLikeSymbolByFqName(classId) ?: return null
return classifier.fir.session.firIdeProvider.getNestedClassifierScope(classId)
}
override fun getPackage(fqName: FqName): FqName? =
fqName.takeIf(packageExistenceChecker::isPackageExists)
}
@@ -5,44 +5,38 @@
package org.jetbrains.kotlin.idea.fir.low.level.api
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.fir.java.FirLibrarySession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
import org.jetbrains.kotlin.idea.caches.resolve.IDEPackagePartProvider
internal class FirIdeModuleDependenciesSymbolProvider(
internal class FirIdeModuleLibraryDependenciesSymbolProvider(
session: FirIdeJavaModuleBasedSession
) : FirDependenciesSymbolProviderImpl(session) {
//todo invalidate cache on libraries changed
override val dependencyProviders: List<FirSymbolProvider> by lazy {
val moduleInfo = session.moduleInfo
val sessionProvider = session.sessionProvider ?: return@lazy emptyList<FirSymbolProvider>()
val sessionProvider = session.sessionProvider ?: error("No session provider found")
val project = sessionProvider.project
val stateService = FirIdeResolveStateService.getInstance(project)
moduleInfo.dependenciesWithoutSelf().filterIsInstance<IdeaModuleInfo>().mapNotNull { dependencyInfo ->
val resolveState = stateService.getResolveState(dependencyInfo)
val dependencySession = when {
dependencyInfo is ModuleSourceInfo -> {
resolveState.getSession(project, dependencyInfo)
}
dependencyInfo.isLibraryClasses() -> {
moduleInfo.dependenciesWithoutSelf()
.filterIsInstance<IdeaModuleInfo>()
.mapNotNull { dependencyInfo ->
val dependencySession = if (dependencyInfo.isLibraryClasses()) {
val dependencyScope = dependencyInfo.contentScope()
FirLibrarySession.create(
dependencyInfo, sessionProvider as FirProjectSessionProvider,
dependencyScope, project, IDEPackagePartProvider(dependencyScope)
)
}
else -> return@mapNotNull null
}
dependencySession.firSymbolProvider
}.toList()
} else null
dependencySession?.firSymbolProvider
}.toList()
}
}