[LL API] Add PSI-based declaration provider for files outside roots
Indices are not available in the IDE for files outside content roots, so a new provider acts as a single-file replacement. ^KTIJ-23937 Fixed
This commit is contained in:
+23
@@ -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<KtClassOrObject>()
|
||||
override fun getAllTypeAliasesByClassId(classId: ClassId) = emptyList<KtTypeAlias>()
|
||||
override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName) = emptySet<Name>()
|
||||
override fun getTopLevelProperties(callableId: CallableId) = emptyList<KtProperty>()
|
||||
override fun getTopLevelFunctions(callableId: CallableId) = emptyList<KtNamedFunction>()
|
||||
override fun getTopLevelCallableFiles(callableId: CallableId) = emptyList<KtFile>()
|
||||
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName) = emptySet<Name>()
|
||||
override fun findFilesForFacadeByPackage(packageFqName: FqName) = emptyList<KtFile>()
|
||||
override fun findFilesForFacade(facadeFqName: FqName) = emptyList<KtFile>()
|
||||
}
|
||||
+122
@@ -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<KtClassOrObject> {
|
||||
return listOfNotNull(getClassLikeDeclarationByClassId(classId) as? KtClassOrObject)
|
||||
}
|
||||
|
||||
override fun getAllTypeAliasesByClassId(classId: ClassId): Collection<KtTypeAlias> {
|
||||
val name = classId.relativeClassName.pathSegments().singleOrNull() ?: return emptyList()
|
||||
return getTopLevelDeclarations(classId.packageFqName, name)
|
||||
}
|
||||
|
||||
override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName): Set<Name> {
|
||||
return getTopLevelDeclarationNames<KtClassLikeDeclaration>(packageFqName)
|
||||
}
|
||||
|
||||
override fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty> {
|
||||
return getTopLevelCallables(callableId)
|
||||
}
|
||||
|
||||
override fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction> {
|
||||
return getTopLevelCallables(callableId)
|
||||
}
|
||||
|
||||
override fun getTopLevelCallableFiles(callableId: CallableId): Collection<KtFile> {
|
||||
return buildSet {
|
||||
getTopLevelProperties(callableId).mapTo(this) { it.containingKtFile }
|
||||
getTopLevelFunctions(callableId).mapTo(this) { it.containingKtFile }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> {
|
||||
return getTopLevelDeclarationNames<KtCallableDeclaration>(packageFqName)
|
||||
}
|
||||
|
||||
override fun findFilesForFacadeByPackage(packageFqName: FqName): Collection<KtFile> {
|
||||
if (kotlinFile.packageFqName != packageFqName) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return listOf(kotlinFile)
|
||||
}
|
||||
|
||||
override fun findFilesForFacade(facadeFqName: FqName): Collection<KtFile> {
|
||||
for (declaration in kotlinFile.declarations) {
|
||||
if (declaration !is KtClassLikeDeclaration) {
|
||||
return listOf(kotlinFile)
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private inline fun <reified T : KtCallableDeclaration> getTopLevelCallables(callableId: CallableId): Collection<T> {
|
||||
require(callableId.classId == null)
|
||||
return getTopLevelDeclarations(callableId.packageName, callableId.callableName)
|
||||
}
|
||||
|
||||
private inline fun <reified T : KtNamedDeclaration> getTopLevelDeclarations(packageFqName: FqName, name: Name): Collection<T> {
|
||||
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 <reified T : KtNamedDeclaration> getTopLevelDeclarationNames(packageFqName: FqName): Set<Name> {
|
||||
if (kotlinFile.packageFqName != packageFqName) {
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
return buildSet {
|
||||
for (declaration in kotlinFile.declarations) {
|
||||
if (declaration is T) {
|
||||
addIfNotNull(declaration.nameAsName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user