[FIR2IR] Introduce special FirProvider with plugin-generated files

For declarations generated by plugins, fir2ir creates special synthetic
  FIR files, which are not registered in the regular FirProvider. This
  leads to incorrect determination of ir parent for generated declarations,
  because `irParent` utility relies on file returned from fir provider

To fix this issue, the new FirProvider for fir2ir is introduced, which
  wraps the original provider and allows to register newly created files

Note that this means that it's illegal anymore to use FirProvider from
  session anywhere in fir2ir. `firProvider` from `Fir2IrComponents`
  should be used instead
This commit is contained in:
Dmitriy Novozhilov
2023-11-15 15:52:48 +02:00
committed by Space Team
parent d85d671b26
commit 8ebb412705
11 changed files with 124 additions and 27 deletions
@@ -24,7 +24,8 @@ import org.jetbrains.kotlin.fir.java.hasJvmFieldAnnotation
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.getRegularClassSymbolByClassId
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
import org.jetbrains.kotlin.fir.serialization.*
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
@@ -292,10 +293,9 @@ class FirJvmSerializerExtension(
return false
}
val grandParent =
containerSymbol.classId.outerClassId?.let {
session.firProvider.getFirClassifierByFqName(it) as? FirRegularClass
}
val grandParent = containerSymbol.classId.outerClassId?.let {
session.symbolProvider.getRegularClassSymbolByClassId(it)?.fir
}
return grandParent != null &&
(grandParent.classKind == ClassKind.INTERFACE || grandParent.classKind == ClassKind.ANNOTATION_CLASS)
}
@@ -18,7 +18,9 @@ import org.jetbrains.kotlin.fir.builder.buildPackageDirective
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildFile
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.isInline
import org.jetbrains.kotlin.fir.declarations.utils.isJava
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.extensions.FirExtensionApiInternals
import org.jetbrains.kotlin.fir.extensions.declarationGenerators
@@ -30,13 +32,15 @@ import org.jetbrains.kotlin.fir.references.impl.FirPropertyFromParameterResolved
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.originalConstructorIfTypeAlias
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
@@ -48,7 +52,10 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.GeneratedByPlugin
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
@@ -575,7 +582,8 @@ internal fun IrDeclarationParent.declareThisReceiverParameter(
}
}
fun FirClass.irOrigin(firProvider: FirProvider): IrDeclarationOrigin = when {
context(Fir2IrComponents)
fun FirClass.irOrigin(): IrDeclarationOrigin = when {
firProvider.getFirClassifierContainerFileIfAny(symbol) != null -> IrDeclarationOrigin.DEFINED
isJava -> IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
else -> when (val origin = origin) {
@@ -90,7 +90,7 @@ class Fir2IrAnnotationsFromPluginRegistrar(private val components: Fir2IrCompone
// we need to use the original session of the declaration
val containingSession = moduleData.session
val topmostParent = topmostParent(containingSession)
return containingSession.firProvider.getContainingFile(topmostParent.symbol)
return components.firProvider.getContainingFile(topmostParent.symbol)
}
private fun FirDeclaration.topmostParent(session: FirSession): FirDeclaration {
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
@@ -335,8 +334,7 @@ class Fir2IrClassifierStorage(
): IrEnumEntry {
getCachedIrEnumEntry(enumEntry)?.let { return it }
val firProviderForEntry = enumEntry.moduleData.session.firProvider
val containingFile = firProviderForEntry.getFirCallableContainerFile(enumEntry.symbol)
val containingFile = firProvider.getFirCallableContainerFile(enumEntry.symbol)
@Suppress("NAME_SHADOWING")
val predefinedOrigin = predefinedOrigin ?: if (containingFile != null) {
@@ -19,6 +19,13 @@ interface Fir2IrComponents {
val session: FirSession
val scopeSession: ScopeSession
/**
* It's important to use this fir provider in fir2ir instead of provider from session,
* because this provider will also contain synthetic fir files for declarations generated
* by frontend plugins
*/
val firProvider: FirProviderWithGeneratedFiles
val converter: Fir2IrConverter
val symbolTable: SymbolTable
@@ -32,6 +32,7 @@ class Fir2IrComponentsStorage(
specialSymbolProvider: Fir2IrSpecialSymbolProvider,
initializedIrBuiltIns: IrBuiltInsOverFir?
) : Fir2IrComponents {
override val firProvider: FirProviderWithGeneratedFiles = FirProviderWithGeneratedFiles(session)
override val signatureComposer: FirBasedSignatureComposer = commonMemberStorage.firSignatureComposer
override val symbolTable: SymbolTable = commonMemberStorage.symbolTable
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.overrides.FakeOverrideRebuilder
import org.jetbrains.kotlin.backend.common.sourceElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.*
@@ -721,7 +720,9 @@ class Fir2IrConverter(
val allFirFiles = buildList {
addAll(firFiles)
addAll(session.createFilesWithGeneratedDeclarations())
val generatedFiles = session.createFilesWithGeneratedDeclarations()
addAll(generatedFiles)
generatedFiles.forEach { components.firProvider.recordFile(it) }
}
components.converter.runSourcesConversion(
@@ -14,7 +14,10 @@ import org.jetbrains.kotlin.fir.backend.generators.isExternalParent
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.descriptors.FirBuiltInsPackageFragment
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol
@@ -894,8 +897,7 @@ class Fir2IrDeclarationStorage(
classifierStorage.getCachedIrEnumEntry(firDeclaration)?.let { return it.symbol }
val irParentClass = firDeclaration.containingClassLookupTag()?.let { classifierStorage.findIrClass(it) }!!
val firProviderForSymbol = firVariableSymbol.moduleData.session.firProvider
val containingFile = firProviderForSymbol.getFirCallableContainerFile(firVariableSymbol)
val containingFile = firProvider.getFirCallableContainerFile(firVariableSymbol)
classifierStorage.getOrCreateIrEnumEntry(
firDeclaration,
@@ -1330,10 +1332,23 @@ class Fir2IrDeclarationStorage(
}
}
val firProviderForSymbol = firBasedSymbol.moduleData.session.firProvider
/**
* In `allowNonCachedDeclarations` mode there is a situation possible when we get source declaration
* from session which is different from one which we convert right now. So we need to take an original firProvider
* for this declaration to correctly find containig file and properly generate NonCachedSourceFileFacadeClass if needed
*/
val firProvider = if (configuration.allowNonCachedDeclarations) {
when {
firBasedSymbol.moduleData == session.moduleData -> components.firProvider
else -> firBasedSymbol.moduleData.session.firProvider
}
} else {
components.firProvider
}
val containerFile = when (firBasedSymbol) {
is FirCallableSymbol -> firProviderForSymbol.getFirCallableContainerFile(firBasedSymbol)
is FirClassLikeSymbol -> firProviderForSymbol.getFirClassifierContainerFileIfAny(firBasedSymbol)
is FirCallableSymbol -> firProvider.getFirCallableContainerFile(firBasedSymbol)
is FirClassLikeSymbol -> firProvider.getFirClassifierContainerFileIfAny(firBasedSymbol)
else -> error("Unknown symbol: $firBasedSymbol")
}
@@ -0,0 +1,66 @@
/*
* 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.fir.backend
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class FirProviderWithGeneratedFiles(val session: FirSession) : FirProvider() {
private val generatedFilesProvider = FirProviderImpl(session, session.kotlinScopeProvider)
private val providers: List<FirProvider> = listOf(session.firProvider, generatedFilesProvider)
override val symbolProvider: FirSymbolProvider
get() = providers.first().symbolProvider
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? {
return providers.firstNotNullOfOrNull { it.getFirClassifierByFqName(classId) }
}
override fun getFirClassifierContainerFile(fqName: ClassId): FirFile {
return getFirClassifierContainerFileIfAny(fqName) ?: error("Couldn't find container for $fqName")
}
override fun getFirClassifierContainerFileIfAny(fqName: ClassId): FirFile? {
return providers.firstNotNullOfOrNull { it.getFirClassifierContainerFileIfAny(fqName) }
}
override fun getFirCallableContainerFile(symbol: FirCallableSymbol<*>): FirFile? {
return providers.firstNotNullOfOrNull { it.getFirCallableContainerFile(symbol) }
}
override fun getFirScriptContainerFile(symbol: FirScriptSymbol): FirFile? {
return providers.firstNotNullOfOrNull { it.getFirScriptContainerFile(symbol) }
}
override fun getFirScriptByFilePath(path: String): FirScriptSymbol? {
return providers.firstNotNullOfOrNull { it.getFirScriptByFilePath(path) }
}
override fun getFirFilesByPackage(fqName: FqName): List<FirFile> {
return providers.flatMap { it.getFirFilesByPackage(fqName) }
}
override fun getClassNamesInPackage(fqName: FqName): Set<Name> {
return providers.flatMapTo(mutableSetOf()) { it.getClassNamesInPackage(fqName) }
}
fun recordFile(file: FirFile) {
generatedFilesProvider.recordFile(file)
}
}
@@ -15,14 +15,16 @@ import org.jetbrains.kotlin.fir.hasEnumEntries
import org.jetbrains.kotlin.fir.lazy.Fir2IrLazyClass
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.types.toLookupTag
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassPublicSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.name.FqName
@@ -203,7 +205,7 @@ class Fir2IrClassifiersGenerator(val components: Fir2IrComponents) : Fir2IrCompo
// finding the parent class that actually contains the [klass] in the tree - it is the root one that should be created on the fly
val classOrLocalParent = generateSequence(klass) { c ->
(c as? FirRegularClass)?.containingClassForLocalAttr?.let { lookupTag ->
(session.firProvider.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirClass)?.takeIf {
(firProvider.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir as? FirClass)?.takeIf {
it.declarations.contains(c)
}
}
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
import org.jetbrains.kotlin.fir.lazy.*
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.unwrapUseSiteSubstitutionOverrides
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -72,7 +71,7 @@ class Fir2IrLazyDeclarationsGenerator(val components: Fir2IrComponents) : Fir2Ir
irParent: IrDeclarationParent,
symbol: IrClassSymbol
): Fir2IrLazyClass = firClass.convertWithOffsets { startOffset, endOffset ->
val firClassOrigin = firClass.irOrigin(session.firProvider)
val firClassOrigin = firClass.irOrigin()
Fir2IrLazyClass(components, startOffset, endOffset, firClassOrigin, firClass, symbol, irParent)
}