[LL FIR] rework transformers, so transformers resolve only a specific set of declarations

The change is needed for the parallel resolution (^KT-55750), so we can resolve the declaration
under a lock that is specific to this declaration.
Previously, if LL FIR was resolving some FirClass, LL FIR  resolved all its children too, and it had no control over what parts of the FIR tree were modified.
The same applied to the designation path, sometimes the classes on the designation path
might be unexpectedly (and without lock) modified.

This commit introduces LLFirResolveTarget, which specifies which exact declarations should be resolved during the lazy resolution of the declaration.
All elements outside the declarations specified for resolve in LLFirResolveTarget, should not be modified.

The logic of lazy transformers is the following:
- Go to target declaration collecting all scopes from the file and containing classes
- Resolve only declarations that are specified by the LLFirResolveTarget, performing the resolve under a separate lock for each declaration

^KT-56543
^KT-57619 Fixed
This commit is contained in:
Dmitrii Gridin
2023-03-30 17:19:30 +02:00
committed by Space Team
parent 18a8cfb090
commit 72def186a3
545 changed files with 4297 additions and 2378 deletions
@@ -70,6 +70,12 @@ public class Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exte
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile.kt");
}
@Test
@TestMetadata("AnnotationOnFile2.kt")
public void testAnnotationOnFile2() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile2.kt");
}
@Test
@TestMetadata("AnnotationOnFileWithImport.kt")
public void testAnnotationOnFileWithImport() throws Exception {
@@ -388,6 +394,30 @@ public class Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exte
runTest("analysis/analysis-api/testData/referenceResolve/NotEqualsOperator.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFile.kt")
public void testPackageFromAnnotationOnFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFile.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFileWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFileWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFileWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunction.kt")
public void testPackageFromAnnotationOnFunction() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunction.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunctionWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFunctionWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunctionWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageReference.kt")
public void testPackageReference() throws Exception {
@@ -769,12 +799,24 @@ public class Fe10IdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exte
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedClass.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedFile.kt")
public void testDanglingAnnotationsResolvedFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedLocal.kt")
public void testDanglingAnnotationsResolvedLocal() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedLocal.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedPackageFile.kt")
public void testDanglingAnnotationsResolvedPackageFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedPackageFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedTopLevel.kt")
public void testDanglingAnnotationsResolvedTopLevel() throws Exception {
@@ -70,6 +70,12 @@ public class FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated ex
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile.kt");
}
@Test
@TestMetadata("AnnotationOnFile2.kt")
public void testAnnotationOnFile2() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile2.kt");
}
@Test
@TestMetadata("AnnotationOnFileWithImport.kt")
public void testAnnotationOnFileWithImport() throws Exception {
@@ -388,6 +394,30 @@ public class FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated ex
runTest("analysis/analysis-api/testData/referenceResolve/NotEqualsOperator.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFile.kt")
public void testPackageFromAnnotationOnFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFile.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFileWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFileWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFileWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunction.kt")
public void testPackageFromAnnotationOnFunction() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunction.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunctionWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFunctionWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunctionWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageReference.kt")
public void testPackageReference() throws Exception {
@@ -769,12 +799,24 @@ public class FirIdeDependentAnalysisSourceModuleReferenceResolveTestGenerated ex
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedClass.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedFile.kt")
public void testDanglingAnnotationsResolvedFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedLocal.kt")
public void testDanglingAnnotationsResolvedLocal() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedLocal.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedPackageFile.kt")
public void testDanglingAnnotationsResolvedPackageFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedPackageFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedTopLevel.kt")
public void testDanglingAnnotationsResolvedTopLevel() throws Exception {
@@ -70,6 +70,12 @@ public class FirIdeNormalAnalysisLibrarySourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile.kt");
}
@Test
@TestMetadata("AnnotationOnFile2.kt")
public void testAnnotationOnFile2() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile2.kt");
}
@Test
@TestMetadata("AnnotationOnFileWithImport.kt")
public void testAnnotationOnFileWithImport() throws Exception {
@@ -388,6 +394,30 @@ public class FirIdeNormalAnalysisLibrarySourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/NotEqualsOperator.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFile.kt")
public void testPackageFromAnnotationOnFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFile.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFileWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFileWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFileWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunction.kt")
public void testPackageFromAnnotationOnFunction() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunction.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunctionWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFunctionWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunctionWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageReference.kt")
public void testPackageReference() throws Exception {
@@ -741,12 +771,24 @@ public class FirIdeNormalAnalysisLibrarySourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedClass.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedFile.kt")
public void testDanglingAnnotationsResolvedFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedLocal.kt")
public void testDanglingAnnotationsResolvedLocal() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedLocal.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedPackageFile.kt")
public void testDanglingAnnotationsResolvedPackageFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedPackageFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedTopLevel.kt")
public void testDanglingAnnotationsResolvedTopLevel() throws Exception {
@@ -70,6 +70,12 @@ public class FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exten
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile.kt");
}
@Test
@TestMetadata("AnnotationOnFile2.kt")
public void testAnnotationOnFile2() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile2.kt");
}
@Test
@TestMetadata("AnnotationOnFileWithImport.kt")
public void testAnnotationOnFileWithImport() throws Exception {
@@ -388,6 +394,30 @@ public class FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exten
runTest("analysis/analysis-api/testData/referenceResolve/NotEqualsOperator.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFile.kt")
public void testPackageFromAnnotationOnFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFile.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFileWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFileWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFileWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunction.kt")
public void testPackageFromAnnotationOnFunction() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunction.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunctionWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFunctionWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunctionWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageReference.kt")
public void testPackageReference() throws Exception {
@@ -769,12 +799,24 @@ public class FirIdeNormalAnalysisSourceModuleReferenceResolveTestGenerated exten
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedClass.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedFile.kt")
public void testDanglingAnnotationsResolvedFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedLocal.kt")
public void testDanglingAnnotationsResolvedLocal() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedLocal.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedPackageFile.kt")
public void testDanglingAnnotationsResolvedPackageFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedPackageFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedTopLevel.kt")
public void testDanglingAnnotationsResolvedTopLevel() throws Exception {
@@ -70,6 +70,12 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile.kt");
}
@Test
@TestMetadata("AnnotationOnFile2.kt")
public void testAnnotationOnFile2() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/AnnotationOnFile2.kt");
}
@Test
@TestMetadata("AnnotationOnFileWithImport.kt")
public void testAnnotationOnFileWithImport() throws Exception {
@@ -388,6 +394,30 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/NotEqualsOperator.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFile.kt")
public void testPackageFromAnnotationOnFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFile.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFileWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFileWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFileWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunction.kt")
public void testPackageFromAnnotationOnFunction() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunction.kt");
}
@Test
@TestMetadata("PackageFromAnnotationOnFunctionWithUnresolvedReference.kt")
public void testPackageFromAnnotationOnFunctionWithUnresolvedReference() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/PackageFromAnnotationOnFunctionWithUnresolvedReference.kt");
}
@Test
@TestMetadata("PackageReference.kt")
public void testPackageReference() throws Exception {
@@ -769,12 +799,24 @@ public class FirStandaloneNormalAnalysisSourceModuleReferenceResolveTestGenerate
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedClass.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedFile.kt")
public void testDanglingAnnotationsResolvedFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedLocal.kt")
public void testDanglingAnnotationsResolvedLocal() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedLocal.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedPackageFile.kt")
public void testDanglingAnnotationsResolvedPackageFile() throws Exception {
runTest("analysis/analysis-api/testData/referenceResolve/danglingAnnotations/DanglingAnnotationsResolvedPackageFile.kt");
}
@Test
@TestMetadata("DanglingAnnotationsResolvedTopLevel.kt")
public void testDanglingAnnotationsResolvedTopLevel() throws Exception {
@@ -0,0 +1,4 @@
@file:kotlin.<caret>Suppress("message")
package foo
@@ -0,0 +1,2 @@
Resolved to:
0: (in kotlin.Suppress) constructor(vararg names: kotlin.String)
@@ -0,0 +1,4 @@
@file:kotlin.jv<caret>m.JvmName("Name")
package foo
@@ -0,0 +1,2 @@
Resolved to:
0: package kotlin.jvm
@@ -0,0 +1,5 @@
@file:kotlin.jv<caret>m.JvmName23("Name")
package foo
// COMPILATION_ERRORS
@@ -0,0 +1,2 @@
Resolved to:
0: package kotlin.jvm
@@ -0,0 +1,6 @@
package foo
@kotlin.jv<caret>m.JvmName("Name")
fun boo() {
}
@@ -0,0 +1,2 @@
Resolved to:
0: package kotlin.jvm
@@ -0,0 +1,8 @@
package foo
@kotlin.jv<caret>m.JvmName2("Name")
fun boo() {
}
// COMPILATION_ERRORS
@@ -0,0 +1,2 @@
Resolved to:
0: package kotlin.jvm
@@ -0,0 +1,2 @@
// COMPILATION_ERRORS
@kotlin.jvm.Jvm<caret>Name("")
@@ -0,0 +1,2 @@
Resolved to:
0: (in kotlin.jvm.JvmName) constructor(name: kotlin.String)
@@ -0,0 +1,2 @@
// COMPILATION_ERRORS
@kotlin.j<caret>vm.JvmName("")
@@ -0,0 +1,2 @@
Resolved to:
0: package kotlin.jvm
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirLazyResolveContractChecker
internal class LLFirGlobalResolveComponents(val project: Project) {
companion object {
@@ -15,5 +16,6 @@ internal class LLFirGlobalResolveComponents(val project: Project) {
}
}
val lockProvider: LLFirLockProvider = LLFirLockProvider()
val checker: LLFirLazyResolveContractChecker = LLFirLazyResolveContractChecker()
val lockProvider: LLFirLockProvider = LLFirLockProvider(checker)
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
@@ -34,6 +34,11 @@ internal class LLFirLazyDeclarationResolver : FirLazyDeclarationResolver() {
val fir = symbol.fir as? FirRegularClass ?: return
val session = fir.moduleData.session
if (session !is LLFirResolvableModuleSession) return
// TODO: should be implemented in the context of KT-56543
val moduleComponents = session.moduleComponents
moduleComponents.firModuleLazyDeclarationResolver.lazyResolveWithCallableMembers(
target = fir,
scopeSession = moduleComponents.scopeSessionProvider.getScopeSession(),
toPhase = toPhase,
)
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.nullableJavaSymbolProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingClass
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment
@@ -45,9 +46,6 @@ open class FirDesignation(
val path: List<FirRegularClass>,
val target: FirElementWithResolveState,
) {
val firstNonFileDeclaration: FirElementWithResolveState
get() = path.firstOrNull() ?: target
fun toSequence(includeTarget: Boolean): Sequence<FirElementWithResolveState> = sequence {
yieldAll(path)
if (includeTarget) yield(target)
@@ -96,6 +94,12 @@ private fun collectDesignationPath(target: FirElementWithResolveState): List<Fir
return collectDesignationPathWithContainingClass(target, containingClassId)
}
is FirAnonymousInitializer -> {
val containingClassId = target.containingClass().symbol.classId
if (containingClassId.isLocal) return null
return collectDesignationPathWithContainingClass(target, containingClassId)
}
is FirErrorProperty -> {
return if (target.diagnostic == ConeDestructuringDeclarationsOnTopLevel) emptyList() else null
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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,7 +8,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analysis.low.level.api.fir.DeclarationCopyBuilder.withBodyFrom
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionDepended
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FileTowerProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
@@ -146,7 +145,11 @@ object LowLevelFirApiFacadeForResolveOnAir {
val scopeSession = firResolveSession.getScopeSessionFor(session)
firFile.lazyResolveToPhase(FirResolvePhase.IMPORTS)
val importingScopes = createImportingScopes(firFile, firFile.moduleData.session, scopeSession, useCaching = false)
return firFile.createTowerDataContext(scopeSession)
}
private fun FirFile.createTowerDataContext(scopeSession: ScopeSession): FirTowerDataContext {
val importingScopes = createImportingScopes(this, moduleData.session, scopeSession, useCaching = false)
val fileScopeElements = importingScopes.map { it.asTowerDataElement(isLocal = false) }
return FirTowerDataContext().addNonLocalTowerDataElements(fileScopeElements)
}
@@ -195,6 +198,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
replacement: RawFirReplacement,
firFile: FirFile,
collector: FirTowerDataContextCollector? = null,
firResolveSession: LLFirResolvableResolveSession,
): FirAnnotation {
val annotationCall = buildFileFirAnnotation(
session = firFile.moduleData.session,
@@ -211,14 +215,16 @@ object LowLevelFirApiFacadeForResolveOnAir {
?: buildErrorWithAttachment("FirFile session expected to be a resolvable session but was ${firFile.llFirSession::class.java}") {
withEntry("firSession", firFile.llFirSession) { it.toString() }
}
val declarationResolver = llFirResolvableSession.moduleComponents.firModuleLazyDeclarationResolver
val declarationResolver = llFirResolvableSession.moduleComponents.firModuleLazyDeclarationResolver
declarationResolver.runLazyDesignatedOnAirResolveToBodyWithoutLock(
FirDesignationWithFile(path = emptyList(), target = fileAnnotationsContainer, firFile),
onAirCreatedDeclaration = true,
collector
)
collector?.addFileContext(firFile, firFile.createTowerDataContext(firResolveSession.getScopeSessionFor(llFirResolvableSession)))
return annotationCall
}
@@ -240,6 +246,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
replacement = replacement,
firFile = originalFirFile,
collector = collector,
firResolveSession = firResolveSession,
)
} else {
error("Cannot find enclosing declaration for ${replacement.from.getElementTextInContext()}")
@@ -247,9 +254,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
}
val originalDeclaration = nonLocalDeclaration.getOrBuildFirOfType<FirDeclaration>(firResolveSession)
val originalDesignation = originalDeclaration.collectDesignation()
val newDeclarationWithReplacement = RawFirNonLocalDeclarationBuilder.buildWithReplacement(
session = originalDeclaration.moduleData.session,
scopeProvider = originalDeclaration.moduleData.session.kotlinScopeProvider,
@@ -259,41 +264,33 @@ object LowLevelFirApiFacadeForResolveOnAir {
)
val isInBodyReplacement = isInBodyReplacement(nonLocalDeclaration, replacement)
val globalResolveComponents = LLFirGlobalResolveComponents.getInstance(firResolveSession.project)
return globalResolveComponents.lockProvider.withLock(originalFirFile) {
val copiedFirDeclaration = if (isInBodyReplacement) {
when (originalDeclaration) {
is FirSimpleFunction ->
originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirSimpleFunction)
is FirProperty ->
originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirProperty)
is FirRegularClass ->
originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirRegularClass)
is FirScript ->
originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirScript)
is FirTypeAlias -> newDeclarationWithReplacement
else -> error("Not supported type ${originalDeclaration::class.simpleName}")
}
} else newDeclarationWithReplacement
val onAirDesignation = FirDesignationWithFile(
path = originalDesignation.path,
target = copiedFirDeclaration,
firFile = originalFirFile
)
val resolvableSession = onAirDesignation.target.llFirResolvableSession
?: error("Expected resolvable session")
resolvableSession.moduleComponents.firModuleLazyDeclarationResolver
.runLazyDesignatedOnAirResolveToBodyWithoutLock(
designation = onAirDesignation,
onAirCreatedDeclaration = onAirCreatedDeclaration,
towerDataContextCollector = collector,
)
copiedFirDeclaration
val copiedFirDeclaration = if (isInBodyReplacement) {
when (originalDeclaration) {
is FirSimpleFunction -> originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirSimpleFunction)
is FirProperty -> originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirProperty)
is FirRegularClass -> originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirRegularClass)
is FirScript -> originalDeclaration.withBodyFrom(newDeclarationWithReplacement as FirScript)
is FirTypeAlias -> newDeclarationWithReplacement
else -> error("Not supported type ${originalDeclaration::class.simpleName}")
}
} else {
newDeclarationWithReplacement
}
val onAirDesignation = FirDesignationWithFile(
path = originalDesignation.path,
target = copiedFirDeclaration,
firFile = originalFirFile
)
val resolvableSession = onAirDesignation.target.llFirResolvableSession ?: error("Expected resolvable session")
resolvableSession.moduleComponents.firModuleLazyDeclarationResolver.runLazyDesignatedOnAirResolveToBodyWithoutLock(
designation = onAirDesignation,
onAirCreatedDeclaration = onAirCreatedDeclaration,
towerDataContextCollector = collector,
)
return copiedFirDeclaration
}
private fun isInBodyReplacement(ktDeclaration: KtDeclaration, replacement: RawFirReplacement): Boolean {
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
/**
* [LLFirResolveTarget] representing a class with all callable members (functions and properties).
*/
class LLFirClassWithAllCallablesResolveTarget(
override val firFile: FirFile,
override val path: List<FirRegularClass>,
val target: FirRegularClass,
) : LLFirResolveTarget() {
override fun forEachTarget(action: (FirElementWithResolveState) -> Unit) {
action(target)
forEachCallable(action)
}
inline fun forEachCallable(action: (FirCallableDeclaration) -> Unit) {
for (member in target.declarations) {
if (member is FirCallableDeclaration) {
action(member)
}
}
}
override fun toStringForTarget(): String = target.name.asString()
}
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
/**
* [LLFirResolveTarget] representing a class with all class members to be resolved (this includes callables, init blocks, and classifiers)
*/
class LLFirClassWithAllMembersResolveTarget(
override val firFile: FirFile,
override val path: List<FirRegularClass>,
val target: FirRegularClass,
) : LLFirResolveTarget() {
override fun forEachTarget(action: (FirElementWithResolveState) -> Unit) {
action(target)
forEachMember(action)
}
inline fun forEachMember(action: (FirDeclaration) -> Unit) {
target.declarations.forEach(action)
}
override fun toStringForTarget(): String = target.name.asString()
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
class LLFirClassWithSpecificMembersResolveTarget(
override val firFile: FirFile,
override val path: List<FirRegularClass>,
val target: FirRegularClass,
val members: List<FirDeclaration>
) : LLFirResolveTarget() {
override fun forEachTarget(action: (FirElementWithResolveState) -> Unit) {
action(target)
forEachMember(action)
}
fun forEachMember(action: (FirDeclaration) -> Unit) {
members.forEach(action)
}
override fun toStringForTarget(): String =
members.joinToString(prefix = "[", postfix = "]") { it.symbol.toString() }
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
/**
* Target to be lazily resolved by LL FIR lazy resolver.
*
* Specifies the path to the resolve targets and resolve targets themselves.
* Those targets are going to be resolved by [org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirModuleLazyDeclarationResolver]
*/
sealed class LLFirResolveTarget {
/**
* [FirFile] where the targets are located
*/
abstract val firFile: FirFile
/**
* The list of [FirRegularClass] which are the required to go from file to target declarations in the top-down order.
*
* If resolve target is [FirRegularClass] itself, it's not included into the [path]
*/
abstract val path: List<FirRegularClass>
/**
* Executions the [action] for each target that this [LLFirResolveTarget] represents.
*/
abstract fun forEachTarget(action: (FirElementWithResolveState) -> Unit)
override fun toString(): String = buildString {
append(this::class.simpleName)
append("(")
buildList {
add(firFile.name)
path.mapTo(this) { it.name.asString() }
add(toStringForTarget())
}.joinTo(this, separator = " -> ")
append(")")
}
protected abstract fun toStringForTarget(): String
}
@@ -0,0 +1,33 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.declarations.*
/**
* [LLFirResolveTarget] representing single target to resolve. The [target] can be any of [FirElementWithResolveState]
*/
class LLFirSingleResolveTarget(
override val firFile: FirFile,
override val path: List<FirRegularClass>,
val target: FirElementWithResolveState,
) : LLFirResolveTarget() {
override fun forEachTarget(action: (FirElementWithResolveState) -> Unit) {
action(target)
}
override fun toStringForTarget(): String = when (target) {
is FirConstructor -> "constructor"
is FirClassLikeDeclaration -> target.symbol.name.asString()
is FirCallableDeclaration -> target.symbol.name.asString()
is FirAnonymousInitializer -> ("<init-block>")
is FirFileAnnotationsContainer -> "<file annotations>"
else -> "???"
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
/**
* [LLFirResolveTarget] representing all declarations in file. All of them are going to be resolved.
*/
class LLFirWholeFileResolveTarget(
override val firFile: FirFile,
) : LLFirResolveTarget() {
override val path: List<FirRegularClass> get() = emptyList()
override fun forEachTarget(action: (FirElementWithResolveState) -> Unit) {
fun goInside(target: FirElementWithResolveState) {
action(target)
if (target is FirRegularClass) {
target.declarations.forEach(::goInside)
}
}
forEachTopLevelDeclaration(::goInside)
}
inline fun forEachTopLevelDeclaration(action: (FirElementWithResolveState) -> Unit) {
action(firFile.annotationsContainer)
for (member in firFile.declarations) {
action(member)
}
}
override fun toStringForTarget(): String = "*"
}
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.fir.FirElementWithResolveState
fun LLFirResolveTarget.forEachPathElementAndTarget(action: (FirElementWithResolveState) -> Unit) {
path.forEach(action)
forEachTarget(action)
}
fun FirDesignationWithFile.asResolveTarget(): LLFirSingleResolveTarget = LLFirSingleResolveTarget(firFile, path, target)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
@@ -12,9 +12,12 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.fir.Persisten
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorComponents
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.util.withSourceCodeAnalysisExceptionUnwrapping
internal abstract class FileStructureElementDiagnosticRetriever {
@@ -25,6 +28,49 @@ internal abstract class FileStructureElementDiagnosticRetriever {
): FileStructureElementDiagnosticList
}
internal class ClassDiagnosticRetriever(
private val structureElementDeclaration: FirRegularClass
) : FileStructureElementDiagnosticRetriever() {
override fun retrieve(
firFile: FirFile,
collector: FileStructureElementDiagnosticsCollector,
moduleComponents: LLFirModuleResolveComponents,
): FileStructureElementDiagnosticList {
val sessionHolder = SessionHolderImpl(moduleComponents.session, moduleComponents.scopeSessionProvider.getScopeSession())
val context = PersistenceContextCollector.collectContext(sessionHolder, firFile, structureElementDeclaration)
return withSourceCodeAnalysisExceptionUnwrapping {
collector.collectForStructureElement(structureElementDeclaration) { components ->
Visitor(structureElementDeclaration, context, components)
}
}
}
private class Visitor(
private val structureElementDeclaration: FirRegularClass,
context: CheckerContextForProvider,
components: DiagnosticCollectorComponents
) : LLFirDiagnosticVisitor(context, components) {
override fun shouldVisitDeclaration(declaration: FirDeclaration): Boolean {
return when {
declaration == structureElementDeclaration -> true
shouldDiagnosticsAlwaysBeCheckedOn(declaration) -> true
declaration is FirDefaultPropertyAccessor -> shouldVisitDeclaration(declaration.propertySymbol.fir)
declaration is FirValueParameter -> shouldVisitDeclaration(declaration.containingFunctionSymbol.fir)
else -> false
}
}
}
companion object {
fun shouldDiagnosticsAlwaysBeCheckedOn(firElement: FirElement) = when (firElement.source?.kind) {
KtFakeSourceElementKind.PropertyFromParameter -> true
KtFakeSourceElementKind.ImplicitConstructor -> true
else -> false
}
}
}
internal class SingleNonLocalDeclarationDiagnosticRetriever(
private val structureElementDeclaration: FirDeclaration
) : FileStructureElementDiagnosticRetriever() {
@@ -34,66 +80,21 @@ internal class SingleNonLocalDeclarationDiagnosticRetriever(
moduleComponents: LLFirModuleResolveComponents,
): FileStructureElementDiagnosticList {
val sessionHolder = SessionHolderImpl(moduleComponents.session, moduleComponents.scopeSessionProvider.getScopeSession())
val context = moduleComponents.globalResolveComponents.lockProvider.withLock(firFile) {
PersistenceContextCollector.collectContext(sessionHolder, firFile, structureElementDeclaration)
}
val context = PersistenceContextCollector.collectContext(sessionHolder, firFile, structureElementDeclaration)
return withSourceCodeAnalysisExceptionUnwrapping {
collector.collectForStructureElement(structureElementDeclaration) { components ->
Visitor(structureElementDeclaration, context, components)
Visitor(context, components)
}
}
}
private class Visitor(
private val structureElementDeclaration: FirDeclaration,
context: CheckerContextForProvider,
components: DiagnosticCollectorComponents
) : LLFirDiagnosticVisitor(context, components) {
private var insideAlwaysVisitableDeclarations = 0
override fun shouldVisitDeclaration(declaration: FirDeclaration): Boolean {
if (declaration.shouldVisitWithNestedDeclarations()) {
insideAlwaysVisitableDeclarations++
}
if (insideAlwaysVisitableDeclarations > 0) {
return true
}
return when {
structureElementDeclaration !is FirRegularClass -> true
structureElementDeclaration == declaration -> true
declaration.hasAnnotation(StandardClassIds.Annotations.Suppress, context.session) -> {
useRegularComponents = false
true
}
else -> false
}
}
private fun FirDeclaration.shouldVisitWithNestedDeclarations(): Boolean {
if (shouldDiagnosticsAlwaysBeCheckedOn(this)) return true
return when (this) {
is FirAnonymousInitializer -> true
is FirEnumEntry -> false
is FirValueParameter -> true
is FirConstructor -> isPrimary
else -> false
}
}
override fun onDeclarationExit(declaration: FirDeclaration) {
if (declaration.shouldVisitWithNestedDeclarations()) {
insideAlwaysVisitableDeclarations--
}
}
}
companion object {
fun shouldDiagnosticsAlwaysBeCheckedOn(firElement: FirElement) = when (firElement.source?.kind) {
KtFakeSourceElementKind.PropertyFromParameter -> true
KtFakeSourceElementKind.ImplicitConstructor -> true
else -> false
return true
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvi
import org.jetbrains.kotlin.fir.analysis.collectors.CheckerRunningDiagnosticCollectorVisitor
import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorComponents
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
internal open class LLFirDiagnosticVisitor(
context: CheckerContextForProvider,
@@ -37,5 +38,21 @@ internal open class LLFirDiagnosticVisitor(
}
checkCanceled()
element.accept(components.reportCommitter, context)
if (element is FirRegularClass) {
suppressReportedDiagnosticsOnClassMembers(element)
}
}
/**
* Some FirClassChecker may report diagnostics on class member headers.
* That diagnostics should be suppressed if we have a `@Suppress` annotation on class member.
*/
private fun suppressReportedDiagnosticsOnClassMembers(element: FirRegularClass) {
for (member in element.declarations) {
withAnnotationContainer(member) {
member.accept(components.reportCommitter, context)
}
}
}
}
@@ -8,14 +8,17 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.fir
import org.jetbrains.kotlin.analysis.low.level.api.fir.ContextByDesignationCollector
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingClass
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollectorVisitor
import org.jetbrains.kotlin.fir.containingClass
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.renderWithType
import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
private class ContextCollectingDiagnosticCollectorVisitor private constructor(
sessionHolder: SessionHolder,
@@ -60,13 +63,20 @@ internal object PersistenceContextCollector {
is FirClassLikeDeclaration -> declaration.symbol.classId.isLocal
is FirCallableDeclaration -> declaration.symbol.callableId.isLocal
is FirDanglingModifierList -> declaration.containingClass()?.classId?.isLocal == true
is FirAnonymousInitializer -> declaration.containingClass().classId.isLocal
is FirScript -> false
else -> error("Unsupported declaration ${declaration.renderWithType()}")
}
require(!isLocal) {
"Cannot collect context for local declaration ${declaration.renderWithType()}"
}
val designation = declaration.collectDesignation(firFile)
designation.path.forEach { firClass ->
firClass.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
}
return ContextCollectingDiagnosticCollectorVisitor.collect(sessionHolder, designation)
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
@@ -116,6 +116,16 @@ internal fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: (KtDec
when (parent) {
is KtScript -> propose(parent)
is KtDestructuringDeclaration -> propose(parent)
is KtAnonymousInitializer -> {
val container = parent.containingDeclaration
if (container is KtClassOrObject &&
!container.isObjectLiteral() &&
declarationCanBeLazilyResolved(container) &&
predicate(parent)
) {
propose(parent)
}
}
is KtNamedDeclaration -> {
val isKindApplicable = when (parent) {
is KtClassOrObject -> !parent.isObjectLiteral()
@@ -5,43 +5,176 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirLazyResolveContractChecker
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.lockWithPCECheck
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.*
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater
import java.util.concurrent.locks.ReentrantLock
import com.intellij.openapi.progress.ProcessCanceledException
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.lockWithPCECheck
import org.jetbrains.kotlin.fir.declarations.FirFile
import java.util.concurrent.locks.ReentrantLock
/**
* Keyed locks provider.
*/
internal class LLFirLockProvider {
//We temporarily disable multi-locks to fix deadlocks problem
internal class LLFirLockProvider(private val checker: LLFirLazyResolveContractChecker) {
private val globalLock = ReentrantLock()
private val locksForImports = ContainerUtil.createConcurrentSoftMap<FirFile, ReentrantLock>()
private val superTypesLock = ReentrantLock()
private val implicitTypesLock = ReentrantLock()
private val statusLock = ReentrantLock()
private val compilerAnnotationsLock = ReentrantLock()
inline fun <R> withLock(
inline fun <R> withGlobalLock(
key: FirFile,
lockingIntervalMs: Long = DEFAULT_LOCKING_INTERVAL,
action: () -> R
): R {
return globalLock.lockWithPCECheck(lockingIntervalMs) {
val session = key.llFirSession
if (!session.isValid) {
throw ProcessCanceledException()
}
): R = globalLock.lockWithPCECheck(lockingIntervalMs) {
val session = key.llFirSession
if (!session.isValid) {
throw ProcessCanceledException()
}
action()
}
fun withGlobalPhaseLock(
phase: FirResolvePhase,
action: () -> Unit
) {
val lock = when (phase) {
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> implicitTypesLock
FirResolvePhase.STATUS -> statusLock
FirResolvePhase.SUPER_TYPES -> superTypesLock
FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS -> compilerAnnotationsLock
else -> null
}
if (lock == null) {
action()
} else {
lock.lockWithPCECheck(DEFAULT_LOCKING_INTERVAL, action)
}
}
inline fun <R> withLocksForImportResolution(
file: FirFile,
action: () -> R
): R {
return locksForImports.getOrPut(file) { ReentrantLock() }.lockWithPCECheck(DEFAULT_LOCKING_INTERVAL) { action() }
inline fun withLock(
target: FirElementWithResolveState,
phase: FirResolvePhase,
action: () -> Unit
) {
checker.lazyResolveToPhaseInside(phase) {
target.withCriticalSection(phase, action)
}
}
inline fun withJumpingLock(
target: FirElementWithResolveState,
phase: FirResolvePhase,
action: () -> Unit
) {
target.withCriticalSection(phase, action)
}
/**
* Locks an a [FirElementWithResolveState] to resolve from `toPhase - 1` to [toPhase] and then updates the [FirElementWithResolveState.resolveState] to a [toPhase].
*
* If [FirElementWithResolveState] is already at least at [toPhase], does nothing.
*
* Otherwise:
* - Marks [FirElementWithResolveState] as in a process of resovle
* - performs the resolve by calling [action]
* - updates the resolve phase to [toPhase]
* - notifies other threads waiting on the same lock that the declaration is already resolved by this thread, so other thread can continue its execution.
*
*
* Contention handling:
* - on lock acquisition, no real lock or barrier is created. Instead, the [FirElementWithResolveState.resolveState] is updated to indicate that the declaration is being resolved now.
* - If some other thread tries to resolve current [FirElementWithResolveState], it changes `resolveState` and puts the barrier there. Then it awaits on it until the initial thread which hold the lock finishes its job.
* - This way, no barrier is used in a case when no contention arise.
*/
private inline fun FirElementWithResolveState.withCriticalSection(
toPhase: FirResolvePhase,
action: () -> Unit
) {
while (true) {
checkCanceled()
@OptIn(ResolveStateAccess::class)
val stateSnapshot = resolveState
if (stateSnapshot.resolvePhase >= toPhase) {
// already resolved by some other thread
return
}
when (stateSnapshot) {
is FirInProcessOfResolvingToPhaseStateWithoutBarrier -> {
// some thread is resolving the phase, so we wait until it finishes
trySettingBarrier(toPhase, stateSnapshot)
continue
}
is FirInProcessOfResolvingToPhaseStateWithBarrier -> {
// some thread is waiting on a barrier as the declaration is beeing resovled, so we try too
if (!waitOnBarrier(stateSnapshot)) continue
checkPhase(toPhase)
return
}
is FirResolvedToPhaseState -> {
if (!tryLock(toPhase, stateSnapshot)) continue
try {
action()
} finally {
unlock(toPhase)
}
return
}
}
}
}
private fun waitOnBarrier(
stateSnapshot: FirInProcessOfResolvingToPhaseStateWithBarrier
): Boolean {
return stateSnapshot.barrier.await(DEFAULT_LOCKING_INTERVAL, TimeUnit.MILLISECONDS)
}
private fun FirElementWithResolveState.trySettingBarrier(
toPhase: FirResolvePhase,
stateSnapshot: FirResolveState
) {
val latch = CountDownLatch(1)
val newState = FirInProcessOfResolvingToPhaseStateWithBarrier(toPhase, latch)
resolveStateFieldUpdater.compareAndSet(this, stateSnapshot, newState)
}
private fun FirElementWithResolveState.tryLock(
toPhase: FirResolvePhase,
stateSnapshot: FirResolveState
): Boolean {
val newState = FirInProcessOfResolvingToPhaseStateWithoutBarrier(toPhase)
return resolveStateFieldUpdater.compareAndSet(this, stateSnapshot, newState)
}
private fun FirElementWithResolveState.unlock(toPhase: FirResolvePhase) {
when (val stateSnapshotAfter = resolveStateFieldUpdater.getAndSet(this, FirResolvedToPhaseState(toPhase))) {
is FirInProcessOfResolvingToPhaseStateWithoutBarrier -> {}
is FirInProcessOfResolvingToPhaseStateWithBarrier -> {
stateSnapshotAfter.barrier.countDown()
}
is FirResolvedToPhaseState -> {
error("phase is unexpectedly unlocked $stateSnapshotAfter")
}
}
}
}
private val resolveStateFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(
FirElementWithResolveState::class.java,
FirResolveState::class.java,
"resolveState"
)
private const val DEFAULT_LOCKING_INTERVAL = 50L
@@ -1,18 +1,17 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignationWithFile
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirClassWithSpecificMembersResolveTarget
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
import org.jetbrains.kotlin.psi.*
internal object FileElementFactory {
/**
@@ -40,12 +39,58 @@ internal object FileElementFactory {
moduleComponents,
)
else -> NonReanalyzableDeclarationStructureElement(
firFile,
firDeclaration,
ktDeclaration,
moduleComponents,
ktDeclaration is KtClassOrObject && ktDeclaration !is KtEnumEntry -> {
lazyResolveClassWithGeneratedMembers(firDeclaration as FirRegularClass, moduleComponents)
NonReanalyzableClassDeclarationStructureElement(
firFile,
firDeclaration,
ktDeclaration,
moduleComponents,
)
}
else -> {
NonReanalyzableNonClassDeclarationStructureElement(
firFile,
firDeclaration,
ktDeclaration,
moduleComponents,
)
}
}
private fun lazyResolveClassWithGeneratedMembers(firClass: FirRegularClass, moduleComponents: LLFirModuleResolveComponents) {
val classMembersToResolve = buildList {
for (member in firClass.declarations) {
when {
member is FirPrimaryConstructor && member.source?.kind == KtFakeSourceElementKind.ImplicitConstructor -> {
add(member)
}
member is FirProperty && member.source?.kind == KtFakeSourceElementKind.PropertyFromParameter -> {
add(member)
}
member is FirField && member.source?.kind == KtFakeSourceElementKind.ClassDelegationField -> {
add(member)
}
member is FirDanglingModifierList -> {
add(member)
}
}
}
}
val firClassDesignation = firClass.collectDesignationWithFile()
val designationWithMembers = LLFirClassWithSpecificMembersResolveTarget(
firClassDesignation.firFile,
firClassDesignation.path,
firClass,
classMembersToResolve,
)
moduleComponents.firModuleLazyDeclarationResolver.lazyResolveTarget(designationWithMembers, FirResolvePhase.BODY_RESOLVE)
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecific
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceByTraversingWholeTree
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirDanglingModifierList
import org.jetbrains.kotlin.fir.declarations.FirFile
@@ -22,6 +23,8 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import java.util.concurrent.ConcurrentHashMap
internal class FileStructure private constructor(
@@ -44,7 +47,7 @@ internal class FileStructure private constructor(
private val structureElements = ConcurrentHashMap<KtElement, FileStructureElement>()
fun getStructureElementFor(element: KtElement): FileStructureElement {
val declaration = element.getNonLocalContainingOrThisDeclaration()
val declaration = getStructureKtElement(element)
val container: KtElement
if (declaration != null) {
container = declaration
@@ -52,11 +55,61 @@ internal class FileStructure private constructor(
val modifierList = PsiTreeUtil.getParentOfType(element, KtModifierList::class.java, false)
container = if (modifierList != null && modifierList.nextSibling is PsiErrorElement) {
modifierList
} else element.containingKtFile
} else {
element.containingKtFile
}
}
return getStructureElementForDeclaration(container)
}
private fun getStructureKtElement(element: KtElement): KtDeclaration? {
val container = element.getNonLocalContainingOrThisDeclaration()
when {
container is KtClassOrObject && container.isInsideSuperClassCall(element) -> {
container.primaryConstructor?.let { return it }
}
container is KtPrimaryConstructor && container.isInsideAnnotationOnParameter(element) -> {
container.containingClassOrObject?.let { return it }
}
}
return container
}
private fun KtClassOrObject.isInsideSuperClassCall(element: KtElement): Boolean {
for (entry in superTypeListEntries) {
if (entry is KtSuperTypeCallEntry && entry.isAncestor(element, strict = false)) return true
}
return false
}
private fun KtPrimaryConstructor.isInsideAnnotationOnParameter(element: KtElement): Boolean {
for (parameter in valueParameters) {
for (annotation in parameter.annotationEntries) {
val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget() ?: continue
when (target) {
AnnotationUseSiteTarget.FIELD,
AnnotationUseSiteTarget.PROPERTY,
AnnotationUseSiteTarget.PROPERTY_GETTER,
AnnotationUseSiteTarget.PROPERTY_SETTER,
AnnotationUseSiteTarget.SETTER_PARAMETER -> {
if (annotation.isAncestor(element)) return true
}
AnnotationUseSiteTarget.FILE,
AnnotationUseSiteTarget.RECEIVER,
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER,
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> {
}
}
}
}
return false
}
private fun getStructureElementForDeclaration(declaration: KtElement): FileStructureElement {
@Suppress("CANNOT_CHECK_FOR_ERASED")
val structureElement = structureElements.compute(declaration) { _, structureElement ->
@@ -123,6 +176,7 @@ internal class FileStructure private constructor(
firProvider,
firFile
)
firDeclaration.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
return FileElementFactory.createFileStructureElement(
firDeclaration = firDeclaration,
@@ -133,8 +187,11 @@ internal class FileStructure private constructor(
}
private fun createDanglingModifierListStructure(container: KtElement): FileStructureElement {
val firDanglingModifierList = container.findSourceByTraversingWholeTree(moduleComponents.firFileBuilder, firFile) as? FirDanglingModifierList
?: errorWithFirSpecificEntries("No dangling modifier found", psi = container)
val firDanglingModifierList = container.findSourceByTraversingWholeTree(
moduleComponents.firFileBuilder,
firFile,
) as? FirDanglingModifierList ?: errorWithFirSpecificEntries("No dangling modifier found", psi = container)
firDanglingModifierList.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
return DanglingTopLevelModifierListStructureElement(firFile, firDanglingModifierList, moduleComponents, container.containingKtFile)
}
@@ -142,6 +199,8 @@ internal class FileStructure private constructor(
private fun createStructureElement(container: KtElement): FileStructureElement = when {
container is KtFile -> {
val firFile = moduleComponents.firFileBuilder.buildRawFirFileWithCaching(ktFile)
firFile.lazyResolveToPhase(FirResolvePhase.IMPORTS)
moduleComponents.firModuleLazyDeclarationResolver.lazyResolve(
target = firFile.annotationsContainer,
scopeSession = moduleComponents.scopeSessionProvider.getScopeSession(),
@@ -6,19 +6,20 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.ClassDiagnosticRetriever
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileDiagnosticRetriever
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.RawFirNonLocalDeclarationBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.declarationCanBeLazilyResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withInvalidationOnException
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
@@ -116,7 +117,7 @@ internal class ReanalyzableFunctionStructureElement(
rootNonLocalDeclaration = newKtDeclaration,
) as FirSimpleFunction
return moduleComponents.globalResolveComponents.lockProvider.withLock(firFile) {
return moduleComponents.globalResolveComponents.lockProvider.withGlobalLock(firFile) {
val upgradedPhase = minOf(originalFunction.resolvePhase, FirResolvePhase.DECLARATIONS)
withInvalidationOnException(moduleComponents.session) {
@@ -166,7 +167,7 @@ internal class ReanalyzablePropertyStructureElement(
rootNonLocalDeclaration = newKtDeclaration,
) as FirProperty
return moduleComponents.globalResolveComponents.lockProvider.withLock(firFile) {
return moduleComponents.globalResolveComponents.lockProvider.withGlobalLock(firFile) {
val getterPhase = originalProperty.getter?.resolvePhase ?: originalProperty.resolvePhase
val setterPhase = originalProperty.setter?.resolvePhase ?: originalProperty.resolvePhase
val upgradedPhase = minOf(originalProperty.resolvePhase, getterPhase, setterPhase, FirResolvePhase.DECLARATIONS)
@@ -197,13 +198,63 @@ internal class ReanalyzablePropertyStructureElement(
}
}
internal class NonReanalyzableDeclarationStructureElement(
internal sealed class NonReanalyzableDeclarationStructureElement(
firFile: FirFile,
moduleComponents: LLFirModuleResolveComponents,
) : FileStructureElement(firFile, moduleComponents)
internal class NonReanalyzableClassDeclarationStructureElement(
firFile: FirFile,
val fir: FirRegularClass,
override val psi: KtClassOrObject,
moduleComponents: LLFirModuleResolveComponents,
) : NonReanalyzableDeclarationStructureElement(firFile, moduleComponents) {
override val mappings = KtToFirMapping(fir, Recorder())
override val diagnostics = FileStructureElementDiagnostics(
firFile,
ClassDiagnosticRetriever(fir),
moduleComponents,
)
private inner class Recorder : FirElementsRecorder() {
override fun visitProperty(property: FirProperty, data: MutableMap<KtElement, FirElement>) {
if (property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) {
super.visitProperty(property, data)
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: MutableMap<KtElement, FirElement>) {
}
override fun visitConstructor(constructor: FirConstructor, data: MutableMap<KtElement, FirElement>) {
if (constructor is FirPrimaryConstructor && constructor.source?.kind == KtFakeSourceElementKind.ImplicitConstructor) {
super.visitConstructor(constructor, data)
}
}
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: MutableMap<KtElement, FirElement>) {
}
override fun visitRegularClass(regularClass: FirRegularClass, data: MutableMap<KtElement, FirElement>) {
if (regularClass != fir) return
super.visitRegularClass(regularClass, data)
}
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: MutableMap<KtElement, FirElement>) {
}
}
}
internal class NonReanalyzableNonClassDeclarationStructureElement(
firFile: FirFile,
val fir: FirDeclaration,
override val psi: KtDeclaration,
moduleComponents: LLFirModuleResolveComponents,
) : FileStructureElement(firFile, moduleComponents) {
override val mappings = KtToFirMapping(fir, recorder)
) : NonReanalyzableDeclarationStructureElement(firFile, moduleComponents) {
override val mappings = KtToFirMapping(fir, Recorder)
override val diagnostics = FileStructureElementDiagnostics(
firFile,
@@ -211,24 +262,7 @@ internal class NonReanalyzableDeclarationStructureElement(
moduleComponents,
)
companion object {
private val recorder = object : FirElementsRecorder() {
override fun visitProperty(property: FirProperty, data: MutableMap<KtElement, FirElement>) {
val psi = property.psi as? KtProperty ?: return super.visitProperty(property, data)
if (!isReanalyzableContainer(psi) || !declarationCanBeLazilyResolved(psi)) {
super.visitProperty(property, data)
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: MutableMap<KtElement, FirElement>) {
val psi = simpleFunction.psi as? KtNamedFunction ?: return super.visitSimpleFunction(simpleFunction, data)
if (!isReanalyzableContainer(psi) || !declarationCanBeLazilyResolved(psi)) {
super.visitSimpleFunction(simpleFunction, data)
}
}
}
}
private object Recorder : FirElementsRecorder()
}
internal class DanglingTopLevelModifierListStructureElement(
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
internal class LLFirLazyResolveContractChecker {
private val currentTransformerPhase = ThreadLocal.withInitial<FirResolvePhase?> { null }
inline fun lazyResolveToPhaseInside(phase: FirResolvePhase, resolve: () -> Unit) {
if (currentTransformerPhase.get() == FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) return
checkIfCanLazyResolveToPhase(phase)
val previousPhase = currentTransformerPhase.get()
currentTransformerPhase.set(phase)
try {
resolve()
} finally {
currentTransformerPhase.set(previousPhase)
}
}
private fun checkIfCanLazyResolveToPhase(requestedPhase: FirResolvePhase) {
val currentPhase = currentTransformerPhase.get() ?: return
if (requestedPhase >= currentPhase) {
error(
"""`lazyResolveToPhase($requestedPhase)` cannot be called from a transformer with a phase $currentPhase.
`lazyResolveToPhase` can be called only from a transformer with a phase which is strictly greater than a requested phase;
i.e., `lazyResolveToPhase(A)` may be only called from a lazy transformer with a phase B, where A < B. This is a contract of lazy resolve""".trimIndent()
)
}
}
}
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.tryCollectDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirClassWithAllMembersResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirSingleResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.forEachPathElementAndTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformerExecutor
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyResolverRunner
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.withOnAirDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile
@@ -19,73 +21,24 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry
import org.jetbrains.kotlin.analysis.utils.errors.rethrowExceptionWithDetails
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
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.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.resolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirModuleResolveComponents) {
private fun FirDeclaration.isValidForResolve(): Boolean = when (origin) {
is FirDeclarationOrigin.Source,
is FirDeclarationOrigin.ImportedFromObjectOrStatic,
is FirDeclarationOrigin.Delegated,
is FirDeclarationOrigin.Synthetic,
is FirDeclarationOrigin.SubstitutionOverride,
is FirDeclarationOrigin.SamConstructor,
is FirDeclarationOrigin.IntersectionOverride -> {
when (this) {
is FirFile -> true
is FirSyntheticProperty -> false
is FirSyntheticPropertyAccessor -> false
is FirSimpleFunction,
is FirProperty,
is FirPropertyAccessor,
is FirField,
is FirTypeAlias,
is FirConstructor -> resolvePhase < FirResolvePhase.BODY_RESOLVE
else -> true
}
}
else -> {
check(resolvePhase == FirResolvePhase.BODY_RESOLVE) {
"Expected body resolve phase for origin $origin but found $resolvePhase"
}
false
}
}
private fun FirElementWithResolveState.isValidForResolve() = when (this) {
is FirDeclaration -> isValidForResolve()
is FirFileAnnotationsContainer -> true
else -> throwUnexpectedFirElementError(this)
}
private fun resolveContainingFileToImports(target: FirElementWithResolveState) {
if (target.resolvePhase >= FirResolvePhase.IMPORTS) return
val firFile = target.getContainingFile() ?: return
if (firFile.resolvePhase >= FirResolvePhase.IMPORTS) return
moduleComponents.globalResolveComponents.lockProvider.withLocksForImportResolution(firFile) {
resolveFileToImportsWithoutLock(firFile)
}
}
private fun resolveFileToImportsWithoutLock(firFile: FirFile) {
if (firFile.resolvePhase >= FirResolvePhase.IMPORTS) return
checkCanceled()
firFile.transform<FirElement, Any?>(FirImportResolveTransformer(firFile.moduleData.session), null)
@OptIn(ResolveStateAccess::class)
firFile.resolveState = FirResolvePhase.IMPORTS.asResolveState()
}
/**
* Run designated resolve only designation with fully resolved path (synchronized).
* Lazily resolves the [target] to a given [toPhase].
*
* Might resolve additional required declarations.
*
* Resolution is performed under the lock specific to each declaration which is going to be resolved.
*
* Suitable for body resolve or/and on-air resolve.
* @see lazyResolve for ordinary resolve
* @param target target non-local declaration
*/
fun lazyResolve(
target: FirElementWithResolveState,
@@ -93,77 +46,68 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod
toPhase: FirResolvePhase,
) {
val fromPhase = target.resolvePhase
if (fromPhase >= toPhase) return
try {
doLazyResolve(target, scopeSession, toPhase)
resolveContainingFileToImports(target)
if (toPhase == FirResolvePhase.IMPORTS) return
lazyResolveTargets(
targets = LLFirResolveMultiDesignationCollector.getDesignationsToResolve(target),
scopeSession = scopeSession,
toPhase = toPhase,
)
} catch (e: Exception) {
handleExceptionFromResolve(e, target, fromPhase, toPhase)
}
}
private fun doLazyResolve(
target: FirElementWithResolveState,
/**
* Lazily resolves the [target] with all callable members to a given [toPhase].
*
* Might resolve additional required declarations.
*
* Resolution is performed under the lock specific to each declaration which is going to be resolved.
*
* Suitable for body resolve or/and on-air resolve.
*/
fun lazyResolveWithCallableMembers(
target: FirRegularClass,
scopeSession: ScopeSession,
toPhase: FirResolvePhase,
) {
if (target.resolvePhase >= toPhase) return
resolveContainingFileToImports(target)
if (toPhase == FirResolvePhase.IMPORTS) return
val fromPhase = target.resolvePhase
try {
resolveContainingFileToImports(target)
if (toPhase == FirResolvePhase.IMPORTS) return
for (designation in declarationDesignationsToResolve(target)) {
if (!designation.target.isValidForResolve()) continue
if (designation.target.resolvePhase >= toPhase) continue
moduleComponents.globalResolveComponents.lockProvider.withLock(designation.firFile) {
runLazyDesignatedResolveWithoutLock(
designation = designation,
scopeSession = scopeSession,
toPhase = toPhase,
)
}
}
}
private fun declarationDesignationsToResolve(target: FirElementWithResolveState): List<FirDesignationWithFile> {
return when (target) {
is FirPropertyAccessor -> declarationDesignationsToResolve(target.propertySymbol.fir)
is FirBackingField -> declarationDesignationsToResolve(target.propertySymbol.fir)
is FirTypeParameter -> declarationDesignationsToResolve(target.containingDeclarationSymbol.fir)
is FirValueParameter -> declarationDesignationsToResolve(target.containingFunctionSymbol.fir)
is FirFile -> {
val validForResolveDeclarations = buildList {
add(target.annotationsContainer)
target.declarations.filterTo(this) { it.isValidForResolve() }
}
validForResolveDeclarations.map {
FirDesignationWithFile(path = emptyList(), target = it, firFile = target)
}
}
else -> listOfNotNull(target.tryCollectDesignationWithFile())
}
}
private fun runLazyDesignatedResolveWithoutLock(
designation: FirDesignationWithFile,
scopeSession: ScopeSession,
toPhase: FirResolvePhase,
) {
val declarationResolvePhase = designation.target.resolvePhase
if (declarationResolvePhase >= toPhase) return
var currentPhase = maxOf(declarationResolvePhase, FirResolvePhase.IMPORTS)
while (currentPhase < toPhase) {
currentPhase = currentPhase.next
checkCanceled()
LLFirLazyTransformerExecutor.execute(
phase = currentPhase,
designation = designation,
lazyResolveTargets(
targets = LLFirResolveMultiDesignationCollector.getDesignationsToResolveWithCallableMembers(target),
scopeSession = scopeSession,
lockProvider = moduleComponents.globalResolveComponents.lockProvider,
towerDataContextCollector = null
toPhase = toPhase,
)
} catch (e: Exception) {
handleExceptionFromResolve(e, target, fromPhase, toPhase)
}
}
/**
* Lazily resolves all the declarations which are specified for resolve by [target]
*
* Might resolve additional required declarations.
*
* Resolution is performed under the lock specific to each declaration which is going to be resolved.
*
* Suitable for body resolve or/and on-air resolve.
*/
fun lazyResolveTarget(
target: LLFirResolveTarget,
toPhase: FirResolvePhase
) {
try {
lazyResolveTargets(listOf(target), moduleComponents.scopeSessionProvider.getScopeSession(), toPhase)
} catch (e: Exception) {
handleExceptionFromResolve(e, target, toPhase)
}
}
@@ -173,6 +117,10 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod
towerDataContextCollector: FirTowerDataContextCollector?,
) {
resolveFileToImportsWithoutLock(designation.firFile)
val resolveTarget = when (designation.target) {
is FirRegularClass -> LLFirClassWithAllMembersResolveTarget(designation.firFile, designation.path, designation.target)
else -> LLFirSingleResolveTarget(designation.firFile, designation.path, designation.target)
}
fun runTransformation() {
val scopeSession = ScopeSession()
@@ -182,9 +130,9 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod
currentPhase = currentPhase.next
checkCanceled()
LLFirLazyTransformerExecutor.execute(
LLFirLazyResolverRunner.runLazyResolverByPhase(
phase = currentPhase,
designation = designation,
target = resolveTarget,
scopeSession = scopeSession,
lockProvider = moduleComponents.globalResolveComponents.lockProvider,
towerDataContextCollector = towerDataContextCollector,
@@ -198,6 +146,58 @@ internal class LLFirModuleLazyDeclarationResolver(val moduleComponents: LLFirMod
runTransformation()
}
}
private fun resolveContainingFileToImports(target: FirElementWithResolveState) {
if (target.resolvePhase >= FirResolvePhase.IMPORTS) return
val firFile = target.getContainingFile() ?: return
if (firFile.resolvePhase >= FirResolvePhase.IMPORTS) return
moduleComponents.globalResolveComponents.lockProvider.withLock(firFile, FirResolvePhase.IMPORTS) {
resolveFileToImportsWithoutLock(firFile)
}
}
private fun resolveFileToImportsWithoutLock(firFile: FirFile) {
if (firFile.resolvePhase >= FirResolvePhase.IMPORTS) return
checkCanceled()
firFile.transform<FirElement, Any?>(FirImportResolveTransformer(firFile.moduleData.session), null)
}
private fun lazyResolveTargets(
targets: List<LLFirResolveTarget>,
scopeSession: ScopeSession,
toPhase: FirResolvePhase,
) {
if (targets.isEmpty()) return
var currentPhase = getMinResolvePhase(targets).coerceAtLeast(FirResolvePhase.IMPORTS)
if (currentPhase >= toPhase) return
while (currentPhase < toPhase) {
currentPhase = currentPhase.next
checkCanceled()
for (target in targets) {
LLFirLazyResolverRunner.runLazyResolverByPhase(
phase = currentPhase,
target = target,
scopeSession = scopeSession,
lockProvider = moduleComponents.globalResolveComponents.lockProvider,
towerDataContextCollector = null
)
}
}
}
private fun getMinResolvePhase(designations: List<LLFirResolveTarget>): FirResolvePhase {
var min = FirResolvePhase.BODY_RESOLVE
for (designation in designations) {
if (min == FirResolvePhase.RAW_FIR) break
designation.forEachPathElementAndTarget { target ->
min = minOf(min, target.resolvePhase)
}
}
return min
}
}
private fun handleExceptionFromResolve(
@@ -226,4 +226,29 @@ private fun handleExceptionFromResolve(
withEntry("moduleData", firDeclarationToResolve.moduleData) { it.toString() }
withFirEntry("firDeclarationToResolve", firDeclarationToResolve)
}
}
private fun handleExceptionFromResolve(
exception: Exception,
designation: LLFirResolveTarget,
toPhase: FirResolvePhase?
): Nothing {
val llFirSession = designation.firFile.llFirSession
llFirSession.invalidate()
val moduleData = llFirSession.llFirModuleData
rethrowExceptionWithDetails(
buildString {
appendLine("Error while resolving ${designation::class.java.name} ")
appendLine("to $toPhase")
appendLine("module data: ${moduleData::class}")
appendLine("KtModule: ${moduleData.ktModule::class}")
appendLine("platform: ${moduleData.ktModule.platform}")
},
exception = exception,
) {
withEntry("KtModule", moduleData.ktModule) { it.moduleDescription }
withEntry("session", designation.firFile.llFirSession) { it.toString() }
withEntry("moduleData", moduleData) { it.toString() }
withEntry("firDesignationToResolve", designation) { it.toString() }
}
}
@@ -17,10 +17,18 @@ internal object LLFirPhaseUpdater {
newPhase: FirResolvePhase,
updateForLocalDeclarations: Boolean,
) {
if (updateForLocalDeclarations) {
target.acceptChildren(PhaseUpdatingTransformer, newPhase)
} else {
updatePhaseForNonLocals(target, newPhase, isTargetDeclaration = true)
updatePhaseForNonLocals(target, newPhase, isTargetDeclaration = true)
if (updateForLocalDeclarations && target is FirCallableDeclaration) {
when (target) {
is FirFunction -> target.body?.accept(PhaseUpdatingTransformer, newPhase)
is FirVariable -> {
target.initializer?.accept(PhaseUpdatingTransformer, newPhase)
target.getter?.body?.accept(PhaseUpdatingTransformer, newPhase)
target.setter?.body?.accept(PhaseUpdatingTransformer, newPhase)
target.backingField?.accept(PhaseUpdatingTransformer, newPhase)
}
}
}
}
@@ -29,7 +37,8 @@ internal object LLFirPhaseUpdater {
if (element.resolvePhase >= newPhase) return
if (!isTargetDeclaration) {
// phase update for target declaration happens as a declaration publication event after resolve is finished
element.replaceResolveState(newPhase.asResolveState())
@OptIn(ResolveStateAccess::class)
element.resolveState = newPhase.asResolveState()
}
if (element is FirTypeParameterRefsOwner) {
@@ -48,13 +57,9 @@ internal object LLFirPhaseUpdater {
is FirProperty -> {
element.getter?.let { updatePhaseForNonLocals(it, newPhase, isTargetDeclaration = false) }
element.setter?.let { updatePhaseForNonLocals(it, newPhase, isTargetDeclaration = false) }
element.backingField?.let { updatePhaseForNonLocals(it, newPhase, isTargetDeclaration = false) }
}
is FirClass -> {
element.declarations.forEach {
updatePhaseForNonLocals(it, newPhase, isTargetDeclaration = false)
}
}
else -> Unit
else -> {}
}
}
}
@@ -63,7 +68,9 @@ private object PhaseUpdatingTransformer : FirVisitor<Unit, FirResolvePhase>() {
override fun visitElement(element: FirElement, data: FirResolvePhase) {
if (element is FirElementWithResolveState) {
if (element.resolvePhase >= data && element !is FirDefaultPropertyAccessor) return
element.replaceResolveState(data.asResolveState())
@OptIn(ResolveStateAccess::class)
element.resolveState = data.asResolveState()
}
element.acceptChildren(this, data)
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirClassWithAllCallablesResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirWholeFileResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.asResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.tryCollectDesignationWithFile
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
internal object LLFirResolveMultiDesignationCollector {
fun getDesignationsToResolve(target: FirElementWithResolveState): List<LLFirResolveTarget> {
return when (target) {
is FirFile -> listOf(LLFirWholeFileResolveTarget(target))
else -> getMainDesignationToResolve(target)?.withAnnotationContainer()
} ?: emptyList()
}
fun getDesignationsToResolveWithCallableMembers(target: FirRegularClass): List<LLFirResolveTarget> {
val designation = target.tryCollectDesignationWithFile() ?: return emptyList()
val resolveTarget = LLFirClassWithAllCallablesResolveTarget(designation.firFile, designation.path, target)
return resolveTarget.withAnnotationContainer()
}
private fun LLFirResolveTarget.withAnnotationContainer(): List<LLFirResolveTarget> {
val annotationsContainer = firFile.annotationsContainer
if (!annotationsContainer.shouldBeResolved()) return listOf(this)
return buildList {
add(annotationsContainer.collectDesignationWithFile().asResolveTarget())
add(this@withAnnotationContainer)
}
}
private fun getMainDesignationToResolve(target: FirElementWithResolveState): LLFirResolveTarget? {
require(target !is FirFile)
if (!target.shouldBeResolved()) return null
return when (target) {
is FirPropertyAccessor -> getMainDesignationToResolve(target.propertySymbol.fir)
is FirBackingField -> getMainDesignationToResolve(target.propertySymbol.fir)
is FirTypeParameter -> getMainDesignationToResolve(target.containingDeclarationSymbol.fir)
is FirValueParameter -> getMainDesignationToResolve(target.containingFunctionSymbol.fir)
else -> target.tryCollectDesignationWithFile()?.asResolveTarget()
}
}
private fun FirElementWithResolveState.shouldBeResolved() = when (this) {
is FirDeclaration -> shouldBeResolved()
is FirFileAnnotationsContainer -> annotations.isNotEmpty()
else -> throwUnexpectedFirElementError(this)
}
private fun FirDeclaration.shouldBeResolved(): Boolean = when (origin) {
is FirDeclarationOrigin.Source,
is FirDeclarationOrigin.ImportedFromObjectOrStatic,
is FirDeclarationOrigin.Delegated,
is FirDeclarationOrigin.Synthetic,
is FirDeclarationOrigin.SubstitutionOverride,
is FirDeclarationOrigin.SamConstructor,
is FirDeclarationOrigin.IntersectionOverride -> {
when (this) {
is FirFile -> true
is FirSyntheticProperty -> false
is FirSyntheticPropertyAccessor -> false
is FirSimpleFunction,
is FirProperty,
is FirPropertyAccessor,
is FirField,
is FirTypeAlias,
is FirConstructor -> true
else -> true
}
}
else -> {
@OptIn(ResolveStateAccess::class)
check(resolvePhase == FirResolvePhase.BODY_RESOLVE) {
"Expected body resolve phase for origin $origin but found $resolveState"
}
false
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2023 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.
*/
@@ -49,20 +49,18 @@ internal fun FirDeclaration.getKtDeclarationForFirElement(): KtDeclaration {
return declaration
}
internal fun declarationCanBeLazilyResolved(declaration: KtDeclaration): Boolean {
return when (declaration) {
!is KtNamedDeclaration -> false
is KtDestructuringDeclarationEntry, is KtFunctionLiteral, is KtTypeParameter -> false
is KtPrimaryConstructor -> false
is KtParameter -> declaration.hasValOrVar() && declaration.containingClassOrObject?.getClassId() != null
is KtCallableDeclaration, is KtEnumEntry -> {
when (val parent = declaration.parent) {
is KtFile -> true
is KtClassBody -> (parent.parent as? KtClassOrObject)?.getClassId() != null
else -> false
}
internal fun declarationCanBeLazilyResolved(declaration: KtDeclaration): Boolean = when (declaration) {
is KtDestructuringDeclarationEntry, is KtFunctionLiteral, is KtTypeParameter -> false
is KtPrimaryConstructor -> (declaration.parent as? KtClassOrObject)?.getClassId() != null
is KtParameter -> declaration.hasValOrVar() && declaration.containingClassOrObject?.getClassId() != null
is KtCallableDeclaration, is KtEnumEntry, is KtClassInitializer -> {
when (val parent = declaration.parent) {
is KtFile -> true
is KtClassBody -> (parent.parent as? KtClassOrObject)?.getClassId() != null
else -> false
}
is KtClassLikeDeclaration -> declaration.getClassId() != null
else -> error("Unexpected ${declaration::class.qualifiedName}")
}
!is KtNamedDeclaration -> false
is KtClassLikeDeclaration -> declaration.getClassId() != null
else -> error("Unexpected ${declaration::class.qualifiedName}")
}
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.LLFirDesignatedImpliciteTypesBodyResolveTransformerForReturnTypeCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformerDispatcher
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.createReturnTypeCalculatorForIDE
internal abstract class LLFirAbstractBodyTargetResolver(
resolveTarget: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
private val scopeSession: ScopeSession,
resolvePhase: FirResolvePhase,
protected val implicitBodyResolveComputationSession: ImplicitBodyResolveComputationSession = ImplicitBodyResolveComputationSession()
) : LLFirTargetResolver(resolveTarget, lockProvider, resolvePhase) {
protected fun createReturnTypeCalculator(): ReturnTypeCalculator = createReturnTypeCalculatorForIDE(
scopeSession,
implicitBodyResolveComputationSession,
::LLFirDesignatedImpliciteTypesBodyResolveTransformerForReturnTypeCalculator
)
abstract val transformer: FirAbstractBodyResolveTransformerDispatcher
override fun checkResolveConsistency() {
check(resolverPhase == transformer.transformerPhase) {
"Inconsistent Resolver($resolverPhase) and Transformer(${transformer.transformerPhase}) phases"
}
}
override fun withFile(firFile: FirFile, action: () -> Unit) {
transformer.context.withFile(firFile, transformer.components) {
action()
}
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
transformer.declarationsTransformer.context.withContainingClass(firClass) {
transformer.declarationsTransformer.withRegularClass(firClass) {
action()
firClass
}
}
}
protected fun calculateLazyBodies(declaration: FirElementWithResolveState) {
val firDesignation = FirDesignationWithFile(nestedClassesStack, declaration, resolveTarget.firFile)
FirLazyBodiesCalculator.calculateLazyBodiesInside(firDesignation)
}
}
@@ -0,0 +1,87 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkAnnotationArgumentsMappingIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirAnnotationArgumentsMappingTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle
internal object LLFirAnnotationArgumentMappingLazyResolver : LLFirLazyResolver(FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirAnnotationArgumentsMappingTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
if (target !is FirAnnotationContainer) return
for (annotation in target.annotations) {
if (annotation is FirAnnotationCall) {
checkAnnotationArgumentsMappingIsResolved(annotation, target)
}
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirAnnotationArgumentsMappingTargetResolver(
resolveTarget: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirAbstractBodyTargetResolver(
resolveTarget,
lockProvider,
scopeSession,
FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING,
) {
override val transformer = FirAnnotationArgumentsMappingTransformer(
session,
scopeSession,
resolverPhase,
returnTypeCalculator = createReturnTypeCalculator()
)
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
FirLazyBodiesCalculator.calculateAnnotations(target)
when (target) {
is FirRegularClass -> {
target.transformAnnotations(transformer.declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformTypeParameters(transformer.declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformSuperTypeRefs(transformer.declarationsTransformer, ResolutionMode.ContextIndependent)
}
is FirCallableDeclaration, is FirAnonymousInitializer, is FirDanglingModifierList, is FirFileAnnotationsContainer, is FirTypeAlias, is FirScript -> {
target.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
else -> throwUnexpectedFirElementError(target)
}
}
}
@@ -0,0 +1,98 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkTypeRefIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirAnnotationArgumentsResolveTransformer
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.visitors.transformSingle
internal object LLFirAnnotationArgumentsLazyResolver : LLFirLazyResolver(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirAnnotationArgumentsTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
if (target !is FirAnnotationContainer) return
val unresolvedAnnotation = target.annotations.firstOrNull { it.annotationTypeRef !is FirResolvedTypeRef }
check(unresolvedAnnotation == null) {
"Unexpected annotationTypeRef annotation, expected resolvedType but actual ${unresolvedAnnotation?.annotationTypeRef}"
}
target.checkPhase(resolverPhase)
for (annotation in target.annotations) {
for (argument in annotation.argumentMapping.mapping.values) {
checkTypeRefIsResolved(argument.typeRef, "annotation argument", target) {
withFirEntry("firAnnotation", annotation)
withFirEntry("firArgument", argument)
}
}
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirAnnotationArgumentsTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirAbstractBodyTargetResolver(
target,
lockProvider,
scopeSession,
FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS,
) {
override val transformer = FirAnnotationArgumentsResolveTransformer(
session,
scopeSession,
resolverPhase,
returnTypeCalculator = createReturnTypeCalculator()
)
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
FirLazyBodiesCalculator.calculateAnnotations(target)
when (target) {
is FirRegularClass -> {
target.transformAnnotations(transformer.declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformTypeParameters(transformer.declarationsTransformer, ResolutionMode.ContextIndependent)
target.transformSuperTypeRefs(transformer.declarationsTransformer, ResolutionMode.ContextIndependent)
}
is FirCallableDeclaration, is FirAnonymousInitializer, is FirDanglingModifierList, is FirFileAnnotationsContainer, is FirTypeAlias, is FirScript -> {
target.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
else -> throwUnexpectedFirElementError(target)
}
}
}
@@ -0,0 +1,165 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkBodyIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDefaultValueIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkInitializerIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment
import org.jetbrains.kotlin.analysis.utils.errors.checkWithAttachmentBuilder
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.visitors.transformSingle
internal object LLFirBodyLazyResolver : LLFirLazyResolver(FirResolvePhase.BODY_RESOLVE) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirBodyTargetResolver(target, lockProvider, session, scopeSession, towerDataContextCollector)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = true)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
when (target) {
is FirValueParameter -> checkDefaultValueIsResolved(target)
is FirVariable -> checkInitializerIsResolved(target)
is FirFunction -> checkBodyIsResolved(target)
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirBodyTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) : LLFirAbstractBodyTargetResolver(
target,
lockProvider,
scopeSession,
FirResolvePhase.BODY_RESOLVE,
) {
override val transformer = object : FirBodyResolveTransformer(
session,
phase = resolverPhase,
implicitTypeOnly = false,
scopeSession = scopeSession,
returnTypeCalculator = createReturnTypeCalculator(),
firTowerDataContextCollector = towerDataContextCollector,
) {
override val preserveCFGForClasses: Boolean get() = false
}
override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean {
when (target) {
is FirRegularClass -> {
if (target.resolvePhase >= resolverPhase) return true
withRegularClass(target) {
transformer.firTowerDataContextCollector?.addDeclarationContext(target, transformer.context.towerDataContext)
}
// resolve class CFG graph here, to do this we need to have property & init blocks resoled
resolveMemberProperties(target)
performCustomResolveUnderLock(target) {
calculateCFG(target)
}
return true
}
}
return false
}
private fun calculateCFG(target: FirRegularClass) {
checkWithAttachmentBuilder(
target.controlFlowGraphReference == null,
{ "controlFlowGraphReference should be null if class phase < $resolverPhase)" },
) {
withFirEntry("firClass", target)
}
val dataFlowAnalyzer = transformer.declarationsTransformer.dataFlowAnalyzer
dataFlowAnalyzer.enterClass(target, buildGraph = true)
val controlFlowGraph = dataFlowAnalyzer.exitClass()
?: buildErrorWithAttachment("CFG should not be null as buildGraph is specified") {
withFirEntry("firClass", target)
}
target.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(controlFlowGraph))
}
private fun resolveMemberProperties(target: FirRegularClass) {
withRegularClass(target) {
for (member in target.declarations) {
if (member is FirCallableDeclaration || member is FirAnonymousInitializer) {
/* TODO we should resolve only properties and init blocks here but due to the recent changes in the compiler, we also have to do this for all callable members
we should avoid doing it as it leads to additional work and also can might to problems with incremental analysis
*/
member.lazyResolveToPhase(resolverPhase.previous)
performResolve(member)
}
}
}
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
val contextCollector = transformer.firTowerDataContextCollector
if (contextCollector != null && target is FirDeclaration) {
val bodyResolveContext = transformer.context
if (target is FirFunction) {
bodyResolveContext.forFunctionBody(target, transformer.components) {
contextCollector.addDeclarationContext(target, bodyResolveContext.towerDataContext)
}
} else {
contextCollector.addDeclarationContext(target, bodyResolveContext.towerDataContext)
}
}
when (target) {
is FirRegularClass -> {
error("should be resolved in ${::doResolveWithoutLock.name}")
}
is FirDanglingModifierList, is FirFileAnnotationsContainer, is FirTypeAlias -> {
// no bodies here
}
is FirCallableDeclaration, is FirAnonymousInitializer, is FirScript -> {
calculateLazyBodies(target)
target.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
else -> throwUnexpectedFirElementError(target)
}
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.CompilerRequiredAnnotationsComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirCompilerRequiredAnnotationsResolveTransformer
internal object LLFirCompilerAnnotationsLazyResolver : LLFirLazyResolver(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirCompilerRequiredAnnotationsTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
checkNestedDeclarationsAreResolved(target)
// TODO add proper check that COMPILER_REQUIRED_ANNOTATIONS are resolved
}
}
private class LLFirCompilerRequiredAnnotationsTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS, isJumpingPhase = true) {
private val transformer =
FirCompilerRequiredAnnotationsResolveTransformer(session, scopeSession, CompilerRequiredAnnotationsComputationSession())
override fun withFile(firFile: FirFile, action: () -> Unit) {
transformer.annotationTransformer.withFileAndFileScopes(firFile) {
action()
}
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
transformer.annotationTransformer.withRegularClass(firClass) {
action()
}
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
FirLazyBodiesCalculator.calculateCompilerAnnotations(target)
when (target) {
is FirTypeAlias -> {
transformer.transformTypeAlias(target, null)
}
is FirRegularClass -> {
transformer.annotationTransformer.resolveRegularClass(
target,
transformChildren = {
target.transformSuperTypeRefs(transformer.annotationTransformer, null)
},
afterChildrenTransform = {
transformer.annotationTransformer.calculateDeprecations(target)
}
)
}
}
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractResolveTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle
internal object LLFirContractsLazyResolver : LLFirLazyResolver(FirResolvePhase.CONTRACTS) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirContractsTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
if (target is FirContractDescriptionOwner) {
// TODO checkContractDescriptionIsResolved(declaration)
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirContractsTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirAbstractBodyTargetResolver(
target,
lockProvider,
scopeSession,
FirResolvePhase.CONTRACTS
) {
override val transformer = FirContractResolveTransformer(session, scopeSession)
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
when (target) {
is FirRegularClass, is FirAnonymousInitializer, is FirDanglingModifierList, is FirFileAnnotationsContainer, is FirTypeAlias, is FirScript -> {
// no contracts here
}
is FirCallableDeclaration -> {
// TODO calculate bodies only when in-body contract is present
calculateLazyBodies(target)
target.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
else -> throwUnexpectedFirElementError(target)
}
}
}
@@ -1,76 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
internal class LLFirDeclarationTransformer(private val designation: FirDesignation) {
private val designationWithoutTargetIterator = designation.toSequence(includeTarget = false).iterator()
private var isInsideTargetDeclaration: Boolean = false
private var designationPassed: Boolean = false
inline fun <D> visitDeclarationContent(
visitor: FirVisitor<Unit, D>,
declaration: FirDeclaration,
data: D,
default: () -> FirDeclaration
): FirDeclaration = processDeclarationContent(declaration, default) {
it.accept(visitor, data)
}
inline fun <D> transformDeclarationContent(
transformer: FirDefaultTransformer<D>,
declaration: FirDeclaration,
data: D,
default: () -> FirDeclaration
): FirDeclaration = processDeclarationContent(declaration, default) { toTransform ->
toTransform.transform<FirElement, D>(transformer, data).also { transformed ->
check(transformed === toTransform) {
"become $transformed `${transformed.render()}`, was ${toTransform}: `${toTransform.render()}`"
}
}
}
private inline fun processDeclarationContent(
declaration: FirDeclaration,
default: () -> FirDeclaration,
applyToDesignated: (FirElementWithResolveState) -> Unit,
): FirDeclaration {
//It means that we are inside the target declaration
if (isInsideTargetDeclaration) {
return default()
}
//It means that we already transform target declaration and now can skip all others
if (designationPassed) {
return declaration
}
if (designationWithoutTargetIterator.hasNext()) {
applyToDesignated(designationWithoutTargetIterator.next())
} else {
try {
isInsideTargetDeclaration = true
designationPassed = true
applyToDesignated(designation.target)
} finally {
isInsideTargetDeclaration = false
}
}
return declaration
}
fun ensureDesignationPassed() {
check(designationPassed) { "Designation not passed for declaration ${designation.target::class.simpleName}" }
}
}
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkAnnotationArgumentsMappingIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
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.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirAnnotationArgumentsMappingTransformer
/**
* Transform designation into ANNOTATIONS_ARGUMENTS_MAPPING declaration. Affects only for target declaration, it's children and dependents
*/
internal class LLFirDesignatedAnnotationArgumentsMappingTransformer(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirLazyTransformer, FirAnnotationArgumentsMappingTransformer(session, scopeSession, FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING) {
private val ideDeclarationTransformer = LLFirDeclarationTransformer(designation)
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration =
ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) {
super.transformDeclarationContent(declaration, data)
}
override fun transformDeclaration() {
FirLazyBodiesCalculator.calculateAnnotations(designation.firFile)
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(
target,
FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING,
updateForLocalDeclarations = false,
)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING)
if (target !is FirAnnotationContainer) return
for (annotation in target.annotations) {
if (annotation is FirAnnotationCall) {
checkAnnotationArgumentsMappingIsResolved(annotation, target)
}
}
checkNestedDeclarationsAreResolved(target)
}
}
@@ -1,89 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkTypeRefIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirAnnotationArgumentsResolveTransformer
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
internal class LLFirDesignatedAnnotationArgumentsResolveTransformer(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirLazyTransformer, FirAnnotationArgumentsResolveTransformer(session, scopeSession, FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS) {
private fun moveNextDeclaration(designationIterator: Iterator<FirElementWithResolveState>) {
if (!designationIterator.hasNext()) {
FirLazyBodiesCalculator.calculateAnnotations(designation.target)
designation.target.transform<FirDeclaration, ResolutionMode>(declarationsTransformer, ResolutionMode.ContextIndependent)
return
}
when (val nextElement = designationIterator.next()) {
is FirFile -> {
context.withFile(nextElement, components) {
moveNextDeclaration(designationIterator)
}
}
is FirRegularClass -> {
context.withRegularClass(nextElement, components) {
moveNextDeclaration(designationIterator)
}
}
is FirEnumEntry -> {
context.forEnumEntry {
moveNextDeclaration(designationIterator)
}
}
else -> {
error("Unexpected declaration in designation: ${nextElement::class.qualifiedName}")
}
}
}
override fun transformDeclaration() {
val designationIterator = designation.toSequenceWithFile(includeTarget = false).iterator()
moveNextDeclaration(designationIterator)
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(
target,
FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS,
updateForLocalDeclarations = false,
)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
if (target !is FirAnnotationContainer) return
val unresolvedAnnotation = target.annotations.firstOrNull { it.annotationTypeRef !is FirResolvedTypeRef }
check(unresolvedAnnotation == null) {
"Unexpected annotationTypeRef annotation, expected resolvedType but actual ${unresolvedAnnotation?.annotationTypeRef}"
}
target.checkPhase(FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS)
for (annotation in target.annotations) {
for (argument in annotation.argumentMapping.mapping.values) {
checkTypeRefIsResolved(argument.typeRef, "annotation argument", target) {
withFirEntry("firAnnotation", annotation)
withFirEntry("firArgument", argument)
}
}
}
checkNestedDeclarationsAreResolved(target)
}
}
@@ -1,69 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.CompilerRequiredAnnotationsComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirCompilerRequiredAnnotationsResolveTransformer
internal class LLFirDesignatedAnnotationsResolveTransformed(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirLazyTransformer,
FirCompilerRequiredAnnotationsResolveTransformer(session, scopeSession, CompilerRequiredAnnotationsComputationSession()) {
private fun moveNextDeclaration(designationIterator: Iterator<FirElementWithResolveState>) {
if (!designationIterator.hasNext()) {
val declaration = designation.target
FirLazyBodiesCalculator.calculateCompilerAnnotations(declaration)
if (declaration is FirRegularClass || declaration is FirTypeAlias) {
declaration.transform<FirDeclaration, Nothing?>(this, null)
}
return
}
when (val nextElement = designationIterator.next()) {
is FirFile -> {
withFileAndScopes(nextElement) {
moveNextDeclaration(designationIterator)
}
}
is FirRegularClass -> {
moveNextDeclaration(designationIterator)
}
else -> {
error("Unexpected declaration in designation: ${nextElement::class.qualifiedName}")
}
}
}
override fun transformDeclaration() {
val designationIterator = designation.toSequenceWithFile(includeTarget = false).iterator()
moveNextDeclaration(designationIterator)
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(
target,
FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS,
updateForLocalDeclarations = false,
)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
// todo add proper check that COMPILER_REQUIRED_ANNOTATIONS are resolved
// checkNestedDeclarationsAreResolved(declaration)
}
}
@@ -1,65 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.LLFirEnsureBasedTransformerForReturnTypeCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
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.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
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.createReturnTypeCalculatorForIDE
/**
* Transform designation into BODY_RESOLVE declaration. Affects only for target declaration and it's children
*/
internal class LLFirDesignatedBodyResolveTransformer(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?
) : LLFirLazyTransformer, FirBodyResolveTransformer(
session,
phase = FirResolvePhase.BODY_RESOLVE,
implicitTypeOnly = false,
scopeSession = scopeSession,
returnTypeCalculator = createReturnTypeCalculatorForIDE(
scopeSession,
ImplicitBodyResolveComputationSession(),
::LLFirEnsureBasedTransformerForReturnTypeCalculator
),
firTowerDataContextCollector = towerDataContextCollector
) {
private val ideDeclarationTransformer = LLFirDeclarationTransformer(designation)
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration =
ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) {
super.transformDeclarationContent(declaration, data)
}
override fun transformDeclaration() {
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
ideDeclarationTransformer.ensureDesignationPassed()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, FirResolvePhase.BODY_RESOLVE, updateForLocalDeclarations = true)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.BODY_RESOLVE)
checkNestedDeclarationsAreResolved(target)
}
}
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirAbstractContractResolveTransformerDispatcher
/**
* Transform designation into CONTRACTS declaration. Affects only for target declaration and it's children
*/
internal class LLFirDesignatedContractsResolveTransformer(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirLazyTransformer, FirAbstractContractResolveTransformerDispatcher(session, scopeSession) {
private val ideDeclarationTransformer = LLFirDeclarationTransformer(designation)
override val contractDeclarationsTransformer: FirDeclarationsContractResolveTransformer
get() = object : FirDeclarationsContractResolveTransformer() {
override fun transformDeclarationContent(firClass: FirClass, data: ResolutionMode) {
ideDeclarationTransformer.transformDeclarationContent(this, firClass, data) {
super.transformDeclarationContent(firClass, data)
firClass
}
}
}
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration =
ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) {
super.transformDeclarationContent(declaration, data)
}
override fun transformDeclaration() {
FirLazyBodiesCalculator.calculateLazyBodiesInside(designation)
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
ideDeclarationTransformer.ensureDesignationPassed()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, FirResolvePhase.CONTRACTS, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.CONTRACTS)
if (target is FirContractDescriptionOwner) {
// TODO checkContractDescriptionIsResolved(declaration)
}
checkNestedDeclarationsAreResolved(target)
}
}
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.mpp.FirExpectActualMatcherTransformer
internal class LLFirDesignatedExpectActualMatcherTransformer(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirLazyTransformer, FirExpectActualMatcherTransformer(session, scopeSession) {
private val declarationTransformer = LLFirDeclarationTransformer(designation)
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): FirStatement {
return declarationTransformer.transformDeclarationContent(this, regularClass, data) {
super.transformRegularClass(regularClass, data) as FirDeclaration
} as FirStatement
}
override fun transformFile(file: FirFile, data: Nothing?): FirFile {
return declarationTransformer.transformDeclarationContent(this, file, data) {
super.transformFile(file, data)
} as FirFile
}
override fun transformDeclaration() {
FirLazyBodiesCalculator.calculateLazyBodiesInside(designation)
designation.firFile.transform<FirFile, Nothing?>(this, null)
declarationTransformer.ensureDesignationPassed()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(
target,
FirResolvePhase.EXPECT_ACTUAL_MATCHING,
updateForLocalDeclarations = false,
)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.EXPECT_ACTUAL_MATCHING)
// TODO check if expect-actual matching is present
checkNestedDeclarationsAreResolved(target)
}
}
@@ -1,34 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirCompanionGenerationTransformer
import org.jetbrains.kotlin.fir.declarations.resolvePhase
internal class LLFirDesignatedGeneratedCompanionObjectResolveTransformer(
val designation: FirDesignationWithFile,
session: FirSession
) : LLFirLazyTransformer {
private val transformer: FirCompanionGenerationTransformer = FirCompanionGenerationTransformer(session)
override fun transformDeclaration() {
designation.target.transform<FirDeclaration, Nothing?>(transformer, null)
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, FirResolvePhase.COMPANION_GENERATION, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
check(target.resolvePhase >= FirResolvePhase.COMPANION_GENERATION)
}
}
@@ -1,75 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.LLFirDesignatedImpliciteTypesBodyResolveTransformerForReturnTypeCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReturnTypeRefIsResolved
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
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.resolve.ResolutionMode
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.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.ImplicitBodyResolveComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.createReturnTypeCalculatorForIDE
/**
* Transform designation into IMPLICIT_TYPES_BODY_RESOLVE declaration. Affects only for target declaration, it's children and dependents
*/
internal class LLFirDesignatedImplicitTypesTransformer(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
implicitBodyResolveComputationSession: ImplicitBodyResolveComputationSession = ImplicitBodyResolveComputationSession(),
) : LLFirLazyTransformer, FirImplicitAwareBodyResolveTransformer(
session,
implicitBodyResolveComputationSession = implicitBodyResolveComputationSession,
phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE,
implicitTypeOnly = true,
scopeSession = scopeSession,
firTowerDataContextCollector = towerDataContextCollector,
returnTypeCalculator = createReturnTypeCalculatorForIDE(
scopeSession,
implicitBodyResolveComputationSession,
::LLFirDesignatedImpliciteTypesBodyResolveTransformerForReturnTypeCalculator
)
) {
private val ideDeclarationTransformer = LLFirDeclarationTransformer(designation)
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration =
ideDeclarationTransformer.transformDeclarationContent(this, declaration, data) {
super.transformDeclarationContent(declaration, data)
}
override fun transformDeclaration() {
designation.firFile.transform<FirFile, ResolutionMode>(this, ResolutionMode.ContextIndependent)
ideDeclarationTransformer.ensureDesignationPassed()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(
target,
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE,
updateForLocalDeclarations = false, /* here should be true if we resolved the body*/
)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE)
if (target is FirCallableDeclaration) {
checkReturnTypeRefIsResolved(target)
}
checkNestedDeclarationsAreResolved(target)
}
}
@@ -1,97 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDeclarationStatusIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.StatusComputationSession
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.visitors.transformSingle
/**
* Transform designation into STATUS phase. Affects only for designation, members of designation classes, target declaration, it's children and dependents
*/
internal class LLFirDesignatedStatusResolveTransformer(
private val designation: FirDesignationWithFile,
private val session: FirSession,
private val scopeSession: ScopeSession,
) : LLFirLazyTransformer {
private inner class FirDesignatedStatusResolveTransformerForIDE(
private val designationIterator: Iterator<FirRegularClass>,
) : FirStatusResolveTransformer(session, scopeSession, StatusComputationSession()) {
private var isInsideTargetDeclaration = false
override fun transformClass(klass: FirClass, data: FirResolvedDeclarationStatus?): FirStatement {
return storeClass(klass) {
resolveClassTypeParameters(klass)
if (isInsideTargetDeclaration) {
transformDeclarationContent(klass, data)
} else {
resolveCallableMembers(klass, data)
moveNextDeclaration()
}
klass
} as FirStatement
}
private fun resolveClassTypeParameters(klass: FirClass) {
klass.typeParameters.forEach { it.transformSingle(this, data = null) }
}
private fun resolveCallableMembers(
klass: FirClass,
data: FirResolvedDeclarationStatus?
) {
for (member in klass.declarations) {
if (member is FirClassLikeDeclaration) continue
// we need the types to be resolved here to compute visibility
// implicit types will not be handled (see bug in the compiler KT-55446)
member.lazyResolveToPhase(FirResolvePhase.TYPES)
member.transformSingle(this, data)
}
}
fun moveNextDeclaration() {
if (!designationIterator.hasNext()) {
isInsideTargetDeclaration = true
designation.target.transform<FirDeclaration, _>(this, data = null)
return
}
val nextClass = designationIterator.next()
transformClassContent(nextClass, data = null)
}
}
override fun transformDeclaration() {
val designationIterator = designation.path.iterator()
val transformer = FirDesignatedStatusResolveTransformerForIDE(designationIterator)
transformer.moveNextDeclaration()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, FirResolvePhase.STATUS, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
if (target !is FirAnonymousInitializer) {
target.checkPhase(FirResolvePhase.STATUS)
}
if (target is FirMemberDeclaration) {
checkDeclarationStatusIsResolved(target)
}
checkNestedDeclarationsAreResolved(target)
}
}
@@ -1,82 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReceiverTypeRefIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReturnTypeRefIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkTypeRefIsResolved
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
/**
* Transform designation into TYPES phase. Affects only for designation, target declaration and it's children
*/
internal class LLFirDesignatedTypeResolverTransformer(
private val designation: FirDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirLazyTransformer, FirTypeResolveTransformer(session, scopeSession) {
private val declarationTransformer = LLFirDeclarationTransformer(designation)
override fun <E : FirElement> transformElement(element: E, data: Any?): E {
return if (element is FirDeclaration && (element is FirRegularClass || element is FirFile)) {
@Suppress("UNCHECKED_CAST")
declarationTransformer.transformDeclarationContent(this, element, data) {
super.transformElement(element, data)
} as E
} else {
super.transformElement(element, data)
}
}
override fun transformDeclaration() {
designation.firFile.transform<FirFile, Any?>(this, null)
declarationTransformer.ensureDesignationPassed()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, FirResolvePhase.TYPES, updateForLocalDeclarations = false)
}
override fun transformTypeRef(typeRef: FirTypeRef, data: Any?): FirResolvedTypeRef {
FirLazyBodiesCalculator.calculateAnnotations(typeRef, session)
return super.transformTypeRef(typeRef, data)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.TYPES)
when (target) {
is FirCallableDeclaration -> {
checkReturnTypeRefIsResolved(target, acceptImplicitTypeRef = true)
checkReceiverTypeRefIsResolved(target)
}
is FirTypeParameter -> {
for (bound in target.bounds) {
checkTypeRefIsResolved(bound, "type parameter bound", target)
}
}
else -> {}
}
checkNestedDeclarationsAreResolved(target)
(target as? FirDeclaration)?.let {
checkTypeParametersAreResolved(it)
checkClassMembersAreResolved(it)
}
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.mpp.FirExpectActualMatcherTransformer
internal object LLFirExpectActualMatcherLazyResolver : LLFirLazyResolver(FirResolvePhase.EXPECT_ACTUAL_MATCHING) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirExpectActualMatchingTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
// TODO check if expect-actual matching is present
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirExpectActualMatchingTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.EXPECT_ACTUAL_MATCHING) {
private val transformer = FirExpectActualMatcherTransformer(session, scopeSession)
override fun withFile(firFile: FirFile, action: () -> Unit) {
action()
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
action()
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
if (target !is FirMemberDeclaration) return
if (!target.canHaveExpectCounterPart()) return
transformer.transformMemberDeclaration(target)
}
private fun FirMemberDeclaration.canHaveExpectCounterPart(): Boolean = when (this) {
is FirEnumEntry -> true
is FirProperty -> true
is FirConstructor -> true
is FirSimpleFunction -> true
is FirRegularClass -> true
is FirTypeAlias -> true
else -> false
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirCompanionGenerationTransformer
internal object LLFirGeneratedCompanionObjectLazyResolver : LLFirLazyResolver(FirResolvePhase.COMPANION_GENERATION) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirCompanionGenerationTargetResolver(target, lockProvider, session)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
}
}
private class LLFirCompanionGenerationTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.COMPANION_GENERATION) {
private val transformer: FirCompanionGenerationTransformer = FirCompanionGenerationTransformer(session)
override fun withFile(firFile: FirFile, action: () -> Unit) {
action()
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
action()
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
if (target !is FirRegularClass) return
transformer.generateAndUpdateCompanion(target)
}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReturnTypeRefIsResolved
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
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.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.visitors.transformSingle
internal object LLFirImplicitTypesLazyResolver : LLFirLazyResolver(FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirImplicitBodyTargetResolver(target, lockProvider, session, scopeSession, towerDataContextCollector)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(
target,
resolverPhase,
updateForLocalDeclarations = false/* here should be true if we resolved the body*/
)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
if (target is FirCallableDeclaration) {
checkReturnTypeRefIsResolved(target)
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirImplicitBodyTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) : LLFirAbstractBodyTargetResolver(
target,
lockProvider,
scopeSession,
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE,
) {
override val transformer = object : FirImplicitAwareBodyResolveTransformer(
session,
implicitBodyResolveComputationSession = implicitBodyResolveComputationSession,
phase = resolverPhase,
implicitTypeOnly = true,
scopeSession = scopeSession,
firTowerDataContextCollector = towerDataContextCollector,
returnTypeCalculator = createReturnTypeCalculator(),
) {
override val preserveCFGForClasses: Boolean get() = false
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
when (target) {
is FirRegularClass, is FirDanglingModifierList, is FirAnonymousInitializer, is FirFileAnnotationsContainer, is FirTypeAlias, is FirScript -> {
// no implicit bodies here
}
is FirCallableDeclaration -> {
calculateLazyBodies(target)
target.transformSingle(transformer, ResolutionMode.ContextIndependent)
}
else -> throwUnexpectedFirElementError(target)
}
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import java.util.*
internal object LLFirLazyPhaseResolverByPhase {
private val byPhase = EnumMap<FirResolvePhase, LLFirLazyResolver>(FirResolvePhase::class.java).apply {
this[FirResolvePhase.COMPANION_GENERATION] = LLFirGeneratedCompanionObjectLazyResolver
this[FirResolvePhase.SUPER_TYPES] = LLFirSupertypeLazyResolver
this[FirResolvePhase.TYPES] = LLFirTypeLazyResolver
this[FirResolvePhase.STATUS] = LLFirStatusLazyResolver
this[FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS] = LLFirCompilerAnnotationsLazyResolver
this[FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS] = LLFirAnnotationArgumentsLazyResolver
this[FirResolvePhase.CONTRACTS] = LLFirContractsLazyResolver
this[FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE] = LLFirImplicitTypesLazyResolver
this[FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING] = LLFirAnnotationArgumentMappingLazyResolver
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)
}
@@ -0,0 +1,75 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
internal abstract class LLFirLazyResolver(
val resolverPhase: FirResolvePhase,
) {
abstract fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
)
abstract fun checkIsResolved(target: FirElementWithResolveState)
abstract fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState)
fun checkIsResolved(designation: LLFirResolveTarget) {
designation.forEachTarget(::checkIsResolved)
}
protected fun checkNestedDeclarationsAreResolved(target: FirElementWithResolveState) {
if (target !is FirDeclaration) return
checkFunctionParametersAreResolved(target)
checkPropertyAccessorsAreResolved(target)
checkPropertyBackingFieldIsResolved(target)
checkTypeParametersAreResolved(target)
}
private fun checkPropertyAccessorsAreResolved(declaration: FirDeclaration) {
if (declaration is FirProperty) {
declaration.getter?.let { checkIsResolved(it) }
declaration.setter?.let { checkIsResolved(it) }
}
}
private fun checkPropertyBackingFieldIsResolved(declaration: FirDeclaration) {
if (declaration is FirProperty) {
declaration.backingField?.let { checkIsResolved(it) }
}
}
private fun checkFunctionParametersAreResolved(declaration: FirDeclaration) {
if (declaration is FirFunction) {
for (parameter in declaration.valueParameters) {
checkIsResolved(parameter)
}
}
}
private fun checkTypeParametersAreResolved(declaration: FirDeclaration) {
if (declaration is FirTypeParameterRefsOwner) {
for (parameter in declaration.typeParameters) {
if (parameter is FirTypeParameter) {
checkIsResolved(parameter)
}
}
}
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
internal object LLFirLazyResolverRunner {
fun runLazyResolverByPhase(
phase: FirResolvePhase,
target: LLFirResolveTarget,
scopeSession: ScopeSession,
lockProvider: LLFirLockProvider,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val lazyResolver = LLFirLazyPhaseResolverByPhase.getByPhase(phase)
val firFile = target.firFile
val session = firFile.moduleData.session
// TODO: global lock should be dropped in the context of KT-56550
lockProvider.withGlobalLock(firFile) {
lockProvider.withGlobalPhaseLock(phase) {
lazyResolver.resolve(target, lockProvider, session, scopeSession, towerDataContextCollector)
}
}
lazyResolver.checkIsResolved(target)
}
}
@@ -1,71 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.*
internal interface LLFirLazyTransformer {
fun transformDeclaration()
fun checkIsResolved(target: FirElementWithResolveState)
fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState)
fun checkNestedDeclarationsAreResolved(target: FirElementWithResolveState) {
if (target !is FirDeclaration) return
checkFunctionParametersAreResolved(target)
checkPropertyAccessorsAreResolved(target)
checkClassMembersAreResolved(target)
}
fun checkClassMembersAreResolved(declaration: FirDeclaration) {
if (!needCheckingIfClassMembersAreResolved) return
if (declaration is FirClass) {
for (member in declaration.declarations) {
checkClassMembersAreResolved(member)
}
}
}
fun checkPropertyAccessorsAreResolved(declaration: FirDeclaration) {
if (declaration is FirProperty) {
declaration.getter?.let { checkIsResolved(it) }
declaration.setter?.let { checkIsResolved(it) }
}
}
fun checkFunctionParametersAreResolved(declaration: FirDeclaration) {
if (declaration is FirFunction) {
for (parameter in declaration.valueParameters) {
checkIsResolved(parameter)
}
}
}
fun checkTypeParametersAreResolved(declaration: FirDeclaration) {
if (declaration is FirTypeParameterRefsOwner) {
for (parameter in declaration.typeParameters) {
if (parameter is FirTypeParameter) {
checkIsResolved(parameter)
}
}
}
}
companion object {
internal var needCheckingIfClassMembersAreResolved: Boolean = false
@TestOnly set
val DUMMY = object : LLFirLazyTransformer {
override fun transformDeclaration() {}
override fun checkIsResolved(target: FirElementWithResolveState) {}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {}
}
}
}
@@ -1,38 +0,0 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.asResolveState
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
internal object LLFirLazyTransformerExecutor {
fun execute(
phase: FirResolvePhase,
designation: FirDesignationWithFile,
scopeSession: ScopeSession,
lockProvider: LLFirLockProvider,
towerDataContextCollector: FirTowerDataContextCollector?
) {
val lazyTransformer = LazyTransformerFactory.createLazyTransformer(
phase,
designation,
scopeSession,
lockProvider,
towerDataContextCollector,
)
lockProvider.withLock(designation.firFile) {
lazyTransformer.transformDeclaration()
lazyTransformer.updatePhaseForDeclarationInternals(designation.target)
designation.target.replaceResolveState(phase.asResolveState())
lazyTransformer.checkIsResolved(designation.target)
}
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
internal object LLFirSealedClassInheritorsLazyResolver : LLFirLazyResolver(FirResolvePhase.SEALED_CLASS_INHERITORS) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirSealedClassInheritorsDesignatedResolver(target, lockProvider)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirSealedClassInheritorsDesignatedResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.SEALED_CLASS_INHERITORS) {
override fun withFile(firFile: FirFile, action: () -> Unit) {
action()
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
action()
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
// just update the phase
}
}
@@ -0,0 +1,159 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.asResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkDeclarationStatusIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.StatusComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhaseWithCallableMembers
import org.jetbrains.kotlin.fir.visitors.transformSingle
internal object LLFirStatusLazyResolver : LLFirLazyResolver(FirResolvePhase.STATUS) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirStatusTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
if (target !is FirAnonymousInitializer) {
target.checkPhase(resolverPhase)
}
if (target is FirMemberDeclaration) {
checkDeclarationStatusIsResolved(target)
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirStatusTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
private val statusComputationSession: StatusComputationSession = StatusComputationSession()
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.STATUS, isJumpingPhase = true) {
private val transformer = Transformer(session, scopeSession)
override fun withFile(firFile: FirFile, action: () -> Unit) {
action()
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
firClass.lazyResolveToPhase(resolverPhase.previous)
resolveClass(firClass, action)
}
private fun resolveClassTypeParameters(klass: FirClass) {
klass.typeParameters.forEach { it.transformSingle(transformer, data = null) }
}
private fun resolveCallableMembers(klass: FirClass) {
// we need the types to be resolved here to compute visibility
// implicit types will not be handled (see bug in the compiler KT-55446)
klass.lazyResolveToPhaseWithCallableMembers(resolverPhase.previous)
for (member in klass.declarations) {
if (member !is FirCallableDeclaration) continue
performResolve(member)
}
}
override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean {
return when (target) {
is FirRegularClass -> {
resolveClass(target, action = {})
true
}
else -> {
false
}
}
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
when (target) {
is FirRegularClass -> {
error("should be resolved in doResolveWithoutLock")
}
else -> {
target.transformSingle(transformer, data = null)
}
}
}
private fun resolveClass(firClass: FirRegularClass, action: () -> Unit) {
transformer.statusComputationSession.startComputing(firClass)
transformer.forceResolveStatusesOfSupertypes(firClass)
performCustomResolveUnderLock(firClass) {
transformer.transformClassStatus(firClass)
transformer.transformValueClassRepresentation(firClass)
transformer.storeClass(firClass) {
resolveClassTypeParameters(firClass)
firClass
}
}
transformer.storeClass(firClass) {
resolveCallableMembers(firClass)
firClass
}
transformer.storeClass(firClass) {
action()
firClass
}
transformer.statusComputationSession.endComputing(firClass)
}
private inner class Transformer(
session: FirSession,
scopeSession: ScopeSession,
) : FirStatusResolveTransformer(session, scopeSession, statusComputationSession) {
override fun FirDeclaration.needResolveMembers(): Boolean = false
override fun FirDeclaration.needResolveNestedClassifiers(): Boolean = false
override fun transformClass(klass: FirClass, data: FirResolvedDeclarationStatus?): FirStatement {
return klass
}
override fun resolveClassForSuperType(regularClass: FirRegularClass): Boolean {
if (regularClass.resolvePhase >= resolverPhase) return true
regularClass.lazyResolveToPhase(resolverPhase.previous)
val designation = regularClass.collectDesignationWithFile().asResolveTarget()
val resolver = LLFirStatusTargetResolver(designation, lockProvider, session, scopeSession, statusComputationSession)
resolver.resolveDesignation()
return true
}
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableSession
@@ -20,33 +21,102 @@ import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.fir.resolve.transformers.FirApplySupertypesTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverVisitor
import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationStatus
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.toSymbol
import org.jetbrains.kotlin.fir.types.type
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
/**
* Transform designation into SUPER_TYPES phase. Affects only the designation, target declaration, its children, and dependents.
*/
internal class LLFirDesignatedSupertypeResolverTransformer(
private val designation: FirDesignationWithFile,
internal object LLFirSupertypeLazyResolver : LLFirLazyResolver(FirResolvePhase.SUPER_TYPES) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirSuperTypeTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
when (target) {
is FirClass -> {
for (superTypeRef in target.superTypeRefs) {
checkTypeRefIsResolved(superTypeRef, "class super type", target)
}
}
is FirTypeAlias -> {
checkTypeRefIsResolved(target.expandedTypeRef, typeRefName = "type alias expanded type", target)
}
else -> {}
}
}
}
internal class LLFirSuperTypeTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
private val session: FirSession,
private val scopeSession: ScopeSession,
private val lockProvider: LLFirLockProvider
) : LLFirLazyTransformer {
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.SUPER_TYPES) {
private val supertypeComputationSession = SupertypeComputationSession()
override fun withFile(firFile: FirFile, action: () -> Unit) {
action()
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
doResolveWithoutLock(firClass)
action()
}
override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean {
when (target) {
is FirRegularClass, is FirTypeAlias -> {
val designationToResolve = FirDesignationWithFile(nestedClassesStack, target, resolveTarget.firFile)
val collected = collect(designationToResolve)
supertypeComputationSession.breakLoops(session)
apply(collected)
}
else -> {
performCustomResolveUnderLock(target) {
// just update the phase
}
}
}
return true
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
error("Should be resolved without lock in ${::doResolveWithoutLock.name}")
}
private inner class DesignatedFirSupertypeResolverVisitor(classDesignation: FirDesignation) :
FirSupertypeResolverVisitor(
session = session,
supertypeComputationSession = supertypeComputationSession,
scopeSession = scopeSession,
scopeForLocalClass = null,
localClassesNavigationInfo = null
localClassesNavigationInfo = null,
) {
val declarationTransformer = LLFirDeclarationTransformer(classDesignation)
@@ -87,6 +157,7 @@ internal class LLFirDesignatedSupertypeResolverTransformer(
supertypeComputationStatus.supertypeRefs.forEach { crawlSupertype(it.type) }
}
}
return visited.values
}
@@ -94,9 +165,7 @@ internal class LLFirDesignatedSupertypeResolverTransformer(
checkCanceled()
val resolver = DesignatedFirSupertypeResolverVisitor(designation)
designation.firFile.lazyResolveToPhase(FirResolvePhase.IMPORTS)
lockProvider.withLock(designation.firFile) {
designation.firFile.accept(resolver, null)
}
designation.firFile.accept(resolver, null)
resolver.declarationTransformer.ensureDesignationPassed()
visited[designation.target] = designation
}
@@ -135,55 +204,84 @@ internal class LLFirDesignatedSupertypeResolverTransformer(
for (designation in designations) {
checkCanceled()
val applier = DesignatedFirApplySupertypesTransformer(designation)
designation.firFile.transform<FirElement, Void?>(applier, null)
applier.declarationTransformer.ensureDesignationPassed()
(designation.target as FirDeclaration).lazyResolveToPhase(resolverPhase.previous)
performCustomResolveUnderLock(designation.target) {
designation.firFile.transform<FirElement, Void?>(applier, null)
applier.declarationTransformer.ensureDesignationPassed()
}
}
}
val filesToDesignations = designations.groupBy { it.firFile }
for (designationsPerFile in filesToDesignations) {
checkCanceled()
lockProvider.withLock(designationsPerFile.key) {
val session = designationsPerFile.key.llFirResolvableSession
?: error("When FirFile exists for the declaration, the session should be resolvevablable")
withInvalidationOnException(session) {
applyToFileSymbols(designationsPerFile.value)
}
val session = designationsPerFile.key.llFirResolvableSession
?: error("When FirFile exists for the declaration, the session should be resolvable")
withInvalidationOnException(session) {
applyToFileSymbols(designationsPerFile.value)
}
}
}
override fun transformDeclaration() {
val targetDesignation = if (designation.target !is FirClassLikeDeclaration) {
val resolvableTarget = designation.path.lastOrNull() ?: return
val targetPath = designation.path.dropLast(1)
FirDesignationWithFile(targetPath, resolvableTarget, designation.firFile)
} else designation
val collected = collect(targetDesignation)
supertypeComputationSession.breakLoops(session)
apply(collected)
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, FirResolvePhase.SUPER_TYPES, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(FirResolvePhase.SUPER_TYPES)
when (target) {
is FirClass -> {
for (superTypeRef in target.superTypeRefs) {
checkTypeRefIsResolved(superTypeRef, "class super type", target)
}
}
is FirTypeAlias -> {
checkTypeRefIsResolved(target.expandedTypeRef, typeRefName = "type alias expanded type", target)
}
else -> {}
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirDeclarationTransformer(private val designation: FirDesignation) {
private val designationWithoutTargetIterator = designation.toSequence(includeTarget = false).iterator()
private var isInsideTargetDeclaration: Boolean = false
private var designationPassed: Boolean = false
inline fun <D> visitDeclarationContent(
visitor: FirVisitor<Unit, D>,
declaration: FirDeclaration,
data: D,
default: () -> FirDeclaration
): FirDeclaration = processDeclarationContent(declaration, default) {
it.accept(visitor, data)
}
inline fun <D> transformDeclarationContent(
transformer: FirDefaultTransformer<D>,
declaration: FirDeclaration,
data: D,
default: () -> FirDeclaration
): FirDeclaration = processDeclarationContent(declaration, default) { toTransform ->
toTransform.transform<FirElement, D>(transformer, data).also { transformed ->
check(transformed === toTransform) {
"become $transformed `${transformed.render()}`, was ${toTransform}: `${toTransform.render()}`"
}
}
}
private inline fun processDeclarationContent(
declaration: FirDeclaration,
default: () -> FirDeclaration,
applyToDesignated: (FirElementWithResolveState) -> Unit,
): FirDeclaration {
//It means that we are inside the target declaration
if (isInsideTargetDeclaration) {
return default()
}
//It means that we already transform target declaration and now can skip all others
if (designationPassed) {
return declaration
}
if (designationWithoutTargetIterator.hasNext()) {
applyToDesignated(designationWithoutTargetIterator.next())
} else {
try {
isInsideTargetDeclaration = true
designationPassed = true
applyToDesignated(designation.target)
} finally {
isInsideTargetDeclaration = false
}
}
return declaration
}
fun ensureDesignationPassed() {
check(designationPassed) { "Designation not passed for declaration ${designation.target::class.simpleName}" }
}
}
@@ -0,0 +1,128 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
internal abstract class LLFirTargetResolver(
protected val resolveTarget: LLFirResolveTarget,
protected val lockProvider: LLFirLockProvider,
protected val resolverPhase: FirResolvePhase,
private val isJumpingPhase: Boolean = false,
) {
private val _nestedClassesStack = mutableListOf<FirRegularClass>()
val nestedClassesStack: List<FirRegularClass> get() = _nestedClassesStack.toList()
protected abstract fun withFile(firFile: FirFile, action: () -> Unit)
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
protected abstract fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit)
@Suppress("DEPRECATION_ERROR")
protected fun withRegularClass(firClass: FirRegularClass, action: () -> Unit) {
_nestedClassesStack += firClass
withRegularClassImpl(firClass, action)
check(_nestedClassesStack.removeLast() === firClass)
}
protected open fun checkResolveConsistency() {}
protected open fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean = false
protected abstract fun doLazyResolveUnderLock(target: FirElementWithResolveState)
fun resolveDesignation() {
checkResolveConsistency()
withFile(resolveTarget.firFile) {
goToTargets(resolveTarget.path.iterator())
}
}
private fun goToTargets(iterator: Iterator<FirRegularClass>) {
if (iterator.hasNext()) {
val firClass = iterator.next()
withRegularClass(firClass) {
goToTargets(iterator)
}
} else {
when (resolveTarget) {
is LLFirClassWithSpecificMembersResolveTarget -> {
performResolve(resolveTarget.target)
withRegularClass(resolveTarget.target) {
resolveTarget.forEachMember(::performResolve)
}
}
is LLFirClassWithAllMembersResolveTarget -> {
performResolve(resolveTarget.target)
withRegularClass(resolveTarget.target) {
resolveTarget.forEachMember(::performResolve)
}
}
is LLFirClassWithAllCallablesResolveTarget -> {
performResolve(resolveTarget.target)
withRegularClass(resolveTarget.target) {
resolveTarget.forEachCallable(::performResolve)
}
}
is LLFirSingleResolveTarget -> {
performResolve(resolveTarget.target)
}
is LLFirWholeFileResolveTarget -> {
resolveTarget.forEachTopLevelDeclaration(::resolveTargetWithNestedDeclarations)
}
}
}
}
private fun resolveTargetWithNestedDeclarations(target: FirElementWithResolveState) {
performResolve(target)
if (target is FirRegularClass) {
withRegularClass(target) {
for (member in target.declarations) {
resolveTargetWithNestedDeclarations(member)
}
}
}
}
protected fun performResolve(target: FirElementWithResolveState) {
if (doResolveWithoutLock(target)) return
performCustomResolveUnderLock(target) {
doLazyResolveUnderLock(target)
}
}
protected inline fun performCustomResolveUnderLock(target: FirElementWithResolveState, crossinline action: () -> Unit) {
checkThatResolvedAtLeastToPreviousPhase(target)
withPossiblyJumpingLock(target) {
action()
LLFirLazyPhaseResolverByPhase.getByPhase(resolverPhase).updatePhaseForDeclarationInternals(target)
}
}
private inline fun withPossiblyJumpingLock(target: FirElementWithResolveState, action: () -> Unit) {
if (isJumpingPhase) {
lockProvider.withJumpingLock(target, resolverPhase, action)
} else {
lockProvider.withLock(target, resolverPhase, action)
}
}
private fun checkThatResolvedAtLeastToPreviousPhase(target: FirElementWithResolveState) {
when (val previousPhase = resolverPhase.previous) {
FirResolvePhase.IMPORTS -> {}
else -> {
target.checkPhase(previousPhase)
}
}
}
}
@@ -0,0 +1,152 @@
/*
* Copyright 2010-2023 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReceiverTypeRefIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkReturnTypeRefIsResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkTypeRefIsResolved
import org.jetbrains.kotlin.fir.FirElementWithResolveState
import org.jetbrains.kotlin.fir.FirFileAnnotationsContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.transformSingle
internal object LLFirTypeLazyResolver : LLFirLazyResolver(FirResolvePhase.TYPES) {
override fun resolve(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?,
) {
val resolver = LLFirTypeTargetResolver(target, lockProvider, session, scopeSession)
resolver.resolveDesignation()
}
override fun updatePhaseForDeclarationInternals(target: FirElementWithResolveState) {
LLFirPhaseUpdater.updateDeclarationInternalsPhase(target, resolverPhase, updateForLocalDeclarations = false)
}
override fun checkIsResolved(target: FirElementWithResolveState) {
target.checkPhase(resolverPhase)
if (target is FirConstructor) {
target.delegatedConstructor?.let { delegated ->
checkTypeRefIsResolved(delegated.constructedTypeRef, "constructor type reference", target, acceptImplicitTypeRef = true)
}
}
when (target) {
is FirCallableDeclaration -> {
checkReturnTypeRefIsResolved(target, acceptImplicitTypeRef = true)
checkReceiverTypeRefIsResolved(target)
}
is FirTypeParameter -> {
for (bound in target.bounds) {
checkTypeRefIsResolved(bound, "type parameter bound", target)
}
}
else -> {}
}
checkNestedDeclarationsAreResolved(target)
}
}
private class LLFirTypeTargetResolver(
target: LLFirResolveTarget,
lockProvider: LLFirLockProvider,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.TYPES) {
private val transformer = object : FirTypeResolveTransformer(session, scopeSession) {
override fun transformTypeRef(typeRef: FirTypeRef, data: Any?): FirResolvedTypeRef {
FirLazyBodiesCalculator.calculateAnnotations(typeRef, session)
return super.transformTypeRef(typeRef, data)
}
}
override fun withFile(firFile: FirFile, action: () -> Unit) {
transformer.withFileScope(firFile) {
action()
}
}
@Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR)
override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) {
firClass.lazyResolveToPhase(resolverPhase.previous)
transformer.withClassDeclarationCleanup(firClass) {
performCustomResolveUnderLock(firClass) {
resolveClassTypes(firClass)
}
transformer.withClassScopes(
firClass,
actionInsideStaticScope = {
resolveConstructors(firClass)
},
action = action,
)
}
}
private fun resolveConstructors(firClass: FirRegularClass): Unit = transformer.withScopeCleanup {
transformer.addTypeParametersScope(firClass)
for (member in firClass.declarations) {
if (member !is FirConstructor) continue
member.lazyResolveToPhase(resolverPhase.previous)
performCustomResolveUnderLock(member) {
// ConstructedTypeRef should be resolved only with type parameters, but not with nested classes and classes from supertypes
transformer.transformDelegatedConstructorCall(member)
transformer.withClassScopes(firClass) {
member.accept(transformer, null)
}
}
}
}
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
when (target) {
is FirDanglingModifierList, is FirFileAnnotationsContainer, is FirCallableDeclaration, is FirTypeAlias, is FirScript -> {
target.accept(transformer, null)
}
is FirRegularClass -> {
resolveClassTypes(target)
}
is FirAnonymousInitializer -> {}
else -> error("Unknown declaration ${target::class.java}")
}
}
private fun resolveClassTypes(firClass: FirRegularClass) {
transformer.transformClassTypeParameters(firClass, null)
transformer.withScopeCleanup {
firClass.transformAnnotations(transformer, null)
}
transformer.withClassScopes(firClass) {
for (contextReceiver in firClass.contextReceivers) {
contextReceiver.transformSingle(transformer, null)
}
}
}
}
@@ -1,83 +0,0 @@
/*
* Copyright 2010-2021 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
internal object LazyTransformerFactory {
fun createLazyTransformer(
phase: FirResolvePhase,
designation: FirDesignationWithFile,
scopeSession: ScopeSession,
lockProvider: LLFirLockProvider,
towerDataContextCollector: FirTowerDataContextCollector?
): LLFirLazyTransformer = when (phase) {
FirResolvePhase.COMPANION_GENERATION -> LLFirDesignatedGeneratedCompanionObjectResolveTransformer(
designation = designation,
session = designation.firFile.moduleData.session,
)
FirResolvePhase.SEALED_CLASS_INHERITORS -> LLFirLazyTransformer.DUMMY
FirResolvePhase.SUPER_TYPES -> LLFirDesignatedSupertypeResolverTransformer(
designation = designation,
session = designation.firFile.moduleData.session,
scopeSession = scopeSession,
lockProvider = lockProvider
)
FirResolvePhase.TYPES -> LLFirDesignatedTypeResolverTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession,
)
FirResolvePhase.STATUS -> LLFirDesignatedStatusResolveTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession,
)
FirResolvePhase.EXPECT_ACTUAL_MATCHING -> LLFirDesignatedExpectActualMatcherTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession
)
FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS -> LLFirDesignatedAnnotationsResolveTransformed(
designation,
designation.firFile.moduleData.session,
scopeSession,
)
FirResolvePhase.ARGUMENTS_OF_ANNOTATIONS -> LLFirDesignatedAnnotationArgumentsResolveTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession,
)
FirResolvePhase.CONTRACTS -> LLFirDesignatedContractsResolveTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession,
)
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> LLFirDesignatedImplicitTypesTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession,
towerDataContextCollector
)
FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING -> LLFirDesignatedAnnotationArgumentsMappingTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession,
)
FirResolvePhase.BODY_RESOLVE -> LLFirDesignatedBodyResolveTransformer(
designation,
designation.firFile.moduleData.session,
scopeSession,
towerDataContextCollector
)
FirResolvePhase.RAW_FIR -> error("Non-lazy phase $phase")
FirResolvePhase.IMPORTS -> error("Non-lazy phase $phase")
}
}
@@ -24,6 +24,7 @@ fun FirElementWithResolveState.getContainingFile(): FirFile? {
is FirValueParameter -> containingFunctionSymbol.fir.getContainingFile()
is FirCallableDeclaration -> provider.getFirCallableContainerFile(symbol)
is FirClassLikeDeclaration -> provider.getFirClassifierContainerFileIfAny(symbol)
is FirAnonymousInitializer -> containingClass().getContainingFile()
is FirDanglingModifierList -> {
val ktFile = psi?.containingFile as? KtFile
?: error("File for dangling modifier list cannot be null")
@@ -9,10 +9,13 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirEle
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.realPsi
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
@@ -95,7 +98,7 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider(
*/
declarations?.firstOrNull { it.psi == this || it.psi == original }
}
this is KtConstructor<*> -> {
this is KtConstructor<*> || this is KtClassInitializer -> {
val containingClass = containingClassOrObject
?: errorWithFirSpecificEntries("Container class should be not null for KtConstructor", psi = this)
val containerClassFir = containingClass.findFir(provider) as? FirRegularClass ?: return null
@@ -112,6 +115,16 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider(
return candidate?.takeIf { it.realPsi == this }
}
fun FirAnonymousInitializer.containingClass(): FirRegularClass {
val dispatchReceiverType = this.dispatchReceiverType as? ConeLookupTagBasedType
?: error("dispatchReceiverType for FirAnonymousInitializer modifier cannot be null")
val dispatchReceiverSymbol = dispatchReceiverType.lookupTag.toSymbol(llFirSession)
?: error("symbol for FirAnonymousInitializer cannot be null")
return dispatchReceiverSymbol.fir as FirRegularClass
}
val ORIGINAL_DECLARATION_KEY = com.intellij.openapi.util.Key<KtDeclaration>("ORIGINAL_DECLARATION_KEY")
var KtDeclaration.originalDeclaration by UserDataProperty(ORIGINAL_DECLARATION_KEY)
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
@@ -43,6 +45,27 @@ internal inline fun checkTypeRefIsResolved(
}
}
internal fun checkBodyIsResolved(function: FirFunction) {
val block = function.body ?: return
checkTypeRefIsResolved(block.typeRef, "block type", function) {
withFirEntry("block", block)
}
}
internal fun checkInitializerIsResolved(variable: FirVariable) {
val initializer = variable.initializer ?: return
checkTypeRefIsResolved(initializer.typeRef, "initializer type", variable) {
withFirEntry("initializer", initializer)
}
}
internal fun checkDefaultValueIsResolved(parameter: FirValueParameter) {
val defaultValue = parameter.defaultValue ?: return
checkTypeRefIsResolved(defaultValue.typeRef, "default value type", parameter) {
withFirEntry("defaultValue", defaultValue)
}
}
internal fun checkReturnTypeRefIsResolved(declaration: FirCallableDeclaration, acceptImplicitTypeRef: Boolean = false) {
checkTypeRefIsResolved(declaration.returnTypeRef, typeRefName = "return type", declaration, acceptImplicitTypeRef)
}
@@ -0,0 +1,7 @@
open class B(x: () -> Unit)
class A() : B(1, {
foo()
})
fun foo() {}
@@ -0,0 +1,7 @@
open class B(x: () -> Unit)
class A : B(1, {
foo()
})
fun foo() {}
@@ -0,0 +1,17 @@
open class A(x: () -> Unit)
class B : A {
constructor(i: Int) : super(
{
foo(i)
}
)
constructor(l: Long) : super(
{
foo(l)
}
)
}
fun foo(any: Any) {}
@@ -0,0 +1,11 @@
open class A(x: () -> Unit)
class B : A {
constructor(i: Int) : super(
{
foo(i)
}
)
}
fun foo(any: Any) {}
@@ -0,0 +1,10 @@
class A(
@setparam:Ann
@get:Ann
@set:Ann
@field:Ann
@property:Ann
var x: Int
)
annotation class Ann
@@ -0,0 +1,6 @@
@Target(AnnotationTarget.TYPE)
annotation class Anno
open class A
class B : @Anno A()
@@ -0,0 +1,6 @@
@Target(AnnotationTarget.TYPE)
annotation class Anno
interface A
class B : @Anno A
@@ -0,0 +1,7 @@
interface A<T>
typealias AS = A<String>
class C : AS {
constructor()
}
+2 -2
View File
@@ -1,6 +1,6 @@
class A {/* NonReanalyzableDeclarationStructureElement */
class A {/* NonReanalyzableClassDeclarationStructureElement */
fun x() {/* ReanalyzableFunctionStructureElement */
}
fun y(): Int = 10/* ReanalyzableFunctionStructureElement */
}
}
@@ -1,11 +1,11 @@
class X {/* NonReanalyzableDeclarationStructureElement */
class X {/* NonReanalyzableClassDeclarationStructureElement */
var x: Int/* ReanalyzablePropertyStructureElement */
get() = field
set(value) {
field = value
}
val y = 42/* NonReanalyzableDeclarationStructureElement */
val y = 42/* NonReanalyzableNonClassDeclarationStructureElement */
var z: Int = 15/* ReanalyzablePropertyStructureElement */
}
}
@@ -0,0 +1,9 @@
class A
(val a: Int)/* NonReanalyzableNonClassDeclarationStructureElement */
{/* NonReanalyzableClassDeclarationStructureElement */
constructor() : this(1) {/* NonReanalyzableNonClassDeclarationStructureElement */
}
}
@@ -1,11 +1,11 @@
class Foo {/* NonReanalyzableDeclarationStructureElement */
class Foo {/* NonReanalyzableClassDeclarationStructureElement */
@Suppress("") @MustBeDocumented
}
class Bar {/* NonReanalyzableDeclarationStructureElement */
class Bar {/* NonReanalyzableClassDeclarationStructureElement */
@Suppress("") @MustBeDocumented
}
class Outer {/* NonReanalyzableDeclarationStructureElement */
class Inner {/* NonReanalyzableDeclarationStructureElement */
class Outer {/* NonReanalyzableClassDeclarationStructureElement */
class Inner {/* NonReanalyzableClassDeclarationStructureElement */
@Suppress("") @MustBeDocumented
}
fun foo() {/* ReanalyzableFunctionStructureElement */
@@ -1,9 +1,9 @@
class A {/* NonReanalyzableDeclarationStructureElement */
class A {/* NonReanalyzableClassDeclarationStructureElement */
val a = run {
class X()
val y = 10
}/* NonReanalyzableDeclarationStructureElement */
}/* NonReanalyzableNonClassDeclarationStructureElement */
}
inline fun <R> run(block: () -> R): R {/* ReanalyzableFunctionStructureElement */
@@ -1,13 +1,13 @@
enum class A {/* NonReanalyzableDeclarationStructureElement */
X,/* NonReanalyzableDeclarationStructureElement */
Y,/* NonReanalyzableDeclarationStructureElement */
enum class A {/* NonReanalyzableClassDeclarationStructureElement */
X,/* NonReanalyzableNonClassDeclarationStructureElement */
Y,/* NonReanalyzableNonClassDeclarationStructureElement */
Z
;/* NonReanalyzableDeclarationStructureElement */
;/* NonReanalyzableNonClassDeclarationStructureElement */
fun foo(){/* ReanalyzableFunctionStructureElement */}
val x = 10/* NonReanalyzableDeclarationStructureElement */
val x = 10/* NonReanalyzableNonClassDeclarationStructureElement */
fun bar() = 10/* NonReanalyzableDeclarationStructureElement */
fun bar() = 10/* NonReanalyzableNonClassDeclarationStructureElement */
}
@@ -1,13 +1,13 @@
enum class A {/* NonReanalyzableDeclarationStructureElement */
X {/* NonReanalyzableDeclarationStructureElement */
enum class A {/* NonReanalyzableClassDeclarationStructureElement */
X {/* NonReanalyzableNonClassDeclarationStructureElement */
fun localInX() = 1
},
Y {/* NonReanalyzableDeclarationStructureElement */
Y {/* NonReanalyzableNonClassDeclarationStructureElement */
override fun foo() {}
},
Z,
;/* NonReanalyzableDeclarationStructureElement */
;/* NonReanalyzableNonClassDeclarationStructureElement */
open fun foo() {/* ReanalyzableFunctionStructureElement */}
}
@@ -1,6 +1,6 @@
class A {/* NonReanalyzableDeclarationStructureElement */
init {
class A {/* NonReanalyzableClassDeclarationStructureElement */
init {/* NonReanalyzableNonClassDeclarationStructureElement */
val x = 10
class B
}
}
}
@@ -2,8 +2,8 @@ fun a() {/* ReanalyzableFunctionStructureElement */
class X
}
class Y {/* NonReanalyzableDeclarationStructureElement */
class Y {/* NonReanalyzableClassDeclarationStructureElement */
fun b() {/* ReanalyzableFunctionStructureElement */
class Z
}
}
}
@@ -4,10 +4,10 @@ fun x() {/* ReanalyzableFunctionStructureElement */
}
}
class A {/* NonReanalyzableDeclarationStructureElement */
class A {/* NonReanalyzableClassDeclarationStructureElement */
fun z() {/* ReanalyzableFunctionStructureElement */
fun q() {
}
}
}
}
@@ -1,13 +1,13 @@
fun foo() {/* ReanalyzableFunctionStructureElement */
var x: Int
}
class A {/* NonReanalyzableDeclarationStructureElement */
class A {/* NonReanalyzableClassDeclarationStructureElement */
fun q() {/* ReanalyzableFunctionStructureElement */
val y = 42
}
}
class B {/* NonReanalyzableDeclarationStructureElement */
class C {/* NonReanalyzableDeclarationStructureElement */
class B {/* NonReanalyzableClassDeclarationStructureElement */
class C {/* NonReanalyzableClassDeclarationStructureElement */
fun u() {/* ReanalyzableFunctionStructureElement */
var z: Int = 15
}
@@ -1,3 +1,3 @@
class A {/* NonReanalyzableDeclarationStructureElement */
typealias X = Int/* NonReanalyzableDeclarationStructureElement */
}
class A {/* NonReanalyzableClassDeclarationStructureElement */
typealias X = Int/* NonReanalyzableNonClassDeclarationStructureElement */
}
@@ -1,16 +1,16 @@
class A {/* NonReanalyzableDeclarationStructureElement */
class B {/* NonReanalyzableDeclarationStructureElement */
class A {/* NonReanalyzableClassDeclarationStructureElement */
class B {/* NonReanalyzableClassDeclarationStructureElement */
fun x() {/* ReanalyzableFunctionStructureElement */
}
class C {/* NonReanalyzableDeclarationStructureElement */
class C {/* NonReanalyzableClassDeclarationStructureElement */
}
}
class E {/* NonReanalyzableDeclarationStructureElement */
class E {/* NonReanalyzableClassDeclarationStructureElement */
}
fun y(): Int = 10/* ReanalyzableFunctionStructureElement */
}
}
@@ -4,10 +4,10 @@ var x: Int = 10/* ReanalyzablePropertyStructureElement */
field = value
}
class X {/* NonReanalyzableDeclarationStructureElement */
class X {/* NonReanalyzableClassDeclarationStructureElement */
var y: Int = 10/* ReanalyzablePropertyStructureElement */
get() = field
set(value) {
field = value
}
}
}

Some files were not shown because too many files have changed in this diff Show More