From 41ab97ff1f6ad545d6ec3c2fe6c86a08e43e29d3 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 3 May 2021 19:25:50 +0200 Subject: [PATCH] FIR IDE: introduce single function for checking if declaration can be lazily resolved --- .../api/element/builder/FirElementBuilder.kt | 4 ++-- .../file/structure/FileStructureElement.kt | 5 ++-- .../api/file/structure/FileStructureUtil.kt | 4 +++- .../resolve/FirLazyDeclarationResolver.kt | 24 ++++++++++++++++++- .../idea/fir/low/level/api/util/utils.kt | 3 --- .../AbstractFirLazyDeclarationResolveTest.kt | 6 +++-- 6 files changed, 34 insertions(+), 12 deletions(-) diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt index 6cdade1e029..d7e9e933a16 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/element/builder/FirElementBuilder.kt @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FileStructureElement -import org.jetbrains.kotlin.idea.fir.low.level.api.util.hasFqName +import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.util.isNonAnonymousClassOrObject import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.psi.* @@ -112,7 +112,7 @@ internal inline fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: if (container is KtNamedDeclaration && (container.isNonAnonymousClassOrObject() || container is KtDeclarationWithBody || container is KtProperty || container is KtTypeAlias) && container !is KtPrimaryConstructor - && container.hasFqName() + && FirLazyDeclarationResolver.declarationCanBeLazilyResolved(container) && container !is KtEnumEntry && container !is KtFunctionLiteral && container.containingClassOrObject !is KtEnumEntry diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt index 35c6a4b75ed..5305627e4fa 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureElement.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.LockProvider import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.providers.FirIdeProvider -import org.jetbrains.kotlin.idea.fir.low.level.api.util.hasFqName import org.jetbrains.kotlin.psi.* internal sealed class FileStructureElement(val firFile: FirFile, protected val lockProvider: LockProvider) { @@ -162,14 +161,14 @@ internal class NonReanalyzableDeclarationStructureElement( private val recorder = object : FirElementsRecorder() { override fun visitProperty(property: FirProperty, data: MutableMap) { val psi = property.psi as? KtProperty ?: return super.visitProperty(property, data) - if (!FileElementFactory.isReanalyzableContainer(psi) || !psi.hasFqName()) { + if (!FileElementFactory.isReanalyzableContainer(psi) || !FirLazyDeclarationResolver.declarationCanBeLazilyResolved(psi)) { super.visitProperty(property, data) } } override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: MutableMap) { val psi = simpleFunction.psi as? KtNamedFunction ?: return super.visitSimpleFunction(simpleFunction, data) - if (!FileElementFactory.isReanalyzableContainer(psi) || !psi.hasFqName()) { + if (!FileElementFactory.isReanalyzableContainer(psi) || !FirLazyDeclarationResolver.declarationCanBeLazilyResolved(psi)) { super.visitSimpleFunction(simpleFunction, data) } } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureUtil.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureUtil.kt index cd2e100caca..0ef96a797bf 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureUtil.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/file/structure/FileStructureUtil.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache +import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.util.replaceFirst import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject @@ -22,7 +23,8 @@ internal object FileStructureUtil { ktDeclaration !is KtClassOrObject && ktDeclaration !is KtDeclarationWithBody && ktDeclaration !is KtProperty && ktDeclaration !is KtTypeAlias -> false ktDeclaration is KtEnumEntry -> false ktDeclaration.containingClassOrObject is KtEnumEntry -> false - else -> !KtPsiUtil.isLocal(ktDeclaration) + ktDeclaration is KtNamedDeclaration -> !FirLazyDeclarationResolver.declarationCanBeLazilyResolved(ktDeclaration) + else -> false } fun replaceDeclaration(firFile: FirFile, from: FirCallableDeclaration<*>, to: FirCallableDeclaration<*>) { diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt index 2f39745f4ec..f2161b36112 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/lazy/resolve/FirLazyDeclarationResolver.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.trasformers.FirDesignatedImpl import org.jetbrains.kotlin.idea.fir.low.level.api.trasformers.FirFileAnnotationsResolveTransformer import org.jetbrains.kotlin.idea.fir.low.level.api.util.* import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject internal class FirLazyDeclarationResolver( private val firFileBuilder: FirFileBuilder @@ -235,7 +236,7 @@ internal class FirLazyDeclarationResolver( private fun FirDeclaration.getNonLocalDeclarationToResolve(provider: FirProvider, moduleFileCache: ModuleFileCache): FirDeclaration { if (this is FirFile) return this val ktDeclaration = psi as? KtDeclaration ?: error("FirDeclaration should have a PSI of type KtDeclaration") - if (!KtPsiUtil.isLocal(ktDeclaration)) return this + if (declarationCanBeLazilyResolved(ktDeclaration)) return this val nonLocalPsi = ktDeclaration.getNonLocalContainingOrThisDeclaration() ?: error("Container for local declaration cannot be null") return nonLocalPsi.findSourceNonLocalFirDeclaration(firFileBuilder, provider.symbolProvider, moduleFileCache) @@ -243,5 +244,26 @@ internal class FirLazyDeclarationResolver( companion object { private val LAST_NON_LAZY_PHASE = FirResolvePhase.STATUS + + fun declarationCanBeLazilyResolved(declaration: KtDeclaration): Boolean { + return when (declaration) { + !is KtNamedDeclaration -> false + is KtDestructuringDeclarationEntry, is KtFunctionLiteral, is KtTypeParameter -> false + is KtPrimaryConstructor -> false + is KtParameter -> { + if (declaration.hasValOrVar()) declaration.containingClassOrObject?.getClassId() != null + else false + } + is KtCallableDeclaration, is KtEnumEntry -> { + when (val parent = declaration.parent) { + is KtFile -> true + is KtClassBody -> (parent.parent as? KtClassOrObject)?.getClassId() != null + else -> false + } + } + is KtClassLikeDeclaration -> declaration.getClassId() != null + else -> error("Unexpected ${declaration::class.qualifiedName}") + } + } } } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/utils.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/utils.kt index c4a46048052..566a7228870 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/utils.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/util/utils.kt @@ -93,9 +93,6 @@ internal fun IdeaModuleInfo.collectTransitiveDependenciesWithSelf(): List(withSelf = false).all { it.isNonAnonymousClassOrObject() } - internal fun KtDeclaration.isNonAnonymousClassOrObject() = this is KtClassOrObject && !this.isObjectLiteral() diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt index fc4b338df87..a1601d3e63f 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt @@ -11,11 +11,11 @@ import org.jetbrains.kotlin.fir.FirRenderer import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration +import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType import org.jetbrains.kotlin.test.KotlinTestUtils import java.io.File @@ -29,7 +29,9 @@ abstract class AbstractFirLazyDeclarationResolveTest : KotlinLightCodeInsightFix fun doTest(path: String) { val testDataFile = File(path) val ktFile = myFixture.configureByText(testDataFile.name, FileUtil.loadFile(testDataFile)) as KtFile - val lazyDeclarations = ktFile.collectDescendantsOfType { ktDeclaration -> !KtPsiUtil.isLocal(ktDeclaration) } + val lazyDeclarations = ktFile.collectDescendantsOfType { ktDeclaration -> + FirLazyDeclarationResolver.declarationCanBeLazilyResolved(ktDeclaration) + } val declarationToResolve = lazyDeclarations.firstOrNull { it.name?.lowercase() == "resolveme" } ?: error("declaration with name `resolveMe` was not found")