From 6dd01a2ff553e54fcefcde9364ac0cea1592b83f Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Thu, 20 Jan 2022 19:02:11 +0100 Subject: [PATCH] LL API: do not lazy resolve local declarations --- .../api/fir/FirModuleResolveStateDepended.kt | 7 +- .../api/fir/FirModuleResolveStateImpl.kt | 29 ++--- .../low/level/api/fir/IdeFirPhaseManager.kt | 1 - .../api/fir/file/structure/FileStructure.kt | 6 +- .../file/structure/FileStructureElement.kt | 11 +- .../lazy/resolve/FirLazyBodiesCalculator.kt | 28 ++--- .../resolve/FirLazyDeclarationResolver.kt | 101 +++++++----------- 7 files changed, 68 insertions(+), 115 deletions(-) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt index afbcf2698a0..8887418df5d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping -import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingKtFileIfAny import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile import org.jetbrains.kotlin.analysis.project.structure.KtModule @@ -62,11 +61,9 @@ internal class FirModuleResolveStateDepended( override fun getOrBuildFirFile(ktFile: KtFile): FirFile = originalState.getOrBuildFirFile(ktFile) - override fun resolveFirToPhase(declaration: D, toPhase: FirResolvePhase): D = + override fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) { originalState.resolveFirToPhase(declaration, toPhase) - - override fun resolveFirToResolveType(declaration: D, type: ResolveType): D = - originalState.resolveFirToResolveType(declaration, type) + } override fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? { val ktFile = declaration.containingKtFileIfAny ?: return null diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt index 443c739e0b1..928b23f8b1f 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateImpl.kt @@ -16,8 +16,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuild import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureCache import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver -import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.ResolveType -import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.lazyResolveDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession @@ -28,9 +26,9 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.getKtModule +import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase @@ -73,7 +71,7 @@ internal class FirModuleResolveStateImpl( ) override fun getOrBuildFirFile(ktFile: KtFile): FirFile = - firFileBuilder.buildRawFirFileWithCaching(ktFile, rootModuleSession.cache, preferLazyBodies = false) + firFileBuilder.buildRawFirFileWithCaching(ktFile, rootModuleSession.cache) override fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? = cache.getContainerFirFile(declaration) @@ -139,13 +137,13 @@ internal class FirModuleResolveStateImpl( } } - override fun resolveFirToPhase(declaration: D, toPhase: FirResolvePhase): D { - if (toPhase == FirResolvePhase.RAW_FIR) return declaration + override fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) { + if (toPhase == FirResolvePhase.RAW_FIR) return val fileCache = when (val session = declaration.moduleData.session) { is FirIdeSourcesSession -> session.cache - else -> return declaration + else -> return } - return firLazyDeclarationResolver.lazyResolveDeclaration( + firLazyDeclarationResolver. lazyResolveDeclaration( firDeclarationToResolve = declaration, moduleFileCache = fileCache, scopeSession = ScopeSession(), @@ -153,19 +151,4 @@ internal class FirModuleResolveStateImpl( checkPCE = true, ) } - - override fun resolveFirToResolveType(declaration: D, type: ResolveType): D { - if (type == ResolveType.NoResolve) return declaration - val fileCache = when (val session = declaration.moduleData.session) { - is FirIdeSourcesSession -> session.cache - else -> return declaration - } - return firLazyDeclarationResolver.lazyResolveDeclaration( - firDeclaration = declaration, - moduleFileCache = fileCache, - scopeSession = ScopeSession(), - toResolveType = type, - checkPCE = true, - ) - } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/IdeFirPhaseManager.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/IdeFirPhaseManager.kt index f6e538c6f5c..251d1d522ea 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/IdeFirPhaseManager.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/IdeFirPhaseManager.kt @@ -33,7 +33,6 @@ internal class IdeFirPhaseManager( scopeSession = ScopeSession(), toPhase = requiredPhase, checkPCE = true, - skipLocalDeclaration = true, ) } catch (e: Throwable) { sessionInvalidator.invalidate(fir.moduleData.session) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt index 21534f0af00..a93dfc8a86a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt @@ -116,7 +116,7 @@ internal class FileStructure private constructor( moduleFileCache, firFile ) - val resolvedDeclaration = firLazyDeclarationResolver.lazyResolveDeclaration( + firLazyDeclarationResolver.lazyResolveDeclaration( firDeclarationToResolve = firDeclaration, moduleFileCache = moduleFileCache, scopeSession = ScopeSession(), @@ -124,7 +124,7 @@ internal class FileStructure private constructor( checkPCE = true, ) return FileElementFactory.createFileStructureElement( - firDeclaration = resolvedDeclaration, + firDeclaration = firDeclaration, ktDeclaration = declaration, firFile = firFile, firFileLockProvider = moduleFileCache.firFileLockProvider @@ -133,7 +133,7 @@ internal class FileStructure private constructor( private fun createStructureElement(container: KtAnnotated): FileStructureElement = when (container) { is KtFile -> { - val firFile = firFileBuilder.buildRawFirFileWithCaching(ktFile, moduleFileCache, preferLazyBodies = true) + val firFile = firFileBuilder.buildRawFirFileWithCaching(ktFile, moduleFileCache) firLazyDeclarationResolver.resolveFileAnnotations( firFile = firFile, annotations = firFile.annotations, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt index 340c9a48160..b4ff178bd88 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt @@ -140,16 +140,13 @@ internal class ReanalyzableFunctionStructureElement( it.replaceResolvePhase(minOf(it.resolvePhase, upgradedPhase)) } - val resolvedDeclaration = firLazyDeclarationResolver.lazyResolveDeclaration( + firLazyDeclarationResolver.lazyResolveDeclaration( firDeclarationToResolve = originalFunction, moduleFileCache = cache, scopeSession = ScopeSession(), toPhase = FirResolvePhase.BODY_RESOLVE, checkPCE = true, ) - check(resolvedDeclaration === originalFunction) { - "Reanalysed declaration not expected to be updated" - } ReanalyzableFunctionStructureElement( firFile, @@ -203,16 +200,14 @@ internal class ReanalyzablePropertyStructureElement( replaceBodyResolveState(FirPropertyBodyResolveState.NOTHING_RESOLVED) } - val resolvedDeclaration = firLazyDeclarationResolver.lazyResolveDeclaration( + firLazyDeclarationResolver.lazyResolveDeclaration( firDeclarationToResolve = originalProperty, moduleFileCache = cache, scopeSession = ScopeSession(), toPhase = FirResolvePhase.BODY_RESOLVE, checkPCE = true, ) - check(resolvedDeclaration === originalProperty) { - "Reanalysed declaration not expected to be updated" - } + ReanalyzablePropertyStructureElement( firFile, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt index 13ae24fb709..bdac8778c68 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt @@ -5,6 +5,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.toPersistentList import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.fir.FirElement @@ -23,14 +26,14 @@ import org.jetbrains.kotlin.psi.KtSecondaryConstructor internal object FirLazyBodiesCalculator { fun calculateLazyBodiesInside(designation: FirDeclarationDesignation) { - designation.declaration.transform>( + designation.declaration.transform>( FirLazyBodiesCalculatorTransformer, - designation.toSequence(includeTarget = true).toMutableList() + designation.toSequence(includeTarget = false).toList().toPersistentList() ) } fun calculateLazyBodies(firFile: FirFile) { - firFile.transform>(FirLazyBodiesCalculatorTransformer, mutableListOf()) + firFile.transform>(FirLazyBodiesCalculatorTransformer, persistentListOf()) } fun calculateLazyBodiesForFunction(designation: FirDeclarationDesignation) { @@ -122,30 +125,29 @@ internal object FirLazyBodiesCalculator { || firProperty.getExplicitBackingField()?.initializer is FirLazyExpression } -private object FirLazyBodiesCalculatorTransformer : FirTransformer>() { +private object FirLazyBodiesCalculatorTransformer : FirTransformer>() { - override fun transformFile(file: FirFile, data: MutableList): FirFile { + override fun transformFile(file: FirFile, data: PersistentList): FirFile { file.declarations.forEach { it.transformSingle(this, data) } return file } - override fun transformElement(element: E, data: MutableList): E { + override fun transformElement(element: E, data: PersistentList): E { if (element is FirRegularClass) { - data.add(element) + val newList = data.add(element) element.declarations.forEach { - it.transformSingle(this, data) + it.transformSingle(this, newList) } - element.transformChildren(this, data) - data.removeLast() + element.transformChildren(this, newList) } return element } override fun transformSimpleFunction( simpleFunction: FirSimpleFunction, - data: MutableList + data: PersistentList ): FirSimpleFunction { if (simpleFunction.body is FirLazyBlock) { val designation = FirDeclarationDesignation(data, simpleFunction) @@ -156,7 +158,7 @@ private object FirLazyBodiesCalculatorTransformer : FirTransformer + data: PersistentList ): FirConstructor { if (constructor.body is FirLazyBlock) { val designation = FirDeclarationDesignation(data, constructor) @@ -165,7 +167,7 @@ private object FirLazyBodiesCalculatorTransformer : FirTransformer): FirProperty { + override fun transformProperty(property: FirProperty, data: PersistentList): FirProperty { if (FirLazyBodiesCalculator.needCalculatingLazyBodyForProperty(property)) { val designation = FirDeclarationDesignation(data, property) FirLazyBodiesCalculator.calculateLazyBodyForProperty(designation) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt index b9897a2b84c..159cb3df907 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirFileAnnotationsResolveTransformer import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirProviderInterceptorForIDE import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LazyTransformerFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration import org.jetbrains.kotlin.fir.FirElement @@ -24,15 +23,13 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor import org.jetbrains.kotlin.fir.expressions.FirAnnotation -import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector -import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassBody import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtEnumEntry internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBuilder) { /** @@ -227,18 +224,17 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui * @see lazyResolveDeclaration for ordinary resolve * @param firDeclarationToResolve target non-local declaration */ - fun lazyResolveDeclaration( - firDeclarationToResolve: D, + fun lazyResolveDeclaration( + firDeclarationToResolve: FirDeclaration, moduleFileCache: ModuleFileCache, scopeSession: ScopeSession, toPhase: FirResolvePhase, checkPCE: Boolean, - skipLocalDeclaration: Boolean = false, - ): D { - if (toPhase == FirResolvePhase.RAW_FIR) return firDeclarationToResolve + ) { + if (toPhase == FirResolvePhase.RAW_FIR) return if (toPhase == FirResolvePhase.IMPORTS) { if (fastTrackForImportsPhase(firDeclarationToResolve, moduleFileCache, checkPCE)) { - return firDeclarationToResolve + return } } when (firDeclarationToResolve) { @@ -249,9 +245,8 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui scopeSession, toPhase, checkPCE, - skipLocalDeclaration ) - return firDeclarationToResolve + return } is FirBackingField -> { @@ -261,7 +256,6 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui scopeSession, toPhase, checkPCE, - skipLocalDeclaration ) } @@ -273,51 +267,61 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui scopeSession = scopeSession, checkPCE = checkPCE, ) - return firDeclarationToResolve + return } + else -> {} } - if (!firDeclarationToResolve.isValidForResolve()) return firDeclarationToResolve - if (firDeclarationToResolve.resolvePhase >= toPhase) return firDeclarationToResolve + if (!firDeclarationToResolve.isValidForResolve()) return + if (firDeclarationToResolve.resolvePhase >= toPhase) return val requestedDeclarationDesignation = firDeclarationToResolve.tryCollectDesignationWithFile() val designation: FirDeclarationDesignationWithFile val neededPhase: FirResolvePhase - val isLocalDeclarationResolveRequested: Boolean + if (requestedDeclarationDesignation != null) { designation = requestedDeclarationDesignation neededPhase = toPhase - isLocalDeclarationResolveRequested = false } else { val possiblyLocalDeclaration = firDeclarationToResolve.getKtDeclarationForFirElement() val nonLocalDeclaration = possiblyLocalDeclaration.getNonLocalContainingOrThisDeclaration() ?: error("Container for local declaration cannot be null") - - isLocalDeclarationResolveRequested = + val isLocalDeclarationResolveRequested = possiblyLocalDeclaration != nonLocalDeclaration - if (isLocalDeclarationResolveRequested && skipLocalDeclaration) return firDeclarationToResolve - val nonLocalFirDeclaration = nonLocalDeclaration.findSourceNonLocalFirDeclaration( - firFileBuilder, - firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider, - moduleFileCache - ) + val declarationToResolve: FirDeclaration - neededPhase = if (isLocalDeclarationResolveRequested) FirResolvePhase.BODY_RESOLVE else toPhase + if (isLocalDeclarationResolveRequested) { + val enumEntry = possiblyLocalDeclaration.getContainingEnumEntryAsMemberOfEnumEntry() ?: return - if (nonLocalFirDeclaration.resolvePhase >= neededPhase) return firDeclarationToResolve - if (!nonLocalFirDeclaration.isValidForResolve()) return firDeclarationToResolve + declarationToResolve = enumEntry.findSourceNonLocalFirDeclaration( + firFileBuilder, + firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider, + moduleFileCache + ) + neededPhase = FirResolvePhase.BODY_RESOLVE + } else { + declarationToResolve = nonLocalDeclaration.findSourceNonLocalFirDeclaration( + firFileBuilder, + firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider, + moduleFileCache + ) + neededPhase = toPhase + } - designation = nonLocalFirDeclaration.collectDesignationWithFile() + if (declarationToResolve.resolvePhase >= neededPhase) return + if (!declarationToResolve.isValidForResolve()) return + + designation = declarationToResolve.collectDesignationWithFile() } - if (designation.declaration.resolvePhase >= neededPhase) return firDeclarationToResolve + if (designation.declaration.resolvePhase >= neededPhase) return if (neededPhase == FirResolvePhase.IMPORTS) { resolveFileToImports(designation.firFile, moduleFileCache, checkPCE) - return firDeclarationToResolve + return } moduleFileCache.firFileLockProvider.runCustomResolveUnderLock(designation.firFile, checkPCE) { @@ -332,33 +336,8 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui designation.declaration } } - - if (!isLocalDeclarationResolveRequested) return firDeclarationToResolve - return remapDeclarationInContainerIfNeeded(firDeclarationToResolve, designation.declaration, toPhase) } - private fun remapDeclarationInContainerIfNeeded( - declarationToRemap: D, - firContainer: FirDeclaration, - firResolvePhase: FirResolvePhase - ): D { - if (declarationToRemap.resolvePhase >= firResolvePhase) return declarationToRemap - val realPsi = declarationToRemap.realPsi - check(realPsi != null) { - "Cannot remap element without PSI" - } - @Suppress("UNCHECKED_CAST") - val firDeclaration = FirElementFinder.findElementIn(firContainer) { - it.realPsi == realPsi - } as? D - check(firDeclaration != null) { - "Containing declaration was resolved but local didn't found in it" - } - check(firDeclaration.resolvePhase >= firResolvePhase) { - "Found local declaration wasn't completely resolved" - } - return firDeclaration - } private fun runLazyDesignatedResolveWithoutLock( designation: FirDeclarationDesignationWithFile, @@ -433,10 +412,8 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui } } -private fun KtDeclaration.isMemberOfEnumEntry(container: KtDeclaration) : Boolean { - if (container !is KtClass) return false - if (!container.isEnum()) return false - val enumEntryBody = this.parent as? KtClassBody ?: return false - return enumEntryBody.parent == container +private fun KtDeclaration.getContainingEnumEntryAsMemberOfEnumEntry(): KtEnumEntry? { + val body = parent as? KtClassBody ?: return null + return body.parent as? KtEnumEntry }