org.jetbrains.kotlin.fir.resolve.providers.impl.FirDependenciesSymbolProviderImpl.kt Maven / Gradle / Ivy
/*
* 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.fir.resolve.providers.impl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.nullableModuleData
import org.jetbrains.kotlin.fir.resolve.providers.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@ThreadSafeMutableState
open class FirDependenciesSymbolProviderImpl(session: FirSession) : FirDependenciesSymbolProvider(session) {
private val classCache = session.firCachesFactory.createCache(::computeClass)
private val topLevelCallableCache = session.firCachesFactory.createCache(::computeTopLevelCallables)
private val topLevelFunctionCache = session.firCachesFactory.createCache(::computeTopLevelFunctions)
private val topLevelPropertyCache = session.firCachesFactory.createCache(::computeTopLevelProperties)
private val packageCache = session.firCachesFactory.createCache(::computePackage)
protected open val dependencyProviders by lazy {
val moduleData = session.nullableModuleData ?: return@lazy emptyList()
(moduleData.dependencies + moduleData.friendDependencies + moduleData.dependsOnDependencies)
.mapNotNull { session.sessionProvider?.getSession(it) }
.sortedBy { it.kind }
.map {
if (it.kind == FirSession.Kind.Source) {
it.symbolProvider.loadTransitiveSourceProvides()
} else {
listOf(it.symbolProvider)
}
}
.flatten()
}
private fun FirSymbolProvider.loadTransitiveSourceProvides(): List {
val result = mutableListOf()
val visited = hashSetOf()
fun loadTransitiveSourceProvides(provider: FirSymbolProvider) {
if (!visited.add(provider)) {
return
}
when {
provider is FirDependenciesSymbolProviderImpl -> {
for (p in provider.dependencyProviders) {
loadTransitiveSourceProvides(p)
}
}
provider is FirCompositeSymbolProvider -> {
for (p in provider.providers) {
loadTransitiveSourceProvides(p)
}
}
provider.session.kind == FirSession.Kind.Source -> {
result.add(provider)
}
}
}
loadTransitiveSourceProvides(this)
return result
}
@OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
private fun computeTopLevelCallables(callableId: CallableId): List> = buildList {
dependencyProviders.forEach { it.getTopLevelCallableSymbolsTo(this, callableId.packageName, callableId.callableName) }
}
@OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
private fun computeTopLevelFunctions(callableId: CallableId): List = buildList {
dependencyProviders.forEach { it.getTopLevelFunctionSymbolsTo(this, callableId.packageName, callableId.callableName) }
}
@OptIn(FirSymbolProviderInternals::class, ExperimentalStdlibApi::class)
private fun computeTopLevelProperties(callableId: CallableId): List = buildList {
dependencyProviders.forEach { it.getTopLevelPropertySymbolsTo(this, callableId.packageName, callableId.callableName) }
}
private fun computePackage(it: FqName): FqName? =
dependencyProviders.firstNotNullOfOrNull { provider -> provider.getPackage(it) }
private fun computeClass(classId: ClassId): FirClassLikeSymbol<*>? =
dependencyProviders.firstNotNullOfOrNull { provider -> provider.getClassLikeSymbolByClassId(classId) }
@FirSymbolProviderInternals
override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {
destination += topLevelFunctionCache.getValue(CallableId(packageFqName, name))
}
@FirSymbolProviderInternals
override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {
destination += topLevelPropertyCache.getValue(CallableId(packageFqName, name))
}
@FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) {
destination += getTopLevelCallableSymbols(packageFqName, name)
}
override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List> {
return topLevelCallableCache.getValue(CallableId(packageFqName, name))
}
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
return classCache.getValue(classId)
}
override fun getPackage(fqName: FqName): FqName? {
return packageCache.getValue(fqName)
}
}