[FIR] Make FirProviderWithGeneratedFiles know about providers from mpp dependencies

During refactoring of FIR2IR commit 8ebb4127 introduced
  `FirProviderWithGeneratedFiles` for lookups for containing FIR for
  generated declaration

But it broke the logic of `Fir2IrIrGeneratedDeclarationsRegistrar`,
  which provides annotations for metadata from generated IR annotations
  (see `containingFile` function in it), as it started to use fir
  provider from the platfrom session instead of provider of the
  corresponding session

So to fix this issue `FirProviderWithGeneratedFiles` was changed in the
  way so it sees declarations from dependant sessions too (only with
  `dependsOn` relation), which allows to use provider for the leaf
  platform session for declarations from any module within the same
  HMPP hierarchy

^KT-64444 Fixed
This commit is contained in:
Dmitriy Novozhilov
2024-01-04 18:14:20 +02:00
committed by Space Team
parent 8feb4def4d
commit 7accda6cda
9 changed files with 177 additions and 6 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.signaturer.FirBasedSignatureComposer
import org.jetbrains.kotlin.ir.declarations.*
@@ -53,4 +54,14 @@ class Fir2IrCommonMemberStorage(
val fakeOverridesInClass: MutableMap<IrClass, MutableMap<Fir2IrDeclarationStorage.FirOverrideKey, FirCallableDeclaration>> = mutableMapOf()
val irForFirSessionDependantDeclarationMap: MutableMap<Fir2IrDeclarationStorage.FakeOverrideIdentifier, IrSymbol> = mutableMapOf()
fun registerFirProvider(moduleData: FirModuleData, firProvider: FirProviderWithGeneratedFiles) {
require(moduleData !in _previousFirProviders) { "FirProvider for $moduleData already registered"}
_previousFirProviders[moduleData] = firProvider
}
val previousFirProviders: Map<FirModuleData, FirProviderWithGeneratedFiles>
get() = _previousFirProviders
private val _previousFirProviders: MutableMap<FirModuleData, FirProviderWithGeneratedFiles> = mutableMapOf()
}
@@ -32,7 +32,11 @@ class Fir2IrComponentsStorage(
specialSymbolProvider: Fir2IrSpecialSymbolProvider,
initializedIrBuiltIns: IrBuiltInsOverFir?
) : Fir2IrComponents {
override val firProvider: FirProviderWithGeneratedFiles = FirProviderWithGeneratedFiles(session)
override val firProvider: FirProviderWithGeneratedFiles = FirProviderWithGeneratedFiles(
session,
commonMemberStorage.previousFirProviders
)
override val signatureComposer: FirBasedSignatureComposer = commonMemberStorage.firSignatureComposer
override val symbolTable: SymbolTable = commonMemberStorage.symbolTable
@@ -743,6 +743,8 @@ class Fir2IrConverter(
components.fir2IrVisitor
)
commonMemberStorage.registerFirProvider(session.moduleData, components.firProvider)
return Fir2IrResult(irModuleFragment, components, moduleDescriptor)
}
}
@@ -5,9 +5,11 @@
package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.fir.FirModuleData
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.moduleData
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
@@ -20,10 +22,14 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class FirProviderWithGeneratedFiles(val session: FirSession) : FirProvider() {
class FirProviderWithGeneratedFiles(val session: FirSession, previousProviders: Map<FirModuleData, FirProviderWithGeneratedFiles>) : FirProvider() {
private val generatedFilesProvider = FirProviderImpl(session, session.kotlinScopeProvider)
private val providers: List<FirProvider> = listOf(session.firProvider, generatedFilesProvider)
private val providers: List<FirProvider> = buildList {
add(session.firProvider)
add(generatedFilesProvider)
session.moduleData.dependsOnDependencies.mapNotNullTo(this) { previousProviders[it] }
}
override val symbolProvider: FirSymbolProvider
get() = providers.first().symbolProvider
@@ -42,6 +42,7 @@ annotation class AllPropertiesConstructor
annotation class AddAnnotations
@Retention(AnnotationRetention.RUNTIME)
annotation class AnnotationToAdd(
val booleanValue: Boolean,
val byteValue: Byte,
@@ -0,0 +1,100 @@
Module: common
FILE: module_common_annotationsGeneratedInBackend_mpp.kt
package test
@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() public final class Some : R|kotlin/Any| {
public constructor(): R|test/Some| {
super<R|kotlin/Any|>()
}
public final fun foo(): R|kotlin/Unit| {
}
}
FILE: module_platform_annotationsGeneratedInBackend_mpp.kt
package test
@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() public final class Other : R|kotlin/Any| {
public constructor(): R|test/Other| {
super<R|kotlin/Any|>()
}
public final fun foo(): R|kotlin/Unit| {
}
}
public final fun checkClass(klass: R|kotlin/reflect/KClass<*>|): R|kotlin/Boolean| {
lval foo: R|kotlin/reflect/KFunction<*>| = R|<local>/klass|.R|kotlin/reflect/full/declaredFunctions|.R|kotlin/collections/first|<R|kotlin/reflect/KFunction<*>|>(<L> = first@fun <anonymous>(it: R|kotlin/reflect/KFunction<*>|): R|kotlin/Boolean| <inline=Inline, kind=UNKNOWN> {
^ ==(R|<local>/it|.R|SubstitutionOverride<kotlin/reflect/KFunction.name: R|kotlin/String|>|, String(foo))
}
)
^checkClass R|<local>/foo|.R|kotlin/reflect/KAnnotatedElement.annotations|.R|kotlin/collections/any|<R|kotlin/Annotation|>(<L> = any@fun <anonymous>(it: R|kotlin/Annotation|): R|kotlin/Boolean| <inline=Inline, kind=UNKNOWN> {
^ ==(R|<local>/it|.R|kotlin/jvm/annotationClass|<R|kotlin/Annotation|>.R|SubstitutionOverride<kotlin/reflect/KClass.simpleName: R|kotlin/String?|>|, String(AnnotationToAdd))
}
)
}
public final fun box(): R|kotlin/String| {
when () {
R|test/checkClass|(<getClass>(Q|test/Some|)).R|kotlin/Boolean.not|() -> {
^box String(Fail: Some)
}
}
when () {
R|test/checkClass|(<getClass>(Q|test/Other|)).R|kotlin/Boolean.not|() -> {
^box String(Fail: Other)
}
}
^box String(OK)
}
Module: platform
FILE: module_common_annotationsGeneratedInBackend_mpp.kt
package test
@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() public final class Some : R|kotlin/Any| {
public constructor(): R|test/Some| {
super<R|kotlin/Any|>()
}
public final fun foo(): R|kotlin/Unit| {
}
}
FILE: module_platform_annotationsGeneratedInBackend_mpp.kt
package test
@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() public final class Other : R|kotlin/Any| {
public constructor(): R|test/Other| {
super<R|kotlin/Any|>()
}
public final fun foo(): R|kotlin/Unit| {
}
}
public final fun checkClass(klass: R|kotlin/reflect/KClass<*>|): R|kotlin/Boolean| {
lval foo: R|kotlin/reflect/KFunction<*>| = R|<local>/klass|.R|kotlin/reflect/full/declaredFunctions|.R|kotlin/collections/first|<R|kotlin/reflect/KFunction<*>|>(<L> = first@fun <anonymous>(it: R|kotlin/reflect/KFunction<*>|): R|kotlin/Boolean| <inline=Inline, kind=UNKNOWN> {
^ ==(R|<local>/it|.R|SubstitutionOverride<kotlin/reflect/KFunction.name: R|kotlin/String|>|, String(foo))
}
)
^checkClass R|<local>/foo|.R|kotlin/reflect/KAnnotatedElement.annotations|.R|kotlin/collections/any|<R|kotlin/Annotation|>(<L> = any@fun <anonymous>(it: R|kotlin/Annotation|): R|kotlin/Boolean| <inline=Inline, kind=UNKNOWN> {
^ ==(R|<local>/it|.R|kotlin/jvm/annotationClass|<R|kotlin/Annotation|>.R|SubstitutionOverride<kotlin/reflect/KClass.simpleName: R|kotlin/String?|>|, String(AnnotationToAdd))
}
)
}
public final fun box(): R|kotlin/String| {
when () {
R|test/checkClass|(<getClass>(Q|test/Some|)).R|kotlin/Boolean.not|() -> {
^box String(Fail: Some)
}
}
when () {
R|test/checkClass|(<getClass>(Q|test/Other|)).R|kotlin/Boolean.not|() -> {
^box String(Fail: Other)
}
}
^box String(OK)
}
@@ -0,0 +1,39 @@
// LANGUAGE: +MultiPlatformProjects
// TARGET_BACKEND: JVM_IR
// WITH_REFLECT
// WITH_STDLIB
// MODULE: common
package test
import org.jetbrains.kotlin.fir.plugin.AddAnnotations
import kotlin.reflect.KClass
@AddAnnotations
class Some {
fun foo() {}
}
// MODULE: platform()()(common)
package test
import org.jetbrains.kotlin.fir.plugin.AddAnnotations
import kotlin.reflect.KAnnotatedElement
import kotlin.reflect.KClass
import kotlin.reflect.full.declaredFunctions
@AddAnnotations
class Other {
fun foo() {}
}
fun checkClass(klass: KClass<*>): Boolean {
val foo = klass.declaredFunctions.first { it.name == "foo" }
return foo.annotations.any { it.annotationClass.simpleName == "AnnotationToAdd" }
}
fun box(): String {
if (!checkClass(Some::class)) return "Fail: Some"
if (!checkClass(Other::class)) return "Fail: Other"
return "OK"
}
@@ -25,6 +25,12 @@ public class FirLightTreePluginBlackBoxCodegenTestGenerated extends AbstractFirL
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir-plugin-prototype/testData/box"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("annotationsGeneratedInBackend_mpp.kt")
public void testAnnotationsGeneratedInBackend_mpp() throws Exception {
runTest("plugins/fir-plugin-prototype/testData/box/annotationsGeneratedInBackend_mpp.kt");
}
@Test
@TestMetadata("builtins.kt")
public void testBuiltins() throws Exception {
@@ -37,9 +37,11 @@ class PluginAnnotationsProvider(testServices: TestServices) : EnvironmentConfigu
class PluginRuntimeAnnotationsProvider(testServices: TestServices) : RuntimeClasspathProvider(testServices) {
override fun runtimeClassPaths(module: TestModule): List<File> {
if (!module.targetPlatform.isJs()) return emptyList()
val jar = findJsLib()
return listOf(jar)
return when {
module.targetPlatform.isJvm() -> listOf(findJvmLib())
module.targetPlatform.isJs() -> listOf(findJsLib())
else -> emptyList()
}
}
}