[FIR IDE] Correctly collect containing declarations in init { ... }

`init` is not a callable declaration, and is considered local, so you
cannot build a designation starting from it. In that we case we traverse
parents until we find the first non-local class, and use it as a
container

KTIJ-21910
This commit is contained in:
Roman Golyshev
2022-06-03 12:48:30 +04:00
committed by Space
parent 0ee04d0825
commit e92cd609fb
@@ -11,20 +11,17 @@ import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFileSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirFileSymbol
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.analysis.api.impl.barebone.parentsOfType import org.jetbrains.kotlin.analysis.api.impl.barebone.parentsOfType
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithVisibility
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue
import org.jetbrains.kotlin.fir.visibilityChecker import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
internal class KtFirVisibilityChecker( internal class KtFirVisibilityChecker(
@@ -41,13 +38,8 @@ internal class KtFirVisibilityChecker(
require(candidateSymbol is KtFirSymbol<*>) require(candidateSymbol is KtFirSymbol<*>)
require(useSiteFile is KtFirFileSymbol) require(useSiteFile is KtFirFileSymbol)
val nonLocalContainingDeclaration = findContainingNonLocalDeclaration(position)
val useSiteFirFile = useSiteFile.firSymbol.fir val useSiteFirFile = useSiteFile.firSymbol.fir
val containers = nonLocalContainingDeclaration val containers = collectContainingDeclarations(position)
?.getOrBuildFirSafe<FirCallableDeclaration>(analysisSession.firResolveSession)
?.collectDesignation()
?.path
.orEmpty()
val explicitDispatchReceiver = receiverExpression val explicitDispatchReceiver = receiverExpression
?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveSession) ?.getOrBuildFirSafe<FirExpression>(analysisSession.firResolveSession)
@@ -64,13 +56,26 @@ internal class KtFirVisibilityChecker(
) )
} }
private fun findContainingNonLocalDeclaration(element: PsiElement): KtCallableDeclaration? { private fun collectContainingDeclarations(position: PsiElement): List<FirDeclaration> {
return element val nonLocalContainer = findContainingNonLocalDeclaration(position)
.parentsOfType<KtCallableDeclaration>() val nonLocalContainerFir = nonLocalContainer?.getOrBuildFirSafe<FirDeclaration>(analysisSession.firResolveSession)
.firstOrNull { it.isNotFromLocalClass } ?: return emptyList()
val designation = nonLocalContainerFir.collectDesignation()
return designation
.toSequence(includeTarget = true) // we include the starting declaration in case it is a class or an object
.toList()
} }
private val KtCallableDeclaration.isNotFromLocalClass private fun findContainingNonLocalDeclaration(element: PsiElement): KtDeclaration? {
return element
.parentsOfType<KtDeclaration>()
.firstOrNull { it.isNotLocal }
}
private val KtDeclaration.isNotLocal
get() = this is KtNamedFunction && (isTopLevel || containingClassOrObject?.isLocal == false) || get() = this is KtNamedFunction && (isTopLevel || containingClassOrObject?.isLocal == false) ||
this is KtProperty && (isTopLevel || containingClassOrObject?.isLocal == false) this is KtProperty && (isTopLevel || containingClassOrObject?.isLocal == false) ||
this is KtClassOrObject && (isTopLevel() || !isLocal)
} }