diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/EmptyKotlinDeclarationProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/EmptyKotlinDeclarationProvider.kt new file mode 100644 index 00000000000..76ee5cdb087 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/EmptyKotlinDeclarationProvider.kt @@ -0,0 +1,23 @@ +/* + * 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.low.level.api.fir.project.structure + +import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider +import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.psi.* + +internal object EmptyKotlinDeclarationProvider : KotlinDeclarationProvider() { + override fun getClassLikeDeclarationByClassId(classId: ClassId) = null + override fun getAllClassesByClassId(classId: ClassId) = emptyList() + override fun getAllTypeAliasesByClassId(classId: ClassId) = emptyList() + override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName) = emptySet() + override fun getTopLevelProperties(callableId: CallableId) = emptyList() + override fun getTopLevelFunctions(callableId: CallableId) = emptyList() + override fun getTopLevelCallableFiles(callableId: CallableId) = emptyList() + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName) = emptySet() + override fun findFilesForFacadeByPackage(packageFqName: FqName) = emptyList() + override fun findFilesForFacade(facadeFqName: FqName) = emptyList() +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/FileBasedKotlinDeclarationProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/FileBasedKotlinDeclarationProvider.kt new file mode 100644 index 00000000000..93b8e5394a6 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/FileBasedKotlinDeclarationProvider.kt @@ -0,0 +1,122 @@ +/* + * Copyright 2010-2022 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.low.level.api.fir.project.structure + +import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider +import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.utils.addIfNotNull + +internal class FileBasedKotlinDeclarationProvider(private val kotlinFile: KtFile) : KotlinDeclarationProvider() { + override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? { + if (classId.isLocal) { + return null + } + + if (kotlinFile.packageFqName != classId.packageFqName) { + return null + } + + var current: KtElement = kotlinFile + + nextSegment@ for (segment in classId.relativeClassName.pathSegments()) { + val container = current as? KtDeclarationContainer ?: return null + for (child in container.declarations) { + if (child is KtClassLikeDeclaration && child.nameAsName == segment) { + current = child + continue@nextSegment + } + } + + return null + } + + return current as? KtClassLikeDeclaration + } + + override fun getAllClassesByClassId(classId: ClassId): Collection { + return listOfNotNull(getClassLikeDeclarationByClassId(classId) as? KtClassOrObject) + } + + override fun getAllTypeAliasesByClassId(classId: ClassId): Collection { + val name = classId.relativeClassName.pathSegments().singleOrNull() ?: return emptyList() + return getTopLevelDeclarations(classId.packageFqName, name) + } + + override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName): Set { + return getTopLevelDeclarationNames(packageFqName) + } + + override fun getTopLevelProperties(callableId: CallableId): Collection { + return getTopLevelCallables(callableId) + } + + override fun getTopLevelFunctions(callableId: CallableId): Collection { + return getTopLevelCallables(callableId) + } + + override fun getTopLevelCallableFiles(callableId: CallableId): Collection { + return buildSet { + getTopLevelProperties(callableId).mapTo(this) { it.containingKtFile } + getTopLevelFunctions(callableId).mapTo(this) { it.containingKtFile } + } + } + + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set { + return getTopLevelDeclarationNames(packageFqName) + } + + override fun findFilesForFacadeByPackage(packageFqName: FqName): Collection { + if (kotlinFile.packageFqName != packageFqName) { + return emptyList() + } + + return listOf(kotlinFile) + } + + override fun findFilesForFacade(facadeFqName: FqName): Collection { + for (declaration in kotlinFile.declarations) { + if (declaration !is KtClassLikeDeclaration) { + return listOf(kotlinFile) + } + } + + return emptyList() + } + + private inline fun getTopLevelCallables(callableId: CallableId): Collection { + require(callableId.classId == null) + return getTopLevelDeclarations(callableId.packageName, callableId.callableName) + } + + private inline fun getTopLevelDeclarations(packageFqName: FqName, name: Name): Collection { + if (kotlinFile.packageFqName != packageFqName) { + return emptyList() + } + + return buildList { + for (declaration in kotlinFile.declarations) { + if (declaration is T && declaration.nameAsName == name) { + add(declaration) + } + } + } + } + + private inline fun getTopLevelDeclarationNames(packageFqName: FqName): Set { + if (kotlinFile.packageFqName != packageFqName) { + return emptySet() + } + + return buildSet { + for (declaration in kotlinFile.declarations) { + if (declaration is T) { + addIfNotNull(declaration.nameAsName) + } + } + } + } +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt index 8d61c92ed0e..ee363d4cf2c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt @@ -17,7 +17,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirNonUnderCon import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionInvalidator import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule -import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createPackageProvider import org.jetbrains.kotlin.analysis.utils.caches.SoftCachedMap import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl @@ -35,6 +34,7 @@ import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.session.* import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver import org.jetbrains.kotlin.platform.jvm.JvmPlatforms +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver internal class LLFirNonUnderContentRootSessionFactory(private val project: Project) { @@ -75,10 +75,12 @@ internal class LLFirNonUnderContentRootSessionFactory(private val project: Proje registerResolveComponents() registerJavaSpecificResolveComponents() + val ktFile = module.file as? KtFile + val provider = LLFirProvider( this, components, - project.createDeclarationProvider(contentScope), + if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider, project.createPackageProvider(contentScope), canContainKotlinPackage = true, )