[LL FIR] KtToFirMapping: encapsulate recorder

We need this to avoid wrong recorders in on-air resolve

^KT-61013
This commit is contained in:
Dmitrii Gridin
2023-08-09 14:26:55 +02:00
committed by Space Team
parent d19a23aae5
commit 4c8399ae8c
3 changed files with 48 additions and 55 deletions
@@ -214,7 +214,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
forcedResolvePhase = requiredResolvePhase(minimalCopiedDeclaration, elementToAnalyze), forcedResolvePhase = requiredResolvePhase(minimalCopiedDeclaration, elementToAnalyze),
) )
val mapping = KtToFirMapping(copiedFirDeclaration, FirElementsRecorder()) val mapping = KtToFirMapping(copiedFirDeclaration)
return LLFirResolveSessionDepended(originalFirResolveSession, collector, mapping) return LLFirResolveSessionDepended(originalFirResolveSession, collector, mapping)
} }
@@ -9,9 +9,6 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement import com.intellij.psi.PsiErrorElement
import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
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.diagnostics.ClassDiagnosticRetriever 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.FileDiagnosticRetriever
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics
@@ -23,7 +20,6 @@ import org.jetbrains.kotlin.fir.correspondingProperty
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirErrorConstructor import org.jetbrains.kotlin.fir.declarations.impl.FirErrorConstructor
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor 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.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCodeFragmentSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCodeFragmentSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
@@ -31,17 +27,29 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
internal sealed class FileStructureElement(val firFile: FirFile, protected val moduleComponents: LLFirModuleResolveComponents) { internal sealed class FileStructureElement(val firFile: FirFile, protected val moduleComponents: LLFirModuleResolveComponents) {
abstract val psi: KtAnnotated abstract val psi: KtAnnotated
abstract val mappings: KtToFirMapping abstract val mappings: KtToFirMapping
abstract val diagnostics: FileStructureElementDiagnostics abstract val diagnostics: FileStructureElementDiagnostics
companion object {
val recorder = FirElementsRecorder()
fun recorderFor(fir: FirElement): FirElementsRecorder = when (fir) {
is FirFile -> RootStructureElement.Recorder
is FirScript -> RootScriptStructureElement.Recorder
is FirRegularClass -> NonReanalyzableClassDeclarationStructureElement.Recorder(fir)
else -> NonReanalyzableNonClassDeclarationStructureElement.Recorder
}
}
} }
internal class KtToFirMapping(firElement: FirElement, recorder: FirElementsRecorder) { internal class KtToFirMapping(firElement: FirElement) {
private val mapping = FirElementsRecorder.recordElementsFrom(firElement, recorder) private val mapping = FirElementsRecorder.recordElementsFrom(
firElement = firElement,
recorder = FileStructureElement.recorderFor(firElement),
)
fun getElement(ktElement: KtElement): FirElement? { fun getElement(ktElement: KtElement): FirElement? {
return mapping[ktElement] return mapping[ktElement]
@@ -119,6 +127,8 @@ internal sealed class ReanalyzableStructureElement<KT : KtAnnotated, S : FirBase
abstract override val psi: KtAnnotated abstract override val psi: KtAnnotated
abstract val timestamp: Long abstract val timestamp: Long
override val mappings = KtToFirMapping(firSymbol.fir)
/** /**
* Recreate [mappings] and [diagnostics] * Recreate [mappings] and [diagnostics]
*/ */
@@ -131,10 +141,6 @@ internal sealed class ReanalyzableStructureElement<KT : KtAnnotated, S : FirBase
SingleNonLocalDeclarationDiagnosticRetriever(firSymbol.fir), SingleNonLocalDeclarationDiagnosticRetriever(firSymbol.fir),
moduleComponents, moduleComponents,
) )
companion object {
val recorder = FirElementsRecorder()
}
} }
internal class ReanalyzableCodeFragmentStructureElement( internal class ReanalyzableCodeFragmentStructureElement(
@@ -143,7 +149,6 @@ internal class ReanalyzableCodeFragmentStructureElement(
firSymbol: FirCodeFragmentSymbol, firSymbol: FirCodeFragmentSymbol,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : ReanalyzableStructureElement<KtCodeFragment, FirCodeFragmentSymbol>(firFile, firSymbol, moduleComponents) { ) : ReanalyzableStructureElement<KtCodeFragment, FirCodeFragmentSymbol>(firFile, firSymbol, moduleComponents) {
override val mappings = KtToFirMapping(firSymbol.fir, recorder)
override val timestamp = psi.modificationStamp override val timestamp = psi.modificationStamp
override fun reanalyze(): ReanalyzableStructureElement<KtCodeFragment, FirCodeFragmentSymbol> { override fun reanalyze(): ReanalyzableStructureElement<KtCodeFragment, FirCodeFragmentSymbol> {
@@ -159,8 +164,6 @@ internal class ReanalyzableFunctionStructureElement(
override val timestamp: Long, override val timestamp: Long,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : ReanalyzableStructureElement<KtNamedFunction, FirFunctionSymbol<*>>(firFile, firSymbol, moduleComponents) { ) : ReanalyzableStructureElement<KtNamedFunction, FirFunctionSymbol<*>>(firFile, firSymbol, moduleComponents) {
override val mappings = KtToFirMapping(firSymbol.fir, recorder)
override fun reanalyze(): ReanalyzableFunctionStructureElement { override fun reanalyze(): ReanalyzableFunctionStructureElement {
firSymbol.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) firSymbol.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
@@ -181,8 +184,6 @@ internal class ReanalyzablePropertyStructureElement(
override val timestamp: Long, override val timestamp: Long,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : ReanalyzableStructureElement<KtProperty, FirPropertySymbol>(firFile, firSymbol, moduleComponents) { ) : ReanalyzableStructureElement<KtProperty, FirPropertySymbol>(firFile, firSymbol, moduleComponents) {
override val mappings = KtToFirMapping(firSymbol.fir, recorder)
override fun reanalyze(): ReanalyzablePropertyStructureElement { override fun reanalyze(): ReanalyzablePropertyStructureElement {
firSymbol.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE) firSymbol.lazyResolveToPhase(FirResolvePhase.BODY_RESOLVE)
@@ -196,26 +197,27 @@ internal class ReanalyzablePropertyStructureElement(
} }
} }
internal sealed class NonReanalyzableDeclarationStructureElement( internal sealed class NonReanalyzableDeclarationStructureElement<T : FirDeclaration>(
val firDeclaration: T,
firFile: FirFile, firFile: FirFile,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : FileStructureElement(firFile, moduleComponents) ) : FileStructureElement(firFile, moduleComponents) {
override val mappings: KtToFirMapping = KtToFirMapping(firDeclaration)
}
internal class RootScriptStructureElement( internal class RootScriptStructureElement(
firFile: FirFile, firFile: FirFile,
val script: FirScript, script: FirScript,
override val psi: KtScript, override val psi: KtScript,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : NonReanalyzableDeclarationStructureElement(firFile, moduleComponents) { ) : NonReanalyzableDeclarationStructureElement<FirScript>(script, firFile, moduleComponents) {
override val mappings: KtToFirMapping = KtToFirMapping(script, Recorder)
override val diagnostics: FileStructureElementDiagnostics = FileStructureElementDiagnostics( override val diagnostics: FileStructureElementDiagnostics = FileStructureElementDiagnostics(
firFile, firFile,
ScriptDiagnosticRetriever(script), ScriptDiagnosticRetriever(firDeclaration),
moduleComponents, moduleComponents,
) )
private object Recorder : FirElementsRecorder() { object Recorder : FirElementsRecorder() {
override fun visitScript(script: FirScript, data: MutableMap<KtElement, FirElement>) { override fun visitScript(script: FirScript, data: MutableMap<KtElement, FirElement>) {
cacheElement(script, data) cacheElement(script, data)
visitScriptDependentElements(script, this, data) visitScriptDependentElements(script, this, data)
@@ -235,20 +237,17 @@ internal fun <T, R> visitScriptDependentElements(script: FirScript, visitor: Fir
internal class NonReanalyzableClassDeclarationStructureElement( internal class NonReanalyzableClassDeclarationStructureElement(
firFile: FirFile, firFile: FirFile,
val fir: FirRegularClass, fir: FirRegularClass,
override val psi: KtClassOrObject, override val psi: KtClassOrObject,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : NonReanalyzableDeclarationStructureElement(firFile, moduleComponents) { ) : NonReanalyzableDeclarationStructureElement<FirRegularClass>(fir, firFile, moduleComponents) {
override val mappings = KtToFirMapping(fir, Recorder())
override val diagnostics = FileStructureElementDiagnostics( override val diagnostics = FileStructureElementDiagnostics(
firFile, firFile,
ClassDiagnosticRetriever(fir), ClassDiagnosticRetriever(firDeclaration),
moduleComponents, moduleComponents,
) )
private inner class Recorder : FirElementsRecorder() { class Recorder(private val firClass: FirRegularClass) : FirElementsRecorder() {
override fun visitProperty(property: FirProperty, data: MutableMap<KtElement, FirElement>) { override fun visitProperty(property: FirProperty, data: MutableMap<KtElement, FirElement>) {
if (property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) { if (property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) {
super.visitProperty(property, data) super.visitProperty(property, data)
@@ -271,7 +270,7 @@ internal class NonReanalyzableClassDeclarationStructureElement(
} }
override fun visitRegularClass(regularClass: FirRegularClass, data: MutableMap<KtElement, FirElement>) { override fun visitRegularClass(regularClass: FirRegularClass, data: MutableMap<KtElement, FirElement>) {
if (regularClass != fir) return if (regularClass != firClass) return
super.visitRegularClass(regularClass, data) super.visitRegularClass(regularClass, data)
} }
@@ -282,20 +281,17 @@ internal class NonReanalyzableClassDeclarationStructureElement(
internal class NonReanalyzableNonClassDeclarationStructureElement( internal class NonReanalyzableNonClassDeclarationStructureElement(
firFile: FirFile, firFile: FirFile,
val fir: FirDeclaration, fir: FirDeclaration,
override val psi: KtDeclaration, override val psi: KtDeclaration,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : NonReanalyzableDeclarationStructureElement(firFile, moduleComponents) { ) : NonReanalyzableDeclarationStructureElement<FirDeclaration>(fir, firFile, moduleComponents) {
override val mappings = KtToFirMapping(fir, Recorder)
override val diagnostics = FileStructureElementDiagnostics( override val diagnostics = FileStructureElementDiagnostics(
firFile, firFile,
SingleNonLocalDeclarationDiagnosticRetriever(fir), SingleNonLocalDeclarationDiagnosticRetriever(firDeclaration),
moduleComponents, moduleComponents,
) )
internal object Recorder : FirElementsRecorder() { object Recorder : FirElementsRecorder() {
override fun visitConstructor(constructor: FirConstructor, data: MutableMap<KtElement, FirElement>) { override fun visitConstructor(constructor: FirConstructor, data: MutableMap<KtElement, FirElement>) {
if (constructor is FirPrimaryConstructor) { if (constructor is FirPrimaryConstructor) {
constructor.valueParameters.forEach { parameter -> constructor.valueParameters.forEach { parameter ->
@@ -312,14 +308,15 @@ internal class NonReanalyzableNonClassDeclarationStructureElement(
internal class DanglingTopLevelModifierListStructureElement( internal class DanglingTopLevelModifierListStructureElement(
firFile: FirFile, firFile: FirFile,
val fir: FirDeclaration, fir: FirDanglingModifierList,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
override val psi: KtAnnotated, override val psi: KtAnnotated,
) : ) : NonReanalyzableDeclarationStructureElement<FirDanglingModifierList>(fir, firFile, moduleComponents) {
FileStructureElement(firFile, moduleComponents) { override val diagnostics = FileStructureElementDiagnostics(
override val mappings = KtToFirMapping(fir, FirElementsRecorder()) firFile,
SingleNonLocalDeclarationDiagnosticRetriever(firDeclaration),
override val diagnostics = FileStructureElementDiagnostics(firFile, SingleNonLocalDeclarationDiagnosticRetriever(fir), moduleComponents) moduleComponents,
)
} }
internal class RootStructureElement( internal class RootStructureElement(
@@ -327,11 +324,10 @@ internal class RootStructureElement(
override val psi: KtFile, override val psi: KtFile,
moduleComponents: LLFirModuleResolveComponents, moduleComponents: LLFirModuleResolveComponents,
) : FileStructureElement(firFile, moduleComponents) { ) : FileStructureElement(firFile, moduleComponents) {
override val mappings = KtToFirMapping(firFile, Recorder) override val mappings = KtToFirMapping(firFile)
override val diagnostics = FileStructureElementDiagnostics(firFile, FileDiagnosticRetriever, moduleComponents) override val diagnostics = FileStructureElementDiagnostics(firFile, FileDiagnosticRetriever, moduleComponents)
private object Recorder : FirElementsRecorder() { object Recorder : FirElementsRecorder() {
override fun visitElement(element: FirElement, data: MutableMap<KtElement, FirElement>) { override fun visitElement(element: FirElement, data: MutableMap<KtElement, FirElement>) {
if (element !is FirDeclaration || element is FirFile) { if (element !is FirDeclaration || element is FirFile) {
super.visitElement(element, data) super.visitElement(element, data)
@@ -63,12 +63,9 @@ abstract class AbstractFirContextCollectionTest : AbstractLowLevelApiSingleFileT
} }
private fun FileStructureElement.getFirDeclaration(): FirDeclaration = when (this) { private fun FileStructureElement.getFirDeclaration(): FirDeclaration = when (this) {
is ReanalyzableStructureElement<*, *> -> firSymbol.fir
is RootStructureElement -> firFile is RootStructureElement -> firFile
is DanglingTopLevelModifierListStructureElement -> fir is ReanalyzableStructureElement<*, *> -> firSymbol.fir
is NonReanalyzableClassDeclarationStructureElement -> fir is NonReanalyzableDeclarationStructureElement<*> -> firDeclaration
is NonReanalyzableNonClassDeclarationStructureElement -> fir
is RootScriptStructureElement -> script
} }
private class BeforeElementLLFirSessionConfigurator(private val testServices: TestServices) : LLFirSessionConfigurator { private class BeforeElementLLFirSessionConfigurator(private val testServices: TestServices) : LLFirSessionConfigurator {