FIR IDE: introduce single function for checking if declaration can be lazily resolved

This commit is contained in:
Ilya Kirillov
2021-05-03 19:25:50 +02:00
parent babf079c31
commit 41ab97ff1f
6 changed files with 34 additions and 12 deletions
@@ -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
@@ -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<FirFile>) {
@@ -162,14 +161,14 @@ internal class NonReanalyzableDeclarationStructureElement(
private val recorder = object : FirElementsRecorder() {
override fun visitProperty(property: FirProperty, data: MutableMap<KtElement, FirElement>) {
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<KtElement, FirElement>) {
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)
}
}
@@ -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<*>) {
@@ -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}")
}
}
}
}
@@ -93,9 +93,6 @@ internal fun IdeaModuleInfo.collectTransitiveDependenciesWithSelf(): List<IdeaMo
return result.toList()
}
internal fun KtDeclaration.hasFqName(): Boolean =
parentsOfType<KtDeclaration>(withSelf = false).all { it.isNonAnonymousClassOrObject() }
internal fun KtDeclaration.isNonAnonymousClassOrObject() =
this is KtClassOrObject
&& !this.isObjectLiteral()
@@ -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> { ktDeclaration -> !KtPsiUtil.isLocal(ktDeclaration) }
val lazyDeclarations = ktFile.collectDescendantsOfType<KtDeclaration> { ktDeclaration ->
FirLazyDeclarationResolver.declarationCanBeLazilyResolved(ktDeclaration)
}
val declarationToResolve = lazyDeclarations.firstOrNull { it.name?.lowercase() == "resolveme" }
?: error("declaration with name `resolveMe` was not found")