[LL FIR] KDoc here and there

This commit is contained in:
Dmitrii Gridin
2024-02-16 18:37:03 +01:00
committed by Space Team
parent 8525a39579
commit 71f9c101a1
26 changed files with 404 additions and 47 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -9,8 +9,8 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLDiagnosticProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLModuleResolutionStrategyProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLModuleProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLModuleResolutionStrategyProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLScopeSessionProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLSessionProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModule
@@ -57,11 +57,21 @@ abstract class LLFirResolveSession(
}
/**
* Build fully resolved FIR node for a requested element.
* This operation could be time-consuming because it creates FileStructureElement
* and resolves non-local declaration into BODY phase.
* Please use [getOrBuildFirFile] to get [FirFile] in undefined phase
* Build [FirElement] node in its final resolved state for a requested element.
*
* Note: that it isn't always [BODY_RESOLVE][FirResolvePhase.BODY_RESOLVE]
* as not all declarations have types/bodies/etc. to resolve.
*
* This operation could be time-consuming because it creates
* [FileStructureElement][org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureElement]
* and may resolve non-local declarations into [BODY_RESOLVE][FirResolvePhase.BODY_RESOLVE] phase.
*
* Please use [getOrBuildFirFile] to get [FirFile] in undefined phase.
*
* @return associated [FirElement] in final resolved state if it exists.
*
* @see getOrBuildFirFile
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder.getOrBuildFirFor
*/
internal abstract fun getOrBuildFirFor(element: KtElement): FirElement?
@@ -70,10 +80,16 @@ abstract class LLFirResolveSession(
*/
internal abstract fun getOrBuildFirFile(ktFile: KtFile): FirFile
/**
* @see LLDiagnosticProvider.getDiagnostics
*/
internal fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> {
return diagnosticProvider.getDiagnostics(element, filter)
}
/**
* @see LLDiagnosticProvider.collectDiagnostics
*/
internal fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection<KtPsiDiagnostic> {
return diagnosticProvider.collectDiagnostics(ktFile, filter)
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -8,10 +8,8 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -89,11 +87,21 @@ fun KtFile.collectDiagnosticsForFile(
firResolveSession.collectDiagnosticsForFile(this, filter)
/**
* Get a [FirElement] which was created by [KtElement]
* Returned [FirElement] is guaranteed to be resolved to [FirResolvePhase.BODY_RESOLVE] phase
* This operation could be performance affective because it create FIleStructureElement and resolve non-local declaration into BODY phase.
* Build [FirElement] node in its final resolved state for a requested element.
*
* The `null` value is returned iff FIR tree does not have corresponding element
* Note: that it isn't always [BODY_RESOLVE][FirResolvePhase.BODY_RESOLVE]
* as not all declarations have types/bodies/etc. to resolve.
*
* This operation could be time-consuming because it creates
* [FileStructureElement][org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureElement]
* and may resolve non-local declarations into [BODY_RESOLVE][FirResolvePhase.BODY_RESOLVE] phase.
*
* Please use [getOrBuildFirFile] to get [FirFile] in undefined phase.
*
* @return associated [FirElement] in final resolved state if it exists.
*
* @see getOrBuildFirFile
* @see LLFirResolveSession.getOrBuildFirFor
*/
fun KtElement.getOrBuildFir(
firResolveSession: LLFirResolveSession,
@@ -22,6 +22,12 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
import org.jetbrains.kotlin.util.withSourceCodeAnalysisExceptionUnwrapping
/**
* Collects [FileStructureElementDiagnosticList] for specific [declaration].
*
* @see FileStructureElementDiagnostics
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureElement
*/
internal sealed class FileStructureElementDiagnosticRetriever(
val declaration: FirDeclaration,
private val file: FirFile,
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -10,6 +10,9 @@ import com.intellij.util.SmartList
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
/**
* @see FileStructureElementDiagnosticsCollector
*/
internal class FileStructureElementDiagnostics(private val retriever: FileStructureElementDiagnosticRetriever) {
private val diagnosticByCommonCheckers: FileStructureElementDiagnosticList by lazy {
retriever.retrieve(FileStructureElementDiagnosticsCollector.USUAL_COLLECTOR)
@@ -40,12 +40,18 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
/**
* This class is responsible for mapping from [KtElement] to [FirElement]
* using [FileStructure][org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructure].
*
* @see getOrBuildFirFor
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructure
* @see getNonLocalContainingDeclaration
*/
@ThreadSafe
internal class FirElementBuilder(
private val moduleComponents: LLFirModuleResolveComponents,
) {
internal class FirElementBuilder(private val moduleComponents: LLFirModuleResolveComponents) {
companion object {
fun getPsiAsFirElementSource(element: KtElement): KtElement? {
private fun getPsiAsFirElementSource(element: KtElement): KtElement? {
val deparenthesized = if (element is KtExpression) KtPsiUtil.safeDeparenthesize(element) else element
return when {
deparenthesized is KtPropertyDelegate -> deparenthesized.expression ?: element
@@ -67,13 +73,29 @@ internal class FirElementBuilder(
else -> deparenthesized
}
}
private fun doKtElementHasCorrespondingFirElement(ktElement: KtElement): Boolean = when (ktElement) {
is KtImportList -> false
else -> true
}
}
fun doKtElementHasCorrespondingFirElement(ktElement: KtElement): Boolean = when (ktElement) {
is KtImportList -> false
else -> true
}
/**
* Returns a [FirElement] in its final resolved state.
*
* Note: that it isn't always [BODY_RESOLVE][FirResolvePhase.BODY_RESOLVE]
* as not all declarations have types/bodies/etc. to resolve.
*
* For instance, [KtPackageDirective] has nothing to resolve,
* so it will be returned as is ([FirPackageDirective][org.jetbrains.kotlin.fir.FirPackageDirective]),
* with the [RAW_FIR][FirResolvePhase.RAW_FIR] phase.
*
* @return associated [FirElement] in final resolved state if it exists.
*
* @see getFirForElementInsideAnnotations
* @see getFirForElementInsideTypes
* @see getFirForElementInsideFileHeader
*/
fun getOrBuildFirFor(element: KtElement): FirElement? {
return if (element is KtFile && element !is KtCodeFragment) {
getOrBuildFirForKtFile(element)
@@ -306,6 +328,12 @@ private fun KtDeclaration.isPartOf(callableDeclaration: KtCallableDeclaration):
internal val KtTypeParameter.containingDeclaration: KtDeclaration?
get() = (parent as? KtTypeParameterList)?.parent as? KtDeclaration
/**
* Returns **true** if [this] declaration is a unit of resolution and can be treated as non-local.
* The property is supposed to be used only in the pair with [getNonLocalContainingDeclaration] or [getNonLocalContainingOrThisDeclaration]
*
* @see getNonLocalContainingDeclaration
*/
internal val KtDeclaration.isAutonomousDeclaration: Boolean
get() = when (this) {
is KtPropertyAccessor, is KtParameter, is KtTypeParameter -> false
@@ -316,6 +344,14 @@ internal fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: (KtDec
return getNonLocalContainingDeclaration(parentsWithSelf, predicate)
}
/**
* Returns the first non-local declaration from [elementsToCheck] that contains the given elements,
* based on the specified predicate.
*
* The resulting declaration can be considered reachable at [RAW_FIR][FirResolvePhase.RAW_FIR] phase.
*
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructure
*/
internal fun getNonLocalContainingDeclaration(
elementsToCheck: Sequence<PsiElement>,
predicate: (KtDeclaration) -> Boolean = { true },
@@ -339,7 +375,7 @@ internal fun getNonLocalContainingDeclaration(
parent is KtCodeFragment ||
parent is PsiErrorElement
) {
// Candidate turned out to be local. Let's find another one.
// The candidate turned out to be local. Let's find another one.
candidate = null
}
}
@@ -18,7 +18,14 @@ import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
import java.util.concurrent.locks.ReentrantLock
/**
* Keyed locks provider.
* This class is responsible for the locking strategy in the lazy resolution mode.
* Each [FirElementWithResolveState] have [FirResolveState] which is used by this provider
* to build the lock system.
*
* @see LLFirLazyResolveContractChecker
* @see withWriteLock
* @see withReadLock
* @see withJumpingLock
*/
internal class LLFirLockProvider(private val checker: LLFirLazyResolveContractChecker) {
private val globalLock = ReentrantLock()
@@ -31,6 +31,25 @@ import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
import java.util.concurrent.ConcurrentHashMap
/**
* Aggregates [KT][KtElement] -> [FIR][org.jetbrains.kotlin.fir.FirElement] mappings and diagnostics for associated [KtFile].
*
* For every [KtFile] we need mapping for, we have [FileStructure] which contains a tree like-structure of [FileStructureElement].
*
* When we want to get `KT -> FIR` mapping,
* we [getOrPut][getStructureElementFor] [FileStructureElement] for the closest non-local declaration
* which contains the requested [KtElement].
*
* Some of [FileStructureElement] can be invalidated in the case on in-block PSI modification.
* See [invalidateElement] and [LLFirDeclarationModificationService] for details.
*
* The mapping is an optimization to avoid searching for the associated [FirElement][org.jetbrains.kotlin.fir.FirElement]
* by [KtElement] as it requires deep traverse through the main element of [FileStructureElement].
*
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder
* @see FileStructureElement
* @see LLFirDeclarationModificationService
*/
internal class FileStructure private constructor(
private val ktFile: KtFile,
private val firFile: FirFile,
@@ -56,12 +75,16 @@ internal class FileStructure private constructor(
* This method is responsible for "invalidation" of re-analyzable declarations.
*
* @see LLFirDeclarationModificationService
* @see getNonLocalReanalyzableContainingDeclaration
*/
fun invalidateElement(element: KtElement) {
val container = getContainerKtElement(element)
structureElements.remove(container)
}
/**
* @return [FileStructureElement] for the closest non-local declaration which contains this [element].
*/
fun getStructureElementFor(element: KtElement): FileStructureElement {
val container = getContainerKtElement(element)
return structureElements.getOrPut(container) { createStructureElement(container) }
@@ -24,6 +24,14 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
/**
* Collects [KT -> FIR][KtToFirMapping] mapping and [diagnostics][FileStructureElementDiagnostics] for [declaration].
*
* @param declaration is a fully resolved declaration
*
* @see FileStructure
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnosticsCollector
*/
internal sealed class FileStructureElement(
val declaration: FirDeclaration,
val diagnostics: FileStructureElementDiagnostics,
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck
*
* In case of non-local changes (out-of-block modification), this service will publish event to [MODULE_OUT_OF_BLOCK_MODIFICATION].
*
* @see getNonLocalReanalyzableContainingDeclaration
* @see MODULE_OUT_OF_BLOCK_MODIFICATION
* @see org.jetbrains.kotlin.analysis.providers.topics.KotlinModuleOutOfBlockModificationListener
*/
@@ -113,7 +114,8 @@ class LLFirDeclarationModificationService(val project: Project) : Disposable {
}
/**
* Force the service to publish delayed modifications. This action is required to fix inconsistencies in FirFile tree.
* Force the service to publish delayed modifications.
* This action is required to fix inconsistencies in [FirFile][org.jetbrains.kotlin.fir.declarations.FirFile] tree.
*/
fun flushModifications() {
ApplicationManager.getApplication().assertIsWriteThread()
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -9,6 +9,12 @@ import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.symbols.FirLazyResolveContractViolationException
/**
* Checks a lazy resolve call's compliance with [FirResolvePhase] contracts.
*
* @see FirResolvePhase
* @see FirLazyResolveContractViolationException
*/
internal class LLFirLazyResolveContractChecker {
private val currentTransformerPhase = ThreadLocal.withInitial<FirResolvePhase?> { null }
@@ -19,6 +19,15 @@ import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.utils.exceptions.rethrowExceptionWithDetails
/**
* This is the entry point for lazy resolution.
*
* The class is responsible to [collect][LLFirResolveDesignationCollector] required [LLFirResolveTarget]
* and resolve it for the requested phase.
*
* @see org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
* @see LLFirLazyResolverRunner
*/
internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirModuleResolveComponents) {
/**
* Lazily resolves the [target] to a given [toPhase].
@@ -19,6 +19,14 @@ import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.isCopyCreatedInScope
/**
* Collects [LLFirResolveTarget] for requested [FirElementWithResolveState].
*
* Effectively, this class is responsible for which elements can be lazily resolved and which cannot.
*
* @see LLFirResolveTarget
* @see shouldBeResolved
*/
internal object LLFirResolveDesignationCollector {
fun getDesignationToResolve(target: FirElementWithResolveState): LLFirResolveTarget? {
return getDesignationToResolve(target, FirDesignation::asResolveTarget)
@@ -54,6 +62,9 @@ internal object LLFirResolveDesignationCollector {
}
}
/**
* @see isLazyResolvable
*/
private fun FirElementWithResolveState.shouldBeResolved() = when (this) {
is FirDeclaration -> shouldBeResolved()
is FirFileAnnotationsContainer -> annotations.isNotEmpty()
@@ -67,6 +67,21 @@ internal object LLFirAnnotationArgumentsLazyResolver : LLFirLazyResolver(FirReso
}
}
/**
* This resolver is responsible for [ANNOTATION_ARGUMENTS][FirResolvePhase.ANNOTATION_ARGUMENTS] phase.
*
* This resolver:
* - Transforms unresolved annotation arguments into resolved ones.
* It includes both regular and type annotations.
*
* Before the transformation, the resolver [recreates][AnnotationArgumentsStateKeepers] all unresolved argument lists
* to prevent corrupted states due to [PCE][com.intellij.openapi.progress.ProcessCanceledException].
*
* @see postponedSymbolsForAnnotationResolution
* @see AnnotationArgumentsStateKeepers
* @see FirAnnotationArgumentsTransformer
* @see FirResolvePhase.ANNOTATION_ARGUMENTS
*/
private class LLFirAnnotationArgumentsTargetResolver(resolveTarget: LLFirResolveTarget) : LLFirAbstractBodyTargetResolver(
resolveTarget,
FirResolvePhase.ANNOTATION_ARGUMENTS,
@@ -65,6 +65,28 @@ internal object LLFirBodyLazyResolver : LLFirLazyResolver(FirResolvePhase.BODY_R
}
}
/**
* This resolver is responsible for [BODY_RESOLVE][FirResolvePhase.BODY_RESOLVE] phase.
*
* This resolver:
* - Transforms bodies of declarations.
* - Builds [control flow graph][org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph].
*
* Before the transformation, the resolver [recreates][BodyStateKeepers] all bodies
* to prevent corrupted states due to [PCE][com.intellij.openapi.progress.ProcessCanceledException].
*
* Special rules:
* - [FirFile] All members which [isUsedInControlFlowGraphBuilderForFile] have
* to be resolved before the file to build correct [CFG][org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph].
* - [FirScript] All members which [isUsedInControlFlowGraphBuilderForScript] have
* to be resolved before the script to build correct [CFG][org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph].
* - [FirRegularClass] All members which [isUsedInControlFlowGraphBuilderForClass] have
* to be resolved before the class to build correct [CFG][org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph].
*
* @see BodyStateKeepers
* @see FirBodyResolveTransformer
* @see FirResolvePhase.BODY_RESOLVE
*/
private class LLFirBodyTargetResolver(target: LLFirResolveTarget) : LLFirAbstractBodyTargetResolver(
target,
FirResolvePhase.BODY_RESOLVE,
@@ -43,6 +43,16 @@ internal object LLFirCompilerAnnotationsLazyResolver : LLFirLazyResolver(FirReso
}
}
/**
* This resolver is responsible for [COMPILER_REQUIRED_ANNOTATIONS][FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS] phase.
*
* This resolver:
* - Transforms compiler required annotations of declarations.
* - Calculates [DeprecationsProvider].
*
* @see FirCompilerRequiredAnnotationsResolveTransformer
* @see FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS
*/
private class LLFirCompilerRequiredAnnotationsTargetResolver(
target: LLFirResolveTarget,
computationSession: LLFirCompilerRequiredAnnotationsComputationSession? = null,
@@ -29,6 +29,20 @@ internal object LLFirContractsLazyResolver : LLFirLazyResolver(FirResolvePhase.C
}
}
/**
* This resolver is responsible for [CONTRACTS][FirResolvePhase.CONTRACTS] phase.
*
* This resolver:
* - Transforms a [contract][org.jetbrains.kotlin.fir.contracts.FirContractDescription]
* definition in [contract owners][FirContractDescriptionOwner].
*
* Before the transformation, the resolver [recreates][ContractStateKeepers] bodies
* to prevent corrupted states due to [PCE][com.intellij.openapi.progress.ProcessCanceledException].
*
* @see ContractStateKeepers
* @see FirContractResolveTransformer
* @see FirResolvePhase.CONTRACTS
*/
private class LLFirContractsTargetResolver(target: LLFirResolveTarget) : LLFirAbstractBodyTargetResolver(
target,
FirResolvePhase.CONTRACTS,
@@ -29,6 +29,19 @@ internal object LLFirExpectActualMatcherLazyResolver : LLFirLazyResolver(FirReso
}
}
/**
* This resolver is responsible for [EXPECT_ACTUAL_MATCHING][FirResolvePhase.EXPECT_ACTUAL_MATCHING] phase.
*
* This resolver:
* - Searches and set [expectForActual][org.jetbrains.kotlin.fir.declarations.expectForActual]
* property for declarations.
*
* Special rules:
* - First resolves outer classes to this phase in multiplatform projects.
*
* @see FirExpectActualMatcherTransformer
* @see FirResolvePhase.EXPECT_ACTUAL_MATCHING
*/
private class LLFirExpectActualMatchingTargetResolver(target: LLFirResolveTarget) : LLFirTargetResolver(
target,
FirResolvePhase.EXPECT_ACTUAL_MATCHING
@@ -17,6 +17,15 @@ internal object LLFirGeneratedCompanionObjectLazyResolver : LLFirLazyResolver(Fi
override fun phaseSpecificCheckIsResolved(target: FirElementWithResolveState) {}
}
/**
* This resolver is responsible for [COMPANION_GENERATION][FirResolvePhase.COMPANION_GENERATION] phase.
*
* This resolver:
* - Generates companion objects which were provided by compiler plugins.
*
* @see FirCompanionGenerationTransformer
* @see FirResolvePhase.COMPANION_GENERATION
*/
private class LLFirCompanionGenerationTargetResolver(target: LLFirResolveTarget) : LLFirTargetResolver(
target,
FirResolvePhase.COMPANION_GENERATION,
@@ -117,6 +117,20 @@ internal class LLImplicitBodyResolveComputationSession : ImplicitBodyResolveComp
fun popCycledSymbolIfExists(): FirCallableSymbol<*>? = cycledSymbol?.also { cycledSymbol = null }
}
/**
* This resolver is responsible for [IMPLICIT_TYPES_BODY_RESOLVE][FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE] phase.
*
* This resolver:
* - Transforms [FirImplicitTypeRef] into [FirResolvedTypeRef][org.jetbrains.kotlin.fir.types.FirResolvedTypeRef].
*
* Before the transformation, the resolver [recreates][BodyStateKeepers] all bodies
* to prevent corrupted states due to [PCE][com.intellij.openapi.progress.ProcessCanceledException].
*
* @see postponedSymbolsForAnnotationResolution
* @see BodyStateKeepers
* @see FirImplicitAwareBodyResolveTransformer
* @see FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE
*/
internal class LLFirImplicitBodyTargetResolver(
target: LLFirResolveTarget,
llImplicitBodyResolveComputationSessionParameter: LLImplicitBodyResolveComputationSession? = null,
@@ -8,19 +8,22 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import java.util.*
/**
* Maps [FirResolvePhase] to the associated [LLFirTargetResolver].
*/
internal object LLFirLazyPhaseResolverByPhase {
private val byPhase = EnumMap<FirResolvePhase, LLFirLazyResolver>(FirResolvePhase::class.java).apply {
this[FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS] = LLFirCompilerAnnotationsLazyResolver
this[FirResolvePhase.COMPANION_GENERATION] = LLFirGeneratedCompanionObjectLazyResolver
this[FirResolvePhase.SUPER_TYPES] = LLFirSupertypeLazyResolver
this[FirResolvePhase.SEALED_CLASS_INHERITORS] = LLFirSealedClassInheritorsLazyResolver
this[FirResolvePhase.TYPES] = LLFirTypeLazyResolver
this[FirResolvePhase.STATUS] = LLFirStatusLazyResolver
this[FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS] = LLFirCompilerAnnotationsLazyResolver
this[FirResolvePhase.EXPECT_ACTUAL_MATCHING] = LLFirExpectActualMatcherLazyResolver
this[FirResolvePhase.CONTRACTS] = LLFirContractsLazyResolver
this[FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE] = LLFirImplicitTypesLazyResolver
this[FirResolvePhase.ANNOTATION_ARGUMENTS] = LLFirAnnotationArgumentsLazyResolver
this[FirResolvePhase.BODY_RESOLVE] = LLFirBodyLazyResolver
this[FirResolvePhase.EXPECT_ACTUAL_MATCHING] = LLFirExpectActualMatcherLazyResolver
this[FirResolvePhase.SEALED_CLASS_INHERITORS] = LLFirSealedClassInheritorsLazyResolver
}
fun getByPhase(phase: FirResolvePhase): LLFirLazyResolver = byPhase.getValue(phase)
@@ -10,11 +10,20 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveT
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.session
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
/**
* Runs required [LLFirLazyResolver] on [LLFirResolveTarget] based on [FirResolvePhase].
*
* @see runLazyResolverByPhase
* @see LLFirLazyResolver
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
*/
internal object LLFirLazyResolverRunner {
fun runLazyResolverByPhase(
phase: FirResolvePhase,
target: LLFirResolveTarget,
) {
/**
* Runs [resolver][LLFirLazyResolver] associated with [phase] for [target] and checks if it finished correctly.
*
* @see LLFirLazyPhaseResolverByPhase
*/
fun runLazyResolverByPhase(phase: FirResolvePhase, target: LLFirResolveTarget) {
val lazyResolver = LLFirLazyPhaseResolverByPhase.getByPhase(phase)
val lockProvider = LLFirGlobalResolveComponents.getInstance(target.session).lockProvider
lockProvider.withGlobalLock {
@@ -18,6 +18,17 @@ internal object LLFirSealedClassInheritorsLazyResolver : LLFirLazyResolver(FirRe
}
/**
* This resolver is responsible for [SEALED_CLASS_INHERITORS][FirResolvePhase.SEALED_CLASS_INHERITORS] phase.
*
* LL FIR use [LLSealedInheritorsProviderByAnalysisApiProvider][org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderByAnalysisApiProvider]
* instead of the compiler [SealedClassInheritorsProviderImpl][org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProviderImpl],
* so it does nothing during this phase as sealed class hierarchy will be provided later on demand.
*
* @see org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.LLSealedInheritorsProviderFactory
* @see org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider
* @see FirResolvePhase.SEALED_CLASS_INHERITORS
*/
private class LLFirSealedClassInheritorsDesignatedResolver(target: LLFirResolveTarget) : LLFirTargetResolver(
target,
FirResolvePhase.SEALED_CLASS_INHERITORS,
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.name.Name
internal object LLFirStatusLazyResolver : LLFirLazyResolver(FirResolvePhase.STATUS) {
override fun createTargetResolver(target: LLFirResolveTarget): LLFirTargetResolver = LLFirStatusTargetResolver(
@@ -49,18 +48,6 @@ private sealed class StatusResolveMode(val resolveSupertypes: Boolean) {
object AllCallables : StatusResolveMode(resolveSupertypes = true) {
override fun shouldBeResolved(callableDeclaration: FirCallableDeclaration): Boolean = true
}
class FunctionWithSpecificName(val name: Name) : StatusResolveMode(resolveSupertypes = true) {
override fun shouldBeResolved(callableDeclaration: FirCallableDeclaration): Boolean {
return callableDeclaration is FirSimpleFunction && callableDeclaration.name == name
}
}
class PropertyWithSpecificName(val name: Name) : StatusResolveMode(resolveSupertypes = true) {
override fun shouldBeResolved(callableDeclaration: FirCallableDeclaration): Boolean {
return callableDeclaration is FirProperty && callableDeclaration.name == name
}
}
}
private fun LLFirResolveTarget.resolveMode(): StatusResolveMode = when (this) {
@@ -91,6 +78,21 @@ private class LLStatusComputationSession(val useSiteSession: FirSession) : Statu
val canHaveActualization: Boolean get() = shouldCheckForActualization
}
/**
* This resolver is responsible for [STATUS][FirResolvePhase.STATUS] phase.
*
* This resolver:
* - Transforms modality, visibility, and modifiers for [member declarations][FirMemberDeclaration].
*
* Special rules:
* - First resolves outer classes to this phase.
* - First resolves all members of super types for non-[FirClassLikeDeclaration] declarations.
* - [Searches][org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirStatusTargetResolver.Transformer.superTypeToSymbols]
* super types not only in the declaration site session, but also in the call site session to resolve `expect` declaration first.
*
* @see FirStatusResolveTransformer
* @see FirResolvePhase.STATUS
*/
private class LLFirStatusTargetResolver(
target: LLFirResolveTarget,
private val statusComputationSession: LLStatusComputationSession = LLStatusComputationSession(target.session),
@@ -48,6 +48,23 @@ internal object LLFirSupertypeLazyResolver : LLFirLazyResolver(FirResolvePhase.S
}
}
/**
* This resolver is responsible for [SUPER_TYPES][FirResolvePhase.SUPER_TYPES] phase.
*
* This resolver:
* - Transforms all supertypes of classes.
* - Performs type aliases expansion.
* - Breaks loops in the type hierarchy if needed.
*
* Special rules:
* - First resolves outer classes to this phase.
* - Resolves all super types recursively.
* - [Searches][org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirSuperTypeTargetResolver.crawlSupertype]
* super types not only in the declaration site session, but also in the call site session to resolve `expect` declaration first.
*
* @see FirSupertypeResolverVisitor
* @see FirResolvePhase.SUPER_TYPES
*/
private class LLFirSuperTypeTargetResolver(
target: LLFirResolveTarget,
private val supertypeComputationSession: LLFirSupertypeComputationSession = LLFirSupertypeComputationSession(target.session),
@@ -38,6 +38,40 @@ import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
/**
* This class represents the resolver for each [FirResolvePhase].
*
* Usually such the resolver extends the corresponding compiler phase transformer or delegates to it.
*
* The main difference with original compiler transformers is that we can transform declarations
* only under the lock of the declaration (see [LLFirLockProvider] for locks implementation).
* E.g., to avoid [contract violations][org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirLazyResolveContractChecker]
* we cannot transform class member declaration under the class lock we have to take the corresponding declaration lock
* to avoid concurrent issues.
*
* So, at least we have a different implementation for transformations of such declarations as [FirFile], [FirScript] and [FirRegularClass].
*
* Due to lazy resolution, we have to maintain the resolution order explicitly in some cases as we are not guaranteed by default that all
* dependencies or outer declarations are resolved before the target one.
* We have [resolveDependencies] method which describes common dependencies between declarations.
* Also, each [LLFirResolveTarget] can define phase-specific rules.
*
* Implementations:
* - [COMPILER_REQUIRED_ANNOTATIONS][FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS] [LLFirCompilerRequiredAnnotationsTargetResolver]
* - [COMPANION_GENERATION][FirResolvePhase.COMPANION_GENERATION] [LLFirCompanionGenerationTargetResolver]
* - [SUPER_TYPES][FirResolvePhase.SUPER_TYPES] [LLFirSuperTypeTargetResolver]
* - [SEALED_CLASS_INHERITORS][FirResolvePhase.SEALED_CLASS_INHERITORS] [LLFirSealedClassInheritorsLazyResolver]
* - [TYPES][FirResolvePhase.TYPES] [LLFirTypeTargetResolver]
* - [STATUS][FirResolvePhase.STATUS] [LLFirStatusTargetResolver]
* - [EXPECT_ACTUAL_MATCHING][FirResolvePhase.EXPECT_ACTUAL_MATCHING] [LLFirExpectActualMatchingTargetResolver]
* - [CONTRACTS][FirResolvePhase.CONTRACTS] [LLFirContractsTargetResolver]
* - [IMPLICIT_TYPES_BODY_RESOLVE][FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE] [LLFirImplicitBodyTargetResolver]
* - [ANNOTATION_ARGUMENTS][FirResolvePhase.ANNOTATION_ARGUMENTS] [LLFirAnnotationArgumentsTargetResolver]
* - [BODY_RESOLVE][FirResolvePhase.BODY_RESOLVE] [LLFirBodyTargetResolver]
*
* @see LLFirLockProvider
* @see FirResolvePhase
*/
internal abstract class LLFirTargetResolver(
protected val resolveTarget: LLFirResolveTarget,
val resolverPhase: FirResolvePhase,
@@ -83,6 +117,12 @@ internal abstract class LLFirTargetResolver(
}
/**
* Dependency target resolution can be skipped to optimize the resolution if this phase does not require any dependencies.
*
* For instance, [LLFirBodyTargetResolver] skips it as no one should depend on body resolution of another declaration.
*
* @return **true** if [resolveDependencies] step should be skipped
*
* @see resolveDependencies
*/
open val skipDependencyTargetResolutionStep: Boolean get() = false
@@ -91,6 +131,7 @@ internal abstract class LLFirTargetResolver(
* Requests the resolution for dependencies to avoid race in the case of FIR instance sharing.
* Will be executed before resolution without a lock.
*
* @see resolveDataClassMemberDependencies
* @see skipDependencyTargetResolutionStep
*/
private fun resolveDependencies(target: FirElementWithResolveState) {
@@ -190,10 +231,32 @@ internal abstract class LLFirTargetResolver(
protected open fun checkResolveConsistency() {}
/**
* This method executes **not under the lock** of [target].
* Any unsafe reads from [target] declaration have to be done under [withReadLock].
* [performCustomResolveUnderLock] have to be used for modifications.
*
* This method can be useful to resolve some dependencies (like [resolveDependencies] in general),
* but with some phase-specific rules.
*
* For instance, to pre-resolve [FirRegularClass] members before the class itself as it is required
* to build the [CFG][org.jetbrains.kotlin.fir.resolve.dfa.cfg.ControlFlowGraph].
*
* @return **true** if [performCustomResolveUnderLock] has been called
*
* @see withReadLock
* @see performCustomResolveUnderLock
*/
protected open fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean = false
/**
* This method executes **under the lock** of [target].
*/
protected abstract fun doLazyResolveUnderLock(target: FirElementWithResolveState)
/**
* Executes the resolution.
*/
fun resolveDesignation() {
checkResolveConsistency()
resolveTarget.visit(this)
@@ -203,6 +266,14 @@ internal abstract class LLFirTargetResolver(
performResolve(element)
}
/**
* Performs the resolution of [target].
* The [target] element have to be at least in [resolverPhase].[previous][FirResolvePhase.previous] phase.
*
* @see resolveDependencies
* @see doResolveWithoutLock
* @see doLazyResolveUnderLock
*/
protected fun performResolve(target: FirElementWithResolveState) {
resolveDependencies(target)
@@ -56,6 +56,18 @@ internal object LLFirTypeLazyResolver : LLFirLazyResolver(FirResolvePhase.TYPES)
}
}
/**
* This resolver is responsible for [TYPES][FirResolvePhase.TYPES] phase.
*
* This resolver:
* - Transform explicitly written types in declaration headers.
*
* Special rules:
* - First resolves outer classes to this phase.
*
* @see FirTypeResolveTransformer
* @see FirResolvePhase.TYPES
*/
private class LLFirTypeTargetResolver(target: LLFirResolveTarget) : LLFirTargetResolver(target, FirResolvePhase.TYPES) {
private val transformer = object : FirTypeResolveTransformer(resolveTargetSession, resolveTargetScopeSession) {
override fun transformTypeRef(typeRef: FirTypeRef, data: Any?): FirResolvedTypeRef {