diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt index 7b76f3abbcd..9a57909581e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers +import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.JvmStubBasedFirDeserializedSymbolProvider import org.jetbrains.kotlin.analysis.utils.collections.buildSmartList import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider @@ -14,12 +15,14 @@ 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.load.kotlin.FacadeClassSource -import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtClassLikeDeclaration import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.utils.SmartSet +import org.jetbrains.kotlin.utils.addIfNotNull internal class LLFirModuleWithDependenciesSymbolProvider( session: FirSession, @@ -33,20 +36,29 @@ internal class LLFirModuleWithDependenciesSymbolProvider( fun getClassLikeSymbolByFqNameWithoutDependencies(classId: ClassId): FirClassLikeSymbol<*>? = providers.firstNotNullOfOrNull { it.getClassLikeSymbolByClassId(classId) } + fun getClassLikeSymbolByFqNameWithoutDependencies( + classLikeDeclaration: KtClassLikeDeclaration, + classId: ClassId + ): FirClassLikeSymbol<*>? { + return providers.filterIsInstance(JvmStubBasedFirDeserializedSymbolProvider::class.java) + .firstNotNullOfOrNull { it.getClassLikeSymbolByClassId(classLikeDeclaration, classId) } + } + @FirSymbolProviderInternals override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) { - getTopLevelCallableSymbolsToWithoutDependencies(destination, packageFqName, name) + providers.forEach { it.getTopLevelCallableSymbolsTo(destination, packageFqName, name) } dependencyProvider.getTopLevelCallableSymbolsTo(destination, packageFqName, name) } @FirSymbolProviderInternals - fun getTopLevelCallableSymbolsWithoutDependencies(packageFqName: FqName, name: Name): List> { - return buildList { getTopLevelCallableSymbolsToWithoutDependencies(this, packageFqName, name) } - } - - @FirSymbolProviderInternals - fun getTopLevelCallableSymbolsToWithoutDependencies(destination: MutableList>, packageFqName: FqName, name: Name) { - providers.forEach { it.getTopLevelCallableSymbolsTo(destination, packageFqName, name) } + fun getTopLevelDeserializedCallableSymbolsToWithoutDependencies( + destination: MutableList>, + callableDeclaration: KtCallableDeclaration, + packageFqName: FqName, + shortName: Name + ) { + providers.filterIsInstance(JvmStubBasedFirDeserializedSymbolProvider::class.java) + .forEach { destination.addIfNotNull(it.getTopLevelCallableSymbol(callableDeclaration, packageFqName, shortName)) } } @FirSymbolProviderInternals diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt index b685df88f46..49aec125c50 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt @@ -18,15 +18,13 @@ import org.jetbrains.kotlin.fir.caches.getValue import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider import org.jetbrains.kotlin.fir.java.deserialization.KotlinBuiltins +import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.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 +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment @@ -67,7 +65,7 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( private val typeAliasCache: FirCache = session.firCachesFactory.createCacheWithPostCompute( - createValue = { classId, _ -> findAndDeserializeTypeAlias(classId) }, + createValue = { classId, context -> findAndDeserializeTypeAlias(classId, context) }, postCompute = { _, symbol, postProcessor -> if (postProcessor != null && symbol != null) { postProcessor.invoke(symbol) @@ -93,12 +91,16 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( return namesByPackageCache.getTopLevelClassifierNamesInPackage(packageFqName) } - private fun findAndDeserializeTypeAlias(classId: ClassId): Pair { - val classLikeDeclaration = declarationProvider.getClassLikeDeclarationByClassId(classId)?.originalElement + private fun findAndDeserializeTypeAlias( + classId: ClassId, + context: StubBasedFirDeserializationContext? + ): Pair { + val classLikeDeclaration = + context?.classLikeDeclaration ?: declarationProvider.getClassLikeDeclarationByClassId(classId)?.originalElement if (classLikeDeclaration is KtTypeAlias) { val symbol = FirTypeAliasSymbol(classId) val postProcessor: DeserializedTypeAliasPostProcessor = { - val rootContext = StubBasedFirDeserializationContext.createRootContext( + val rootContext = context ?: StubBasedFirDeserializationContext.createRootContext( moduleData, StubBasedAnnotationDeserializer(session), classId.packageFqName, @@ -117,7 +119,12 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( classId: ClassId, parentContext: StubBasedFirDeserializationContext? = null ): FirRegularClassSymbol? { - val classLikeDeclaration = declarationProvider.getClassLikeDeclarationByClassId(classId)?.originalElement ?: return null + val (classLikeDeclaration, context) = + if (parentContext?.classLikeDeclaration != null) { + parentContext.classLikeDeclaration to null + } else { + (declarationProvider.getClassLikeDeclarationByClassId(classId)?.originalElement ?: return null) to parentContext + } val symbol = FirRegularClassSymbol(classId) if (classLikeDeclaration is KtClassOrObject) { deserializeClassToSymbol( @@ -128,14 +135,14 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( moduleData, StubBasedAnnotationDeserializer(session), kotlinScopeProvider, - parentContext, + parentContext = context, containerSource = if (initialOrigin == FirDeclarationOrigin.BuiltIns) null else JvmFromStubDecompilerSource( JvmClassName.byClassId( classId ) ), deserializeNestedClass = this::getClass, - initialOrigin + initialOrigin = initialOrigin ) return symbol } @@ -223,4 +230,51 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( if (!namesByPackageCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null return getClass(classId) ?: getTypeAlias(classId) } + + fun getClassLikeSymbolByClassId(classLikeDeclaration: KtClassLikeDeclaration, classId: ClassId): FirClassLikeSymbol<*>? { + val annotationDeserializer = StubBasedAnnotationDeserializer(session) + val deserializationContext = StubBasedFirDeserializationContext( + moduleData, + classId.packageFqName, + classId.relativeClassName, + StubBasedFirTypeDeserializer( + moduleData, + annotationDeserializer, + parent = null, + containingSymbol = null, + owner = null, + initialOrigin + ), + annotationDeserializer, + containerSource = null, + outerClassSymbol = null, + outerTypeParameters = emptyList(), + initialOrigin, + classLikeDeclaration + ) + if (classLikeDeclaration is KtClassOrObject) { + return classCache.getValue( + classId, + deserializationContext + ) + } + return typeAliasCache.getValue(classId, deserializationContext) + } + + fun getTopLevelCallableSymbol( + callableDeclaration: KtCallableDeclaration, + packageFqName: FqName, + shortName: Name + ): FirCallableSymbol<*>? { + //possible overloads spoils here + //we can't use only this callable instead of index access to fill the cache + //names check is redundant though as we already have existing callable in scope + val callableId = CallableId(packageFqName, shortName) + val callableSymbols = when (callableDeclaration) { + is KtNamedFunction -> functionCache.getValue(callableId) + is KtProperty -> propertyCache.getValue(callableId) + else -> null + } + return callableSymbols?.singleOrNull { it.fir.realPsi == callableDeclaration } + } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirMemberDeserializer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirMemberDeserializer.kt index 3ab2a386542..2941748b93e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirMemberDeserializer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirMemberDeserializer.kt @@ -45,7 +45,8 @@ internal class StubBasedFirDeserializationContext( val containerSource: DeserializedContainerSource?, val outerClassSymbol: FirRegularClassSymbol?, val outerTypeParameters: List, - private val initialOrigin: FirDeclarationOrigin + private val initialOrigin: FirDeclarationOrigin, + val classLikeDeclaration: KtClassLikeDeclaration? = null ) { val session: FirSession = moduleData.session diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt index f4d97c2b218..6925458d976 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/StubBasedFirTypeDeserializer.kt @@ -42,7 +42,7 @@ internal class StubBasedFirTypeDeserializer( private val annotationDeserializer: StubBasedAnnotationDeserializer, private val parent: StubBasedFirTypeDeserializer?, private val containingSymbol: FirBasedSymbol<*>?, - owner: KtTypeParameterListOwner, + owner: KtTypeParameterListOwner?, initialOrigin: FirDeclarationOrigin ) { private val typeParametersByName: Map @@ -51,8 +51,8 @@ internal class StubBasedFirTypeDeserializer( get() = typeParametersByName.values.toList() init { - val typeParameters = owner.typeParameters - if (typeParameters.isNotEmpty()) { + val typeParameters = owner?.typeParameters + if (!typeParameters.isNullOrEmpty()) { typeParametersByName = mutableMapOf() val builders = mutableListOf() for (typeParameter in typeParameters) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt index 27b0fff25d9..f56b49709e4 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirDeclarationForCompiledElementSearcher.kt @@ -70,7 +70,7 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid val classCandidate = when (symbolProvider) { is LLFirModuleWithDependenciesSymbolProvider -> { - symbolProvider.getClassLikeSymbolByFqNameWithoutDependencies(classId) + symbolProvider.getClassLikeSymbolByFqNameWithoutDependencies(declaration, classId) ?: symbolProvider.friendBuiltinsProvider?.getClassLikeSymbolByClassId(classId) } else -> { @@ -162,7 +162,7 @@ private fun FirSymbolProvider.findCallableCandidates( @OptIn(FirSymbolProviderInternals::class) return when (this) { is LLFirModuleWithDependenciesSymbolProvider -> buildList { - getTopLevelCallableSymbolsToWithoutDependencies(this, packageFqName, shortName) + getTopLevelDeserializedCallableSymbolsToWithoutDependencies(this, declaration, packageFqName, shortName) friendBuiltinsProvider?.getTopLevelCallableSymbolsTo(this, packageFqName, shortName) } else -> getTopLevelCallableSymbols(packageFqName, shortName)