[LL API] Support FirScript declarations in declaration providers (KTIJ-21108)

This commit is contained in:
Yan Zhulanow
2023-03-02 17:09:07 +09:00
committed by Space Team
parent dc2e072af2
commit a350deaa4d
4 changed files with 32 additions and 20 deletions
@@ -49,6 +49,13 @@ internal class FileBasedKotlinDeclarationProvider(private val kotlinFile: KtFile
val (chunks, element) = tasks.removeFirst() val (chunks, element) = tasks.removeFirst()
assert(chunks.isNotEmpty()) assert(chunks.isNotEmpty())
if (element is KtScript) {
for (child in element.declarations) {
tasks.addLast(Task(chunks, child))
}
continue
}
if (element !is KtNamedDeclaration || element.nameAsName != chunks[0]) { if (element !is KtNamedDeclaration || element.nameAsName != chunks[0]) {
continue continue
} }
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util
import org.jetbrains.kotlin.analysis.utils.errors.requireWithAttachmentBuilder import org.jetbrains.kotlin.analysis.utils.errors.requireWithAttachmentBuilder
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.packageFqName import org.jetbrains.kotlin.fir.packageFqName
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
@@ -33,11 +30,17 @@ object FirElementFinder {
val classIdPathSegment = classId.relativeClassName.pathSegments() val classIdPathSegment = classId.relativeClassName.pathSegments()
var result: FirClassLikeDeclaration? = null var result: FirClassLikeDeclaration? = null
fun find(declarations: List<FirDeclaration>, classIdPathIndex: Int) { fun find(declarations: Iterable<FirDeclaration>, classIdPathIndex: Int) {
if (result != null) return if (result != null) return
val currentClassSegment = classIdPathSegment[classIdPathIndex] val currentClassSegment = classIdPathSegment[classIdPathIndex]
for (subDeclaration in declarations) { for (subDeclaration in declarations) {
if (subDeclaration is FirScript) {
val scriptDeclarations = subDeclaration.statements.asSequence().filterIsInstance<FirDeclaration>()
find(scriptDeclarations.asIterable(), classIdPathIndex)
continue
}
if (subDeclaration is FirClassLikeDeclaration && currentClassSegment == subDeclaration.symbol.name) { if (subDeclaration is FirClassLikeDeclaration && currentClassSegment == subDeclaration.symbol.name) {
if (classIdPathIndex == classIdPathSegment.lastIndex) { if (classIdPathIndex == classIdPathSegment.lastIndex) {
result = subDeclaration result = subDeclaration
@@ -61,9 +61,13 @@ internal fun KtElement.findSourceByTraversingWholeTree(
val firFile = containerFirFile ?: firFileBuilder.buildRawFirFileWithCaching(containingKtFile) val firFile = containerFirFile ?: firFileBuilder.buildRawFirFileWithCaching(containingKtFile)
val originalDeclaration = (this as? KtDeclaration)?.originalDeclaration val originalDeclaration = (this as? KtDeclaration)?.originalDeclaration
val isDeclaration = this is KtDeclaration val isDeclaration = this is KtDeclaration
return FirElementFinder.findElementIn(firFile, canGoInside = { it is FirRegularClass }) { firDeclaration -> return FirElementFinder.findElementIn(
firDeclaration.psi == this || isDeclaration && firDeclaration.psi == originalDeclaration firFile,
} canGoInside = { it is FirRegularClass || it is FirScript },
predicate = { firDeclaration ->
firDeclaration.psi == this || isDeclaration && firDeclaration.psi == originalDeclaration
}
)
} }
private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider( private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider(
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.psi.psiUtil package org.jetbrains.kotlin.psi.psiUtil
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
@@ -14,9 +13,9 @@ import org.jetbrains.kotlin.psi.*
internal object ClassIdCalculator { internal object ClassIdCalculator {
fun calculateClassId(declaration: KtClassLikeDeclaration): ClassId? { fun calculateClassId(declaration: KtClassLikeDeclaration): ClassId? {
var ktFile: KtFile? = null var ktFile: KtFile? = null
var element: PsiElement? = declaration
val containingClasses = mutableListOf<KtClassLikeDeclaration>() val containingClasses = mutableListOf<KtClassLikeDeclaration>()
while (element != null) {
for (element in declaration.parentsWithSelf) {
when (element) { when (element) {
is KtEnumEntry -> { is KtEnumEntry -> {
return null return null
@@ -24,24 +23,23 @@ internal object ClassIdCalculator {
is KtClassLikeDeclaration -> { is KtClassLikeDeclaration -> {
containingClasses += element containingClasses += element
} }
is KtObjectLiteralExpression -> {
return null
}
is KtFile -> { is KtFile -> {
ktFile = element ktFile = element
break break
} }
is KtDeclaration -> { is KtScript -> {
// Skip script parent
}
is KtDeclaration, is KtObjectLiteralExpression -> {
// Local declarations don't have a 'ClassId'
return null return null
} }
} }
element = element.parent
} }
if (ktFile == null) return null if (ktFile == null) return null
val relativeClassName = FqName.fromSegments( val relativeClassName = FqName.fromSegments(containingClasses.reversed().map { containingClass ->
containingClasses.reversed().map { containingClass -> containingClass.name ?: SpecialNames.NO_NAME_PROVIDED.asString()
containingClass.name ?: SpecialNames.NO_NAME_PROVIDED.asString() }
}
) )
return ClassId(ktFile.packageFqName, relativeClassName, /*local=*/false) return ClassId(ktFile.packageFqName, relativeClassName, /*local=*/false)
} }