From a350deaa4d4a56d26cd8694d966f212372c26efc Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 2 Mar 2023 17:09:07 +0900 Subject: [PATCH] [LL API] Support FirScript declarations in declaration providers (KTIJ-21108) --- .../FileBasedKotlinDeclarationProvider.kt | 7 ++++++ .../util/FirNonLocalDeclarationSearcher.kt | 13 ++++++----- .../level/api/fir/util/declarationUtils.kt | 10 ++++++--- .../kotlin/psi/psiUtil/ClassIdCalculator.kt | 22 +++++++++---------- 4 files changed, 32 insertions(+), 20 deletions(-) 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 index 236c7927ed4..b49d83ac20b 100644 --- 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 @@ -49,6 +49,13 @@ internal class FileBasedKotlinDeclarationProvider(private val kotlinFile: KtFile val (chunks, element) = tasks.removeFirst() 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]) { continue } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirNonLocalDeclarationSearcher.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirNonLocalDeclarationSearcher.kt index c4aeb7f912e..8cf603a0772 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirNonLocalDeclarationSearcher.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/FirNonLocalDeclarationSearcher.kt @@ -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.fir.FirElement -import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration -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.* import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.packageFqName import org.jetbrains.kotlin.fir.render @@ -33,11 +30,17 @@ object FirElementFinder { val classIdPathSegment = classId.relativeClassName.pathSegments() var result: FirClassLikeDeclaration? = null - fun find(declarations: List, classIdPathIndex: Int) { + fun find(declarations: Iterable, classIdPathIndex: Int) { if (result != null) return val currentClassSegment = classIdPathSegment[classIdPathIndex] for (subDeclaration in declarations) { + if (subDeclaration is FirScript) { + val scriptDeclarations = subDeclaration.statements.asSequence().filterIsInstance() + find(scriptDeclarations.asIterable(), classIdPathIndex) + continue + } + if (subDeclaration is FirClassLikeDeclaration && currentClassSegment == subDeclaration.symbol.name) { if (classIdPathIndex == classIdPathSegment.lastIndex) { result = subDeclaration diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt index e2c41a30478..13cdc0171d1 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/declarationUtils.kt @@ -61,9 +61,13 @@ internal fun KtElement.findSourceByTraversingWholeTree( val firFile = containerFirFile ?: firFileBuilder.buildRawFirFileWithCaching(containingKtFile) val originalDeclaration = (this as? KtDeclaration)?.originalDeclaration val isDeclaration = this is KtDeclaration - return FirElementFinder.findElementIn(firFile, canGoInside = { it is FirRegularClass }) { firDeclaration -> - firDeclaration.psi == this || isDeclaration && firDeclaration.psi == originalDeclaration - } + return FirElementFinder.findElementIn( + firFile, + canGoInside = { it is FirRegularClass || it is FirScript }, + predicate = { firDeclaration -> + firDeclaration.psi == this || isDeclaration && firDeclaration.psi == originalDeclaration + } + ) } private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider( diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ClassIdCalculator.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ClassIdCalculator.kt index 5924820d030..c5bf6e3703f 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ClassIdCalculator.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ClassIdCalculator.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.psi.psiUtil -import com.intellij.psi.PsiElement import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.SpecialNames @@ -14,9 +13,9 @@ import org.jetbrains.kotlin.psi.* internal object ClassIdCalculator { fun calculateClassId(declaration: KtClassLikeDeclaration): ClassId? { var ktFile: KtFile? = null - var element: PsiElement? = declaration val containingClasses = mutableListOf() - while (element != null) { + + for (element in declaration.parentsWithSelf) { when (element) { is KtEnumEntry -> { return null @@ -24,24 +23,23 @@ internal object ClassIdCalculator { is KtClassLikeDeclaration -> { containingClasses += element } - is KtObjectLiteralExpression -> { - return null - } is KtFile -> { ktFile = element break } - is KtDeclaration -> { + is KtScript -> { + // Skip script parent + } + is KtDeclaration, is KtObjectLiteralExpression -> { + // Local declarations don't have a 'ClassId' return null } } - element = element.parent } if (ktFile == null) return null - val relativeClassName = FqName.fromSegments( - containingClasses.reversed().map { containingClass -> - containingClass.name ?: SpecialNames.NO_NAME_PROVIDED.asString() - } + val relativeClassName = FqName.fromSegments(containingClasses.reversed().map { containingClass -> + containingClass.name ?: SpecialNames.NO_NAME_PROVIDED.asString() + } ) return ClassId(ktFile.packageFqName, relativeClassName, /*local=*/false) }