[FIR IDE] Fix invalid body lazy resolve

This commit is contained in:
Igor Yakovlev
2021-05-06 14:57:39 +02:00
committed by TeamCityServer
parent cfc0bfd64a
commit 445f13d1bf
14 changed files with 192 additions and 80 deletions
@@ -6,13 +6,11 @@
package org.jetbrains.kotlin.fir.resolve.transformers package org.jetbrains.kotlin.fir.resolve.transformers
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
@@ -83,7 +81,7 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(
// Note that annotations are still visited here // Note that annotations are still visited here
// again, although there's no need in it // again, although there's no need in it
transformElement(firClass, data) transformDeclarationContent(firClass, data) as FirClass<*>
} }
} }
@@ -92,6 +90,10 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(
scopes.add(FirMemberTypeParameterScope(this)) scopes.add(FirMemberTypeParameterScope(this))
} }
} }
open fun transformDeclarationContent(declaration: FirDeclaration, data: Any?): FirDeclaration {
return transformElement(declaration, data)
}
} }
fun createSubstitutionForSupertype(superType: ConeLookupTagBasedType, session: FirSession): ConeSubstitutor { fun createSubstitutionForSupertype(superType: ConeLookupTagBasedType, session: FirSession): ConeSubstitutor {
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeCyclicTypeBound import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeCyclicTypeBound
import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.FirScope
@@ -38,7 +39,7 @@ fun <F : FirClassLikeDeclaration<F>> F.runTypeResolvePhaseForLocalClass(
} }
open class FirTypeResolveTransformer( open class FirTypeResolveTransformer(
override val session: FirSession, final override val session: FirSession,
scopeSession: ScopeSession, scopeSession: ScopeSession,
initialScopes: List<FirScope> = emptyList() initialScopes: List<FirScope> = emptyList()
) : FirAbstractTreeTransformerWithSuperTypes( ) : FirAbstractTreeTransformerWithSuperTypes(
@@ -52,7 +52,7 @@ open class FirContractResolveTransformer(
return annotationCall return annotationCall
} }
private class FirDeclarationsContractResolveTransformer(transformer: FirBodyResolveTransformer) : FirDeclarationsResolveTransformer(transformer) { protected open class FirDeclarationsContractResolveTransformer(transformer: FirBodyResolveTransformer) : FirDeclarationsResolveTransformer(transformer) {
override fun transformSimpleFunction( override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction, simpleFunction: FirSimpleFunction,
data: ResolutionMode data: ResolutionMode
@@ -224,11 +224,15 @@ open class FirContractResolveTransformer(
} }
} }
open fun transformDeclarationContent(firClass: FirClass<*>, data: ResolutionMode) {
firClass.transformDeclarations(this, data)
}
override fun transformRegularClass(regularClass: FirRegularClass, data: ResolutionMode): FirStatement { override fun transformRegularClass(regularClass: FirRegularClass, data: ResolutionMode): FirStatement {
regularClass.updatePhase() regularClass.updatePhase()
regularClass.transformCompanionObject(this, data) regularClass.transformCompanionObject(this, data)
context.withRegularClass(regularClass, components, forContracts = true) { context.withRegularClass(regularClass, components, forContracts = true) {
regularClass.transformDeclarations(this, data) transformDeclarationContent(regularClass, data)
} }
return regularClass return regularClass
} }
@@ -239,7 +243,7 @@ open class FirContractResolveTransformer(
): FirStatement { ): FirStatement {
anonymousObject.updatePhase() anonymousObject.updatePhase()
context.withAnonymousObject(anonymousObject, components) { context.withAnonymousObject(anonymousObject, components) {
anonymousObject.transformDeclarations(this, data) transformDeclarationContent(anonymousObject, data)
} }
return anonymousObject return anonymousObject
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.api package org.jetbrains.kotlin.idea.fir.low.level.api.api
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.builder.RawFirFragmentForLazyBodiesBuilder import org.jetbrains.kotlin.fir.builder.RawFirFragmentForLazyBodiesBuilder
import org.jetbrains.kotlin.fir.builder.RawFirReplacement import org.jetbrains.kotlin.fir.builder.RawFirReplacement
@@ -14,8 +15,6 @@ import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.util.getContainingFile
import org.jetbrains.kotlin.idea.util.getElementTextInContext
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
object DeclarationCopyBuilder { object DeclarationCopyBuilder {
@@ -59,6 +58,12 @@ object DeclarationCopyBuilder {
val originalFunction = rootNonLocalDeclaration.getOrBuildFirOfType<FirSimpleFunction>(state) val originalFunction = rootNonLocalDeclaration.getOrBuildFirOfType<FirSimpleFunction>(state)
val builtFunction = createCopy(rootNonLocalDeclaration, originalFunction, replacement) val builtFunction = createCopy(rootNonLocalDeclaration, originalFunction, replacement)
//TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers?
val functionBlock = rootNonLocalDeclaration.bodyBlockExpression
if (functionBlock == null || !PsiTreeUtil.isAncestor(functionBlock, replacement.from, true)) {
return builtFunction
}
// right now we can't resolve builtFunction header properly, as it built right in air, // right now we can't resolve builtFunction header properly, as it built right in air,
// without file, which is now required for running stages other then body resolve, so we // without file, which is now required for running stages other then body resolve, so we
// take original function header (which is resolved) and copy replacing body with body from builtFunction // take original function header (which is resolved) and copy replacing body with body from builtFunction
@@ -77,6 +82,12 @@ object DeclarationCopyBuilder {
val originalFirClass = rootNonLocalDeclaration.getOrBuildFirOfType<FirRegularClass>(state) val originalFirClass = rootNonLocalDeclaration.getOrBuildFirOfType<FirRegularClass>(state)
val builtClass = createCopy(rootNonLocalDeclaration, originalFirClass, replacement) val builtClass = createCopy(rootNonLocalDeclaration, originalFirClass, replacement)
//TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers?
val classBody = rootNonLocalDeclaration.body
if (classBody == null || !PsiTreeUtil.isAncestor(classBody, replacement.from, true)) {
return builtClass
}
return buildRegularClassCopy(originalFirClass) { return buildRegularClassCopy(originalFirClass) {
declarations.clear() declarations.clear()
declarations.addAll(builtClass.declarations) declarations.addAll(builtClass.declarations)
@@ -94,12 +105,13 @@ object DeclarationCopyBuilder {
val originalFirTypeAlias = rootNonLocalDeclaration.getOrBuildFirOfType<FirTypeAlias>(state) val originalFirTypeAlias = rootNonLocalDeclaration.getOrBuildFirOfType<FirTypeAlias>(state)
val builtTypeAlias = createCopy(rootNonLocalDeclaration, originalFirTypeAlias, replacement) val builtTypeAlias = createCopy(rootNonLocalDeclaration, originalFirTypeAlias, replacement)
return builtTypeAlias
return buildTypeAliasCopy(originalFirTypeAlias) { // return buildTypeAliasCopy(originalFirTypeAlias) {
expandedTypeRef = builtTypeAlias.expandedTypeRef // expandedTypeRef = builtTypeAlias.expandedTypeRef
symbol = builtTypeAlias.symbol // symbol = builtTypeAlias.symbol
initDeclaration(originalFirTypeAlias, builtTypeAlias, state) // initDeclaration(originalFirTypeAlias, builtTypeAlias, state)
} // }
} }
private fun <T : KtElement> createPropertyCopy( private fun <T : KtElement> createPropertyCopy(
@@ -110,6 +122,18 @@ object DeclarationCopyBuilder {
val originalProperty = rootNonLocalDeclaration.getOrBuildFirOfType<FirProperty>(state) val originalProperty = rootNonLocalDeclaration.getOrBuildFirOfType<FirProperty>(state)
val builtProperty = createCopy(rootNonLocalDeclaration, originalProperty, replacement) val builtProperty = createCopy(rootNonLocalDeclaration, originalProperty, replacement)
//TODO Check do we really need this optimisation? Maybe it is not optimisation at all because of Kt travers?
val insideGetterBody = rootNonLocalDeclaration.getter?.bodyBlockExpression?.let {
PsiTreeUtil.isAncestor(it, replacement.from, true)
} ?: false
if (!insideGetterBody) {
val insideSetterBody = rootNonLocalDeclaration.setter?.bodyBlockExpression?.let {
PsiTreeUtil.isAncestor(it, replacement.from, true)
} ?: false
if (!insideSetterBody) return builtProperty
}
val originalSetter = originalProperty.setter val originalSetter = originalProperty.setter
val builtSetter = builtProperty.setter val builtSetter = builtProperty.setter
@@ -69,7 +69,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
require(state is FirModuleResolveStateImpl) require(state is FirModuleResolveStateImpl)
require(place.isPhysical) require(place.isPhysical)
val declaration = runResolveBodyResolveOnAir( val declaration = runBodyResolveOnAir(
state = state, state = state,
replacement = RawFirReplacement(place, elementToResolve), replacement = RawFirReplacement(place, elementToResolve),
collector = null, collector = null,
@@ -102,7 +102,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
FileTowerProvider(place, onAirGetTowerContextForFile(state, place)) FileTowerProvider(place, onAirGetTowerContextForFile(state, place))
} else { } else {
FirTowerDataContextAllElementsCollector().also { FirTowerDataContextAllElementsCollector().also {
runResolveBodyResolveOnAir(state, collector = it, replacement = RawFirReplacement(place, place)) runBodyResolveOnAir(state, collector = it, replacement = RawFirReplacement(place, place))
} }
} }
} }
@@ -152,7 +152,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
) )
val collector = FirTowerDataContextAllElementsCollector() val collector = FirTowerDataContextAllElementsCollector()
val copiedFirDeclaration = runResolveBodyResolveOnAir( val copiedFirDeclaration = runBodyResolveOnAir(
originalState, originalState,
collector = collector, collector = collector,
replacement = RawFirReplacement(sameDeclarationInOriginalFile, dependencyNonLocalDeclaration), replacement = RawFirReplacement(sameDeclarationInOriginalFile, dependencyNonLocalDeclaration),
@@ -163,7 +163,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
return FirModuleResolveStateDepended(originalState, collector, recordedMap) return FirModuleResolveStateDepended(originalState, collector, recordedMap)
} }
private fun <T : KtElement> runResolveBodyResolveOnAir( private fun <T : KtElement> runBodyResolveOnAir(
state: FirModuleResolveStateImpl, state: FirModuleResolveStateImpl,
replacement: RawFirReplacement<T>, replacement: RawFirReplacement<T>,
collector: FirTowerDataContextCollector? = null, collector: FirTowerDataContextCollector? = null,
@@ -173,9 +173,7 @@ internal class FirLazyDeclarationResolver(
firProviderInterceptor: FirProviderInterceptorForSupertypeResolver?, firProviderInterceptor: FirProviderInterceptorForSupertypeResolver?,
designation: FirDeclarationDesignationWithFile designation: FirDeclarationDesignationWithFile
) { ) {
if (designation.toSequence(includeTarget = true).all { it.resolvePhase >= phase }) { if (designation.declaration.resolvePhase >= phase) return
return
}
val transformer = phase.createLazyTransformer( val transformer = phase.createLazyTransformer(
designation, designation,
@@ -220,7 +218,8 @@ internal class FirLazyDeclarationResolver(
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> FirDesignatedImplicitTypesTransformerForIDE( FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> FirDesignatedImplicitTypesTransformerForIDE(
designation, designation,
designation.firFile.moduleData.session, designation.firFile.moduleData.session,
scopeSession scopeSession,
towerDataContextCollector
) )
FirResolvePhase.BODY_RESOLVE -> FirDesignatedBodyResolveTransformerForIDE( FirResolvePhase.BODY_RESOLVE -> FirDesignatedBodyResolveTransformerForIDE(
designation, designation,
@@ -9,13 +9,14 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.* import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.*
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase
internal class FirDesignatedBodyResolveTransformerForIDE( internal class FirDesignatedBodyResolveTransformerForIDE(
private val designation: FirDeclarationDesignationWithFile, private val designation: FirDeclarationDesignationWithFile,
@@ -49,7 +50,13 @@ internal class FirDesignatedBodyResolveTransformerForIDE(
ideDeclarationTransformer.needReplacePhase ideDeclarationTransformer.needReplacePhase
override fun transformDeclaration() { override fun transformDeclaration() {
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextDependent) if (designation.declaration.resolvePhase >= FirResolvePhase.BODY_RESOLVE) return
designation.ensureTargetPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
ideDeclarationTransformer.ensureDesignationPassed()
//TODO Figure out why the phase is not updated
(designation.declaration as? FirTypeAlias)?.replaceResolvePhase(FirResolvePhase.BODY_RESOLVE)
designation.ensureTargetPhase(FirResolvePhase.BODY_RESOLVE)
} }
} }
@@ -6,12 +6,13 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.transformers package org.jetbrains.kotlin.idea.fir.low.level.api.transformers
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractResolveTransformer
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase
internal class FirDesignatedContractsResolveTransformerForIDE( internal class FirDesignatedContractsResolveTransformerForIDE(
private val designation: FirDeclarationDesignationWithFile, private val designation: FirDeclarationDesignationWithFile,
@@ -20,16 +21,34 @@ internal class FirDesignatedContractsResolveTransformerForIDE(
) : FirLazyTransformerForIDE, FirContractResolveTransformer(session, scopeSession) { ) : FirLazyTransformerForIDE, FirContractResolveTransformer(session, scopeSession) {
private val ideDeclarationTransformer = IDEDeclarationTransformer(designation) private val ideDeclarationTransformer = IDEDeclarationTransformer(designation)
override val declarationsTransformer: FirDeclarationsResolveTransformer = object : FirDeclarationsContractResolveTransformer(this) {
override fun transformDeclarationContent(firClass: FirClass<*>, data: ResolutionMode) {
ideDeclarationTransformer.transformDeclarationContent(this, firClass, data) {
super.transformDeclarationContent(firClass, data)
}
}
}
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration = override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration =
ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) { ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) {
super.transformDeclarationContent(declaration, data) super.transformDeclarationContent(declaration, data)
} }
override fun needReplacePhase(firDeclaration: FirDeclaration): Boolean = ideDeclarationTransformer.needReplacePhase override fun needReplacePhase(firDeclaration: FirDeclaration): Boolean = ideDeclarationTransformer.needReplacePhase
override fun transformDeclaration() { override fun transformDeclaration() {
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextDependent) if (designation.declaration.resolvePhase >= FirResolvePhase.CONTRACTS) return
val typeAlias = designation.declaration as? FirTypeAlias
if (typeAlias != null) {
//Nothing to do with typealias to CONTRACTS
typeAlias.replaceResolvePhase(FirResolvePhase.CONTRACTS)
return
}
designation.ensureTargetPhase(FirResolvePhase.STATUS)
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
ideDeclarationTransformer.ensureDesignationPassed()
designation.ensureTargetPhase(FirResolvePhase.CONTRACTS)
} }
} }
@@ -6,21 +6,23 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.transformers package org.jetbrains.kotlin.idea.fir.low.level.api.transformers
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ResolutionMode import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitAwareBodyResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitAwareBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.createReturnTypeCalculatorForIDE import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.createReturnTypeCalculatorForIDE
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirIdeDesignatedBodyResolveTransformerForReturnTypeCalculator
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase
internal class FirDesignatedImplicitTypesTransformerForIDE( internal class FirDesignatedImplicitTypesTransformerForIDE(
private val designation: FirDeclarationDesignationWithFile, private val designation: FirDeclarationDesignationWithFile,
session: FirSession, session: FirSession,
scopeSession: ScopeSession, scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector? = null,
implicitBodyResolveComputationSession: ImplicitBodyResolveComputationSession = ImplicitBodyResolveComputationSession(), implicitBodyResolveComputationSession: ImplicitBodyResolveComputationSession = ImplicitBodyResolveComputationSession(),
) : FirLazyTransformerForIDE, FirImplicitAwareBodyResolveTransformer( ) : FirLazyTransformerForIDE, FirImplicitAwareBodyResolveTransformer(
session, session,
@@ -28,6 +30,7 @@ internal class FirDesignatedImplicitTypesTransformerForIDE(
phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE, phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE,
implicitTypeOnly = true, implicitTypeOnly = true,
scopeSession = scopeSession, scopeSession = scopeSession,
firTowerDataContextCollector = towerDataContextCollector,
returnTypeCalculator = createReturnTypeCalculatorForIDE( returnTypeCalculator = createReturnTypeCalculatorForIDE(
session, session,
scopeSession, scopeSession,
@@ -46,6 +49,32 @@ internal class FirDesignatedImplicitTypesTransformerForIDE(
override fun needReplacePhase(firDeclaration: FirDeclaration): Boolean = ideDeclarationTransformer.needReplacePhase override fun needReplacePhase(firDeclaration: FirDeclaration): Boolean = ideDeclarationTransformer.needReplacePhase
override fun transformDeclaration() { override fun transformDeclaration() {
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextDependent) if (designation.declaration.resolvePhase >= FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) return
designation.ensureTargetPhase(FirResolvePhase.CONTRACTS)
when (val declaration = designation.declaration) {
is FirCallableDeclaration<*> -> {
//We don't need resolve callable declaration if it is already resolved (for ex. with TYPES)
if (declaration.returnTypeRef is FirResolvedTypeRef) {
declaration.replaceResolvePhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
return
}
}
is FirTypeAlias -> {
//Nothing to do with type alias to this phase
declaration.replaceResolvePhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
return
}
}
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
ideDeclarationTransformer.ensureDesignationPassed()
val callableDeclaration = designation.declaration as? FirCallableDeclaration<*>
check(callableDeclaration == null || callableDeclaration.returnTypeRef is FirResolvedTypeRef) {
"Callable declaration seems to be unresolved after ${FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE} phase"
}
designation.ensureTargetPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
} }
} }
@@ -14,13 +14,14 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.StatusComputationSession import org.jetbrains.kotlin.fir.resolve.transformers.StatusComputationSession
import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePhase import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePathPhase
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase
class FirDesignatedStatusResolveTransformerForIDE( class FirDesignatedStatusResolveTransformerForIDE(
private val designation: FirDeclarationDesignationWithFile, private val designation: FirDeclarationDesignationWithFile,
private val session: FirSession, private val session: FirSession,
private val scopeSession: ScopeSession, private val scopeSession: ScopeSession,
): FirLazyTransformerForIDE { ) : FirLazyTransformerForIDE {
private val firstItemInDesignation = designation.path.firstOrNull() ?: designation.declaration private val firstItemInDesignation = designation.path.firstOrNull() ?: designation.declaration
@@ -52,34 +53,33 @@ class FirDesignatedStatusResolveTransformerForIDE(
firstItemInDesignation.transformSingle(transformer, null) firstItemInDesignation.transformSingle(transformer, null)
} }
private fun resolveTopLevelMethod(targetCallable: FirCallableDeclaration<*>) { private fun resolveTopLevelDeclaration(declaration: FirDeclaration) {
val transformer = FirStatusResolveTransformer( val transformer = FirStatusResolveTransformer(
session = session, session = session,
scopeSession = scopeSession, scopeSession = scopeSession,
statusComputationSession = StatusComputationSession.Regular() statusComputationSession = StatusComputationSession.Regular()
) )
targetCallable.transformSingle(transformer, null) declaration.transformSingle(transformer, null)
} }
private fun resolveClassMember(containingClass: FirClass<*>, targetCallable: FirCallableDeclaration<*>) { private fun resolveClassMember(containingClass: FirClass<*>, targetCallable: FirDeclaration) {
val transformer = object : FirDesignatedStatusResolveTransformer( val transformer = object : FirDesignatedStatusResolveTransformer(
session = session, session = session,
scopeSession = scopeSession, scopeSession = scopeSession,
designation = designation.toSequence(includeTarget = true).iterator(), designation = designation.toSequence(includeTarget = true).iterator(),
targetClass = containingClass, targetClass = if (targetCallable is FirRegularClass) targetCallable else containingClass,
statusComputationSession = StatusComputationSession.Regular(), statusComputationSession = StatusComputationSession.Regular(),
designationMapForLocalClasses = emptyMap(), designationMapForLocalClasses = emptyMap(),
scopeForLocalClass = null scopeForLocalClass = null
) { ) {
override fun <F : FirClass<F>> transformClass( override fun <F : FirClass<F>> transformClass(klass: FirClass<F>, data: FirResolvedDeclarationStatus?): FirStatement {
klass: FirClass<F>, if (klass != containingClass) return super.transformClass(klass, data)
data: FirResolvedDeclarationStatus? val result = storeClass(klass) {
): FirStatement {
return storeClass(klass) {
targetCallable.transformSingle(this, data) targetCallable.transformSingle(this, data)
} as FirStatement }
return result as FirStatement
} }
} }
@@ -87,21 +87,18 @@ class FirDesignatedStatusResolveTransformerForIDE(
} }
override fun transformDeclaration() { override fun transformDeclaration() {
designation.ensurePhase(FirResolvePhase.STATUS, exceptTarget = true) if (designation.declaration.resolvePhase >= FirResolvePhase.STATUS) return
when (val resolveTarget = designation.declaration) { designation.ensurePathPhase(FirResolvePhase.TYPES)
is FirClass<*> -> resolveClass(resolveTarget) designation.ensureTargetPhase(FirResolvePhase.TYPES)
is FirTypeAlias -> resolveTypeAlias(resolveTarget)
is FirCallableDeclaration<*> -> { val containingClass = designation.path.lastOrNull()
val containingClass = designation.path.lastOrNull() if (containingClass == null) {
if (containingClass == null) { resolveTopLevelDeclaration(designation.declaration)
check(designation.path.isEmpty()) { "Invalid designation - should be single element designation for top level declaration" } } else {
resolveTopLevelMethod(resolveTarget) check(containingClass is FirClass<*>) { "Invalid designation - the parent is a class" }
} else { resolveClassMember(containingClass, designation.declaration)
check(containingClass is FirClass<*>) { "Invalid designation - the parent of callable is not a class" }
resolveClassMember(containingClass, resolveTarget)
}
}
else -> error("Unexpected declaration to resolve ${resolveTarget::class.simpleName}")
} }
designation.ensureTargetPhase(FirResolvePhase.STATUS)
} }
} }
@@ -13,9 +13,10 @@ import org.jetbrains.kotlin.fir.resolve.transformers.FirApplySupertypesTransform
import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver import org.jetbrains.kotlin.fir.resolve.transformers.FirProviderInterceptorForSupertypeResolver
import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverVisitor import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverVisitor
import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePhase import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePathPhase
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhaseIfClass
internal class FirDesignatedSupertypeResolverTransformerForIDE( internal class FirDesignatedSupertypeResolverTransformerForIDE(
private val designation: FirDeclarationDesignationWithFile, private val designation: FirDeclarationDesignationWithFile,
@@ -27,7 +28,8 @@ internal class FirDesignatedSupertypeResolverTransformerForIDE(
private val supertypeComputationSession = SupertypeComputationSession() private val supertypeComputationSession = SupertypeComputationSession()
override fun transformDeclaration() { override fun transformDeclaration() {
designation.ensurePhase(FirResolvePhase.SUPER_TYPES, exceptTarget = true) if (designation.declaration.resolvePhase >= FirResolvePhase.SUPER_TYPES) return
designation.ensurePathPhase(FirResolvePhase.SUPER_TYPES)
val resolver = FirSupertypeResolverVisitor( val resolver = FirSupertypeResolverVisitor(
session = session, session = session,
@@ -40,5 +42,6 @@ internal class FirDesignatedSupertypeResolverTransformerForIDE(
designation.declaration.accept(resolver, null) designation.declaration.accept(resolver, null)
val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession) val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession)
designation.declaration.transform<FirElement, Void?>(applySupertypesTransformer, null) designation.declaration.transform<FirElement, Void?>(applySupertypesTransformer, null)
designation.ensureTargetPhaseIfClass(FirResolvePhase.SUPER_TYPES)
} }
} }
@@ -5,13 +5,17 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.transformers package org.jetbrains.kotlin.idea.fir.low.level.api.transformers
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePhase import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensurePathPhase
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhase
import org.jetbrains.kotlin.idea.fir.low.level.api.transformers.FirLazyTransformerForIDE.Companion.ensureTargetPhaseIfClass
class FirDesignatedTypeResolverTransformerForIDE( class FirDesignatedTypeResolverTransformerForIDE(
private val designation: FirDeclarationDesignationWithFile, private val designation: FirDeclarationDesignationWithFile,
@@ -21,22 +25,21 @@ class FirDesignatedTypeResolverTransformerForIDE(
private val ideDeclarationTransformer = IDEDeclarationTransformer(designation) private val ideDeclarationTransformer = IDEDeclarationTransformer(designation)
@Suppress("NAME_SHADOWING") override fun <E : FirElement> transformElement(element: E, data: Any?): E {
override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): FirStatement { if (element !is FirRegularClass && element !is FirAnonymousObject && element !is FirFile)
return ideDeclarationTransformer.transformDeclarationContent(this, regularClass, data) { return super.transformElement(element, data)
super.transformRegularClass(regularClass, data) as FirRegularClass
}
}
@Suppress("NAME_SHADOWING") return ideDeclarationTransformer.transformDeclarationContent(this, element, data) {
override fun transformAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?): FirStatement { super.transformElement(element, data)
return ideDeclarationTransformer.transformDeclarationContent(this, anonymousObject, data) {
super.transformAnonymousObject(anonymousObject, data) as FirAnonymousObject
} }
} }
override fun transformDeclaration() { override fun transformDeclaration() {
designation.ensurePhase(FirResolvePhase.TYPES, exceptTarget = true) if (designation.declaration.resolvePhase >= FirResolvePhase.TYPES) return
designation.ensurePathPhase(FirResolvePhase.TYPES)
designation.ensureTargetPhaseIfClass(FirResolvePhase.SUPER_TYPES)
designation.firFile.transform<FirFile, Any?>(this, null) designation.firFile.transform<FirFile, Any?>(this, null)
ideDeclarationTransformer.ensureDesignationPassed()
designation.ensureTargetPhase(FirResolvePhase.TYPES)
} }
} }
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.transformers package org.jetbrains.kotlin.idea.fir.low.level.api.transformers
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignationWithFile
internal interface FirLazyTransformerForIDE { internal interface FirLazyTransformerForIDE {
@@ -16,13 +16,27 @@ internal interface FirLazyTransformerForIDE {
override fun transformDeclaration() = Unit override fun transformDeclaration() = Unit
} }
fun FirDeclarationDesignationWithFile.ensurePhase(firResolvePhase: FirResolvePhase, exceptTarget: Boolean) { fun FirDeclarationDesignationWithFile.ensurePathPhase(firResolvePhase: FirResolvePhase) {
val designationIterator = toSequence(includeTarget = !exceptTarget) toSequence(includeTarget = false).forEach { firDeclaration ->
designationIterator.forEach { firDeclaration ->
check(firDeclaration.resolvePhase >= firResolvePhase) { check(firDeclaration.resolvePhase >= firResolvePhase) {
"Designation element phase required to be $firResolvePhase but element resolved to ${firDeclaration.resolvePhase}" "Designation element phase required to be $firResolvePhase but element resolved to ${firDeclaration.resolvePhase}"
} }
} }
} }
fun FirDeclarationDesignationWithFile.ensureTargetPhase(firResolvePhase: FirResolvePhase) =
check(declaration.resolvePhase >= firResolvePhase) { "Expected $firResolvePhase but found ${declaration.resolvePhase}" }
fun FirDeclarationDesignationWithFile.ensureTargetPhaseIfClass(firResolvePhase: FirResolvePhase) = when (declaration) {
is FirProperty, is FirSimpleFunction -> Unit
is FirClass<*>, is FirTypeAlias -> ensureTargetPhase(firResolvePhase)
else -> error("Unexpected target")
}
fun FirDeclarationDesignationWithFile.ensureTargetPhaseIfMember(firResolvePhase: FirResolvePhase) = when (declaration) {
is FirProperty, is FirSimpleFunction -> ensureTargetPhase(firResolvePhase)
is FirClass<*>, is FirTypeAlias -> Unit
else -> error("Unexpected target")
}
} }
} }
@@ -26,11 +26,16 @@ internal class IDEDeclarationTransformer(private val designation: FirDeclaration
return defaultCallTransform() return defaultCallTransform()
} }
if (designationPassed) {
return declaration
}
if (designationWithoutTargetIterator.hasNext()) { if (designationWithoutTargetIterator.hasNext()) {
designationWithoutTargetIterator.next().visitNoTransform(transformer, data) designationWithoutTargetIterator.next().visitNoTransform(transformer, data)
} else { } else {
try { try {
isInsideTargetDeclaration = true isInsideTargetDeclaration = true
designationPassed = true
designation.declaration.visitNoTransform(transformer, data) designation.declaration.visitNoTransform(transformer, data)
} finally { } finally {
isInsideTargetDeclaration = false isInsideTargetDeclaration = false
@@ -41,6 +46,11 @@ internal class IDEDeclarationTransformer(private val designation: FirDeclaration
} }
val needReplacePhase: Boolean get() = isInsideTargetDeclaration val needReplacePhase: Boolean get() = isInsideTargetDeclaration
private var designationPassed: Boolean = false
fun ensureDesignationPassed() {
check(designationPassed) { "Designation not passed for declaration ${designation.declaration::class.simpleName}" }
}
} }
private fun <D> FirElement.visitNoTransform(transformer: FirTransformer<D>, data: D) { private fun <D> FirElement.visitNoTransform(transformer: FirTransformer<D>, data: D) {