[LL API] Move 'FileBasedKotlinDeclarationProvider' to be used in IDE

This commit is contained in:
Yan Zhulanow
2023-04-18 17:11:44 +09:00
committed by Space Team
parent bbe1e708f9
commit 5e04c0d4f7
4 changed files with 5 additions and 4 deletions
@@ -0,0 +1,171 @@
/*
* 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.providers.impl
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.yieldIfNotNull
public class FileBasedKotlinDeclarationProvider(public val kotlinFile: KtFile) : KotlinDeclarationProvider() {
private val topLevelDeclarations: Sequence<KtDeclaration>
get() {
return sequence {
for (child in kotlinFile.declarations) {
if (child is KtScript) {
yieldAll(child.declarations)
} else {
yield(child)
}
}
}
}
override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? {
return getClassLikeDeclarationsByClassId(classId).firstOrNull()
}
override fun getAllClassesByClassId(classId: ClassId): Collection<KtClassOrObject> {
return getClassLikeDeclarationsByClassId(classId).filterIsInstance<KtClassOrObject>().toList()
}
private fun getClassLikeDeclarationsByClassId(classId: ClassId): Sequence<KtClassLikeDeclaration> {
if (classId.isLocal) {
return emptySequence()
}
if (kotlinFile.packageFqName != classId.packageFqName) {
return emptySequence()
}
data class Task(val chunks: List<Name>, val element: KtElement)
return sequence {
val tasks = ArrayDeque<Task>()
val startingChunks = classId.relativeClassName.pathSegments()
for (declaration in topLevelDeclarations) {
tasks.addLast(Task(startingChunks, declaration))
}
tasks += Task(startingChunks, kotlinFile)
while (!tasks.isEmpty()) {
val (chunks, element) = tasks.removeFirst()
assert(chunks.isNotEmpty())
if (element !is KtNamedDeclaration || element.nameAsName != chunks[0]) {
continue
}
if (chunks.size == 1) {
yieldIfNotNull(element as? KtClassLikeDeclaration)
continue
}
if (element is KtDeclarationContainer) {
val newChunks = chunks.subList(1, chunks.size)
for (child in element.declarations) {
tasks.addLast(Task(newChunks, child))
}
}
}
}
}
override fun getAllTypeAliasesByClassId(classId: ClassId): Collection<KtTypeAlias> {
return getClassLikeDeclarationsByClassId(classId).filterIsInstance<KtTypeAlias>().toList()
}
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> {
if (kotlinFile.javaFileFacadeFqName != facadeFqName) return emptyList()
for (declaration in topLevelDeclarations) {
if (declaration !is KtClassLikeDeclaration) {
return listOf(kotlinFile)
}
}
return emptyList()
}
override fun findInternalFilesForFacade(facadeFqName: FqName): Collection<KtFile> = emptyList()
override fun computePackageSetWithTopLevelCallableDeclarations(): Set<String> {
return setOf(kotlinFile.packageFqName.asString())
}
override fun findFilesForScript(scriptFqName: FqName): Collection<KtScript> =
listOfNotNull(kotlinFile.script?.takeIf { it.fqName == scriptFqName })
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 topLevelDeclarations) {
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 topLevelDeclarations) {
if (declaration is T) {
addIfNotNull(declaration.nameAsName)
}
}
}
}
}