[LL API] Get designation correctly for enum value members (KTIJ-23458)

Although being a 'KtClass' in the PSI, 'KtEnumEntry' is a callable in
Analysis API, and its direct members should also be treated as local.
This commit is contained in:
Yan Zhulanow
2022-11-01 23:15:23 +09:00
committed by teamcity
parent 4d41ac09df
commit b770e5d02f
4 changed files with 26 additions and 15 deletions
@@ -37,26 +37,21 @@ import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.isAncestor import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment
import org.jetbrains.kotlin.analysis.utils.errors.* import org.jetbrains.kotlin.analysis.utils.errors.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
object LowLevelFirApiFacadeForResolveOnAir { object LowLevelFirApiFacadeForResolveOnAir {
private fun findNonLocalParentMaybeSelf(position: KtElement): KtNamedDeclaration? {
private fun KtDeclaration.canBeEnclosingDeclaration(): Boolean = when (this) { return position.parentsWithSelf
is KtNamedFunction -> isTopLevel || containingClassOrObject?.isLocal == false .filterIsInstance<KtNamedDeclaration>()
is KtProperty -> isTopLevel || containingClassOrObject?.isLocal == false .filter { it is KtNamedFunction || it is KtProperty || (it is KtClassOrObject && it !is KtEnumEntry) || it is KtTypeAlias }
is KtClassOrObject -> !isLocal .filter { !KtPsiUtil.isLocal(it) && it.containingClassOrObject !is KtEnumEntry }
is KtTypeAlias -> isTopLevel() || containingClassOrObject?.isLocal == false .firstOrNull()
else -> false
} }
private fun findEnclosingNonLocalDeclaration(position: KtElement): KtNamedDeclaration? =
position.parentsOfType<KtNamedDeclaration>().firstOrNull { ktDeclaration ->
ktDeclaration.canBeEnclosingDeclaration()
}
private fun recordOriginalDeclaration(targetDeclaration: KtNamedDeclaration, originalDeclaration: KtNamedDeclaration) { private fun recordOriginalDeclaration(targetDeclaration: KtNamedDeclaration, originalDeclaration: KtNamedDeclaration) {
require(originalDeclaration.containingKtFile !== targetDeclaration.containingKtFile) require(originalDeclaration.containingKtFile !== targetDeclaration.containingKtFile)
val originalDeclarationParents = originalDeclaration.parentsOfType<KtDeclaration>().toList() val originalDeclarationParents = originalDeclaration.parentsOfType<KtDeclaration>().toList()
@@ -150,7 +145,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
require(originalFirResolveSession is LLFirResolvableResolveSession) require(originalFirResolveSession is LLFirResolvableResolveSession)
require(elementToAnalyze !is KtFile) { "KtFile for dependency element not supported" } require(elementToAnalyze !is KtFile) { "KtFile for dependency element not supported" }
val dependencyNonLocalDeclaration = findEnclosingNonLocalDeclaration(elementToAnalyze) val dependencyNonLocalDeclaration = findNonLocalParentMaybeSelf(elementToAnalyze)
?: return LLFirResolveSessionDepended( ?: return LLFirResolveSessionDepended(
originalFirResolveSession, originalFirResolveSession,
FileTowerProvider(elementToAnalyze.containingKtFile, onAirGetTowerContextForFile(originalFirResolveSession, originalKtFile)), FileTowerProvider(elementToAnalyze.containingKtFile, onAirGetTowerContextForFile(originalFirResolveSession, originalKtFile)),
@@ -216,7 +211,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
onAirCreatedDeclaration: Boolean, onAirCreatedDeclaration: Boolean,
collector: FirTowerDataContextCollector? = null, collector: FirTowerDataContextCollector? = null,
): FirElement { ): FirElement {
val nonLocalDeclaration = findEnclosingNonLocalDeclaration(replacement.from) val nonLocalDeclaration = findNonLocalParentMaybeSelf(replacement.from)
val originalFirFile = firResolveSession.getOrBuildFirFile(replacement.from.containingKtFile) val originalFirFile = firResolveSession.getOrBuildFirFile(replacement.from.containingKtFile)
if (nonLocalDeclaration == null) { if (nonLocalDeclaration == null) {
@@ -0,0 +1,7 @@
enum class Foo {
VALUE {
/*PLACE*/fun run() = 1
}
}
/*ONAIR*/fun box(): Int = 0
@@ -0,0 +1,3 @@
public final [BODY_RESOLVE] fun box(): R|kotlin/Int| {
^box Int(0)
}
@@ -30,6 +30,12 @@ public class FirOnAirResolveTestGenerated extends AbstractFirOnAirResolveTest {
runTest("analysis/low-level-api-fir/testdata/onAirResolve/classInClass.kt"); runTest("analysis/low-level-api-fir/testdata/onAirResolve/classInClass.kt");
} }
@Test
@TestMetadata("enumValueMember.kt")
public void testEnumValueMember() throws Exception {
runTest("analysis/low-level-api-fir/testdata/onAirResolve/enumValueMember.kt");
}
@Test @Test
@TestMetadata("fileAnnotation.kt") @TestMetadata("fileAnnotation.kt")
public void testFileAnnotation() throws Exception { public void testFileAnnotation() throws Exception {