diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt index 4f4af30528c..095180014df 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/klib/compilerPipeline.kt @@ -260,7 +260,8 @@ private class Fir2KlibSerializer( FirKLibSerializerExtension( session, metadataVersion, ConstValueProviderImpl(fir2IrActualizedResult.components), - allowErrorTypes = false, exportKDoc = false + allowErrorTypes = false, exportKDoc = false, + fir2IrActualizedResult.components.annotationsFromPluginRegistrar.createMetadataAnnotationsProvider() ), languageVersionSettings, ) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/FirMetadataSerializer.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/FirMetadataSerializer.kt index f9f4e730e83..0f2657d254a 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/FirMetadataSerializer.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/FirMetadataSerializer.kt @@ -167,7 +167,8 @@ internal class FirMetadataSerializer( actualizedExpectDeclarations = null, FirKLibSerializerExtension( session, metadataVersion, constValueProvider = null, - allowErrorTypes = false, exportKDoc = false + allowErrorTypes = false, exportKDoc = false, + additionalAnnotationsProvider = null ), languageVersionSettings, ) diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAdditionalMetadataAnnotationsProvider.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAdditionalMetadataAnnotationsProvider.kt new file mode 100644 index 00000000000..b7b402767a9 --- /dev/null +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirAdditionalMetadataAnnotationsProvider.kt @@ -0,0 +1,14 @@ +/* + * 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.serialization + +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.expressions.FirAnnotation + +abstract class FirAdditionalMetadataAnnotationsProvider { + abstract fun findGeneratedAnnotationsFor(declaration: FirDeclaration): List + abstract fun hasGeneratedAnnotationsFor(declaration: FirDeclaration): Boolean +} diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt index a6c9795db03..64bbbb5b7e0 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt @@ -129,7 +129,7 @@ class FirElementSerializer private constructor( val hasEnumEntries = klass.classKind == ClassKind.ENUM_CLASS && languageVersionSettings.supportsFeature(LanguageFeature.EnumEntries) val flags = Flags.getClassFlags( - klass.nonSourceAnnotations(session).isNotEmpty(), + klass.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(klass), ProtoEnumFlags.visibility(regularClass?.let { normalizeVisibility(it) } ?: Visibilities.Local), ProtoEnumFlags.modality(modality), ProtoEnumFlags.classKind(klass.classKind, regularClass?.isCompanion == true), @@ -377,6 +377,8 @@ class FirElementSerializer private constructor( val hasAnnotations = property.nonSourceAnnotations(session).isNotEmpty() || property.backingField?.nonSourceAnnotations(session)?.isNotEmpty() == true + || extension.hasAdditionalAnnotations(property) + || property.backingField?.let { extension.hasAdditionalAnnotations(it) } == true val modality = property.modality!! val defaultAccessorFlags = Flags.getAccessorFlags( @@ -499,7 +501,7 @@ class FirElementSerializer private constructor( val local = createChildSerializer(function) val flags = Flags.getFunctionFlags( - function.nonSourceAnnotations(session).isNotEmpty(), + function.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(function), ProtoEnumFlags.visibility(simpleFunction?.let { normalizeVisibility(it) } ?: Visibilities.Local), ProtoEnumFlags.modality(simpleFunction?.modality ?: Modality.FINAL), if (function.origin == FirDeclarationOrigin.Delegated) ProtoBuf.MemberKind.DELEGATION else ProtoBuf.MemberKind.DECLARATION, @@ -603,7 +605,7 @@ class FirElementSerializer private constructor( val local = createChildSerializer(typeAlias) val flags = Flags.getTypeAliasFlags( - typeAlias.nonSourceAnnotations(session).isNotEmpty(), + typeAlias.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(typeAlias), ProtoEnumFlags.visibility(normalizeVisibility(typeAlias)) ) if (flags != builder.flags) { @@ -657,7 +659,7 @@ class FirElementSerializer private constructor( val local = createChildSerializer(constructor) val flags = Flags.getConstructorFlags( - constructor.nonSourceAnnotations(session).isNotEmpty(), + constructor.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(constructor), ProtoEnumFlags.visibility(normalizeVisibility(constructor)), !constructor.isPrimary, shouldSetStableParameterNames(constructor) @@ -703,7 +705,9 @@ class FirElementSerializer private constructor( function.symbol.getSingleExpectForActualOrNull(compatibleOnly = true).containsDefaultValue(index) val flags = Flags.getValueParameterFlags( - additionalAnnotations.isNotEmpty() || parameter.nonSourceAnnotations(session).isNotEmpty(), + additionalAnnotations.isNotEmpty() + || parameter.nonSourceAnnotations(session).isNotEmpty() + || extension.hasAdditionalAnnotations(parameter), declaresDefaultValue, parameter.isCrossinline, parameter.isNoinline @@ -1026,15 +1030,15 @@ class FirElementSerializer private constructor( private fun getAccessorFlags(accessor: FirPropertyAccessor, property: FirProperty): Int { // [FirDefaultPropertyAccessor]---a property accessor without body---can still hold other information, such as annotations, // user-contributed visibility, and modifiers, such as `external` or `inline`. - val nonSourceAnnotations = accessor.nonSourceAnnotations(session) + val hasAnnotations = accessor.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(accessor) val isDefault = property.isLocal || (accessor is FirDefaultPropertyAccessor && - nonSourceAnnotations.isEmpty() && + !hasAnnotations && accessor.visibility == property.visibility && !accessor.isExternal && !accessor.isInline) return Flags.getAccessorFlags( - nonSourceAnnotations.isNotEmpty(), + hasAnnotations, ProtoEnumFlags.visibility(normalizeVisibility(accessor)), // non-default accessor modality is always final, so we check property.modality instead ProtoEnumFlags.modality(property.modality!!), diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirKLibSerializerExtension.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirKLibSerializerExtension.kt index bd8ef818971..7dbdabb91bf 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirKLibSerializerExtension.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirKLibSerializerExtension.kt @@ -29,7 +29,8 @@ class FirKLibSerializerExtension( override val metadataVersion: BinaryVersion, override val constValueProvider: ConstValueProvider?, private val allowErrorTypes: Boolean, - private val exportKDoc: Boolean + private val exportKDoc: Boolean, + override val additionalAnnotationsProvider: FirAdditionalMetadataAnnotationsProvider? ) : FirSerializerExtensionBase(KlibMetadataSerializerProtocol) { override fun shouldUseTypeTable(): Boolean = true diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt index 0c80e9ff306..4f5af510438 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtension.kt @@ -27,6 +27,7 @@ abstract class FirSerializerExtension { val annotationSerializer by lazy { FirAnnotationSerializer(session, stringTable, constValueProvider) } protected abstract val constValueProvider: ConstValueProvider? + protected abstract val additionalAnnotationsProvider: FirAdditionalMetadataAnnotationsProvider? @OptIn(ConstValueProviderInternals::class) internal inline fun processFile(firFile: FirFile, crossinline action: () -> T): T { @@ -97,7 +98,16 @@ abstract class FirSerializerExtension { } } + fun hasAdditionalAnnotations(declaration: FirDeclaration): Boolean { + return additionalAnnotationsProvider?.hasGeneratedAnnotationsFor(declaration) ?: false + } + + // TODO: add usages + fun getAnnotationsGeneratedByPlugins(declaration: FirDeclaration): List { + return additionalAnnotationsProvider?.findGeneratedAnnotationsFor(declaration) ?: emptyList() + } + open fun serializeErrorType(type: ConeErrorType, builder: ProtoBuf.Type.Builder) { - throw IllegalStateException("Cannot serialize error type: $type") + error("Cannot serialize error type: $type") } } diff --git a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt index 065c56e68ff..0ddd0d01c19 100644 --- a/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt +++ b/compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirSerializerExtensionBase.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.serialization import org.jetbrains.kotlin.constant.ConstantValue import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget import org.jetbrains.kotlin.fir.FirAnnotationContainer +import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue @@ -63,7 +64,7 @@ abstract class FirSerializerExtensionBase( val fieldPropertyAnnotations = mutableListOf() val delegatePropertyAnnotations = mutableListOf() - for (annotation in property.backingField?.nonSourceAnnotations(session).orEmpty()) { + for (annotation in property.backingField?.allRequiredAnnotations(session).orEmpty()) { val destination = when (annotation.useSiteTarget) { AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> delegatePropertyAnnotations else -> fieldPropertyAnnotations @@ -71,7 +72,7 @@ abstract class FirSerializerExtensionBase( destination += annotation } - property.nonSourceAnnotations(session).serializeAnnotations(proto, protocol.propertyAnnotation) + property.allRequiredAnnotations(session).serializeAnnotations(proto, protocol.propertyAnnotation) fieldPropertyAnnotations.serializeAnnotations(proto, protocol.propertyBackingFieldAnnotation) delegatePropertyAnnotations.serializeAnnotations(proto, protocol.propertyDelegatedFieldAnnotation) @@ -110,7 +111,7 @@ abstract class FirSerializerExtensionBase( extension: GeneratedMessageLite.GeneratedExtension>? ) { if (extension == null) return - this.nonSourceAnnotations(session).serializeAnnotations(proto, extension) + this.allRequiredAnnotations(session).serializeAnnotations(proto, extension) } @Suppress("Reformat") @@ -140,4 +141,14 @@ abstract class FirSerializerExtensionBase( addExtension(extension, value) } } + + private fun FirAnnotationContainer.allRequiredAnnotations(session: FirSession): List { + val nonSourceAnnotations = nonSourceAnnotations(session) + val additionalMetadataAnnotationsProvider = additionalAnnotationsProvider + return if (this is FirDeclaration && additionalMetadataAnnotationsProvider != null) { + nonSourceAnnotations + additionalMetadataAnnotationsProvider.findGeneratedAnnotationsFor(this) + } else { + nonSourceAnnotations + } + } } diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt index 14bf8c8f199..47708c95387 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmSerializerExtension.kt @@ -61,6 +61,7 @@ class FirJvmSerializerExtension( private val jvmDefaultMode: JvmDefaultMode, override val stringTable: FirElementAwareStringTable, override val constValueProvider: ConstValueProvider?, + override val additionalAnnotationsProvider: FirAdditionalMetadataAnnotationsProvider?, ) : FirSerializerExtension() { constructor( @@ -77,6 +78,7 @@ class FirJvmSerializerExtension( state.globalSerializationBindings, state.useTypeTableInSerializer, state.moduleName, state.classBuilderMode, state.isParamAssertionsDisabled, state.unifiedNullChecks, state.metadataVersion, state.jvmDefaultMode, FirJvmElementAwareStringTable(typeMapper, components), ConstValueProviderImpl(components), + components.annotationsFromPluginRegistrar.createMetadataAnnotationsProvider() ) override fun shouldUseTypeTable(): Boolean = useTypeTable diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt index 2b7b70451d3..e522278140f 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirMetadataSerializer.kt @@ -104,7 +104,8 @@ fun makeLocalFirMetadataSerializerForMetadataSource( configuration.metadataVersion(session.languageVersionSettings.languageVersion), session.languageVersionSettings.getFlag(JvmAnalysisFlags.jvmDefaultMode), stringTable, - constValueProvider = null + constValueProvider = null, + additionalAnnotationsProvider = null ) return FirMetadataSerializer( globalSerializationBindings, diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrAnnotationsFromPluginRegistrar.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrAnnotationsFromPluginRegistrar.kt new file mode 100644 index 00000000000..892fe49a00f --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrAnnotationsFromPluginRegistrar.kt @@ -0,0 +1,105 @@ +/* + * 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.backend.common.extensions.IrAnnotationsFromPluginRegistrar +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.declarations.utils.classId +import org.jetbrains.kotlin.fir.expressions.FirAnnotation +import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation +import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping +import org.jetbrains.kotlin.fir.packageFqName +import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile +import org.jetbrains.kotlin.fir.resolve.providers.toSymbol +import org.jetbrains.kotlin.fir.serialization.FirAdditionalMetadataAnnotationsProvider +import org.jetbrains.kotlin.fir.types.constructClassType +import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.toLookupTag +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.nameWithPackage +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.runIf + +class Fir2IrAnnotationsFromPluginRegistrar(private val components: Fir2IrComponents) : IrAnnotationsFromPluginRegistrar() { + private val generatedIrDeclarationsByFileByOffset = mutableMapOf, MutableList>>() + + override fun addMetadataVisibleAnnotationsToElement(declaration: IrDeclaration, annotations: List) { + require(annotations.all { it.valueArgumentsCount == 0 && it.typeArgumentsCount == 0 }) { + "Saving annotations with arguments from IR to metadata is not supported yet. See KT-58968" + } + annotations.forEach { + require(it.symbol.owner.constructedClass.isAnnotationClass) { "${it.render()} is not an annotation constructor call" } + } + val fileFqName = declaration.file.nameWithPackage + val fileStorage = generatedIrDeclarationsByFileByOffset.getOrPut(fileFqName) { mutableMapOf() } + val storage = fileStorage.getOrPut(declaration.startOffset to declaration.endOffset) { mutableListOf() } + storage += annotations + declaration.annotations += annotations + } + + fun createMetadataAnnotationsProvider(): FirAdditionalMetadataAnnotationsProvider { + return Provider() + } + + private inner class Provider : FirAdditionalMetadataAnnotationsProvider() { + private val session = components.session + + override fun findGeneratedAnnotationsFor(declaration: FirDeclaration): List { + val irAnnotations = extractGeneratedIrDeclarations(declaration).takeUnless { it.isEmpty() } ?: return emptyList() + return irAnnotations.map { it.toFirAnnotation() } + } + + override fun hasGeneratedAnnotationsFor(declaration: FirDeclaration): Boolean { + return extractGeneratedIrDeclarations(declaration).isNotEmpty() + } + + private fun extractGeneratedIrDeclarations(declaration: FirDeclaration): List { + val firFile = declaration.containingFile() ?: return emptyList() + val fileFqName = firFile.packageFqName.child(Name.identifier(firFile.name)).asString() + val source = declaration.source ?: return emptyList() + val fileStorage = generatedIrDeclarationsByFileByOffset[fileFqName] ?: return emptyList() + return fileStorage[source.startOffset to source.endOffset] ?: emptyList() + } + + private fun FirDeclaration.containingFile(): FirFile? { + if (this is FirFile) return this + val topmostParent = topmostParent() + return components.session.firProvider.getContainingFile(topmostParent.symbol) + } + + private fun FirDeclaration.topmostParent(): FirDeclaration { + return when (this) { + is FirClassLikeDeclaration -> runIf(!classId.isLocal) { classId.topmostParentClassId.toSymbol(session)?.fir } + is FirTypeParameter -> containingDeclarationSymbol.fir.topmostParent() + is FirValueParameter -> containingFunctionSymbol.fir.topmostParent() + is FirCallableDeclaration -> symbol.callableId.classId + ?.takeIf { !it.isLocal } + ?.topmostParentClassId + ?.toSymbol(session) + ?.fir + else -> error("Unsupported declaration type: $this") + } ?: this + } + + private val ClassId.topmostParentClassId: ClassId + get() = parentClassId?.topmostParentClassId ?: this + + private fun IrConstructorCall.toFirAnnotation(): FirAnnotation { + val annotationClassId = this.symbol.owner.constructedClass.classId!! + return buildAnnotation { + annotationTypeRef = annotationClassId + .toLookupTag() + .constructClassType(typeArguments = emptyArray(), isNullable = false) + .toFirResolvedTypeRef() + argumentMapping = FirEmptyAnnotationArgumentMapping + } + } + } +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt index 8cfe4409d88..98618c776a7 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponents.kt @@ -43,4 +43,6 @@ interface Fir2IrComponents { val extensions: Fir2IrExtensions val configuration: Fir2IrConfiguration + + val annotationsFromPluginRegistrar: Fir2IrAnnotationsFromPluginRegistrar } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt index 790ac6b4f9e..a8520e6fd14 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrComponentsStorage.kt @@ -44,6 +44,8 @@ class Fir2IrComponentsStorage( override lateinit var fakeOverrideGenerator: FakeOverrideGenerator override lateinit var delegatedMemberGenerator: DelegatedMemberGenerator + override lateinit var annotationsFromPluginRegistrar: Fir2IrAnnotationsFromPluginRegistrar + override val lock: IrLock get() = symbolTable.lock } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index 8067724248b..4ef12afd782 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -481,6 +481,7 @@ class Fir2IrConverter( components.fakeOverrideGenerator = FakeOverrideGenerator(components, conversionScope) components.callGenerator = CallAndReferenceGenerator(components, fir2irVisitor, conversionScope) components.irProviders = listOf(FirIrProvider(components)) + components.annotationsFromPluginRegistrar = Fir2IrAnnotationsFromPluginRegistrar(components) fir2IrExtensions.registerDeclarations(commonMemberStorage.symbolTable) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrPluginContext.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrPluginContext.kt index 1e4a2002574..9ebf358026c 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrPluginContext.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrPluginContext.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.backend import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI +import org.jetbrains.kotlin.backend.common.extensions.IrAnnotationsFromPluginRegistrar import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.ir.BuiltinSymbolsBase import org.jetbrains.kotlin.config.LanguageVersionSettings @@ -72,6 +73,9 @@ class Fir2IrPluginContext( private val symbolProvider: FirSymbolProvider get() = components.session.symbolProvider + override val annotationsRegistrar: Fir2IrAnnotationsFromPluginRegistrar + get() = components.annotationsFromPluginRegistrar + override fun referenceClass(classId: ClassId): IrClassSymbol? { val firSymbol = symbolProvider.getClassLikeSymbolByClassId(classId) as? FirClassSymbol<*> ?: return null return components.classifierStorage.getIrClassSymbol(firSymbol) diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrAnnotationsFromPluginRegistrar.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrAnnotationsFromPluginRegistrar.kt new file mode 100644 index 00000000000..e65be9b06ae --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrAnnotationsFromPluginRegistrar.kt @@ -0,0 +1,17 @@ +/* + * 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.backend.common.extensions + +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall + +abstract class IrAnnotationsFromPluginRegistrar { + abstract fun addMetadataVisibleAnnotationsToElement(declaration: IrDeclaration, annotations: List) + + fun addMetadataVisibleAnnotationsToElement(declaration: IrDeclaration, vararg annotations: IrConstructorCall) { + addMetadataVisibleAnnotationsToElement(declaration, annotations.toList()) + } +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContext.kt index ed4a79bc3ea..925d660f867 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContext.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContext.kt @@ -56,6 +56,12 @@ interface IrPluginContext : IrGeneratorContext { val platform: TargetPlatform? + /** + * Use this service to add annotations to declarations if those annotations should be saved into metadata + * This service properly works only in K2 compiler + */ + val annotationsRegistrar: IrAnnotationsFromPluginRegistrar + /** * Returns a logger instance to post diagnostic messages from plugin * diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContextImpl.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContextImpl.kt index 56c5bdd8ff9..add53ebf7d1 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContextImpl.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrPluginContextImpl.kt @@ -14,6 +14,8 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.linkage.IrDeserializer import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.IdSignature @@ -51,6 +53,9 @@ open class IrPluginContextImpl constructor( override val symbolTable: ReferenceSymbolTable = st + final override val annotationsRegistrar: IrAnnotationsFromPluginRegistrar + get() = DummyIrAnnotationsFromPluginRegistrar + private fun resolveMemberScope(fqName: FqName): MemberScope? { val pkg = module.getPackage(fqName) @@ -124,7 +129,6 @@ open class IrPluginContextImpl constructor( @OptIn(FirIncompatiblePluginAPI::class) override fun referenceConstructors(classFqn: FqName): Collection { - @Suppress("DEPRECATION") val classSymbol = referenceClass(classFqn) ?: error("Cannot find class $classFqn") return classSymbol.owner.declarations.filterIsInstance().map { it.symbol } } @@ -176,4 +180,10 @@ open class IrPluginContextImpl constructor( linker.postProcess(inOrAfterLinkageStep = false) return symbol } + + private object DummyIrAnnotationsFromPluginRegistrar : IrAnnotationsFromPluginRegistrar() { + override fun addMetadataVisibleAnnotationsToElement(declaration: IrDeclaration, annotations: List) { + declaration.annotations += annotations + } + } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt index f017b896cfe..0ab04ef4ca6 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrJsResultsConverter.kt @@ -146,7 +146,8 @@ class Fir2IrJsResultsConverter( FirKLibSerializerExtension( components.session, metadataVersion, ConstValueProviderImpl(components), - allowErrorTypes = false, exportKDoc = false + allowErrorTypes = false, exportKDoc = false, + components.annotationsFromPluginRegistrar.createMetadataAnnotationsProvider() ), configuration.languageVersionSettings, ) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt index 82b5d5d2572..2c5b174b6a4 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FirNativeSerializer.kt @@ -85,7 +85,9 @@ internal fun PhaseContext.firSerializerBase( fir2IrInput?.let { ConstValueProviderImpl(fir2IrInput.components) }, - allowErrorTypes = false, exportKDoc = shouldExportKDoc() + allowErrorTypes = false, + exportKDoc = shouldExportKDoc(), + additionalAnnotationsProvider = fir2IrInput?.components?.annotationsFromPluginRegistrar?.createMetadataAnnotationsProvider() ), configuration.languageVersionSettings, ) diff --git a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt index 945f5e0f1e8..34b4d5d4752 100644 --- a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt +++ b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/ir/plugin/TransformerForAddingAnnotations.kt @@ -67,7 +67,7 @@ class TransformerForAddingAnnotations(val context: IrPluginContext) : IrElementV type = annotationClass.defaultType, constructorSymbol = annotationConstructor.symbol ) - declaration.annotations += annotationCall + context.annotationsRegistrar.addMetadataVisibleAnnotationsToElement(declaration, annotationCall) } } } diff --git a/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt index 88f3ff6e420..4f9fe62e554 100644 --- a/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt +++ b/plugins/fir-plugin-prototype/testData/firLoadK2Compiled/annotationsGeneratedInBackend.fir.k2.klib.txt @@ -1,13 +1,13 @@ -@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() public final class Some : R|kotlin/Any| { - public final fun foo(): R|kotlin/Unit| +@R|org/jetbrains/kotlin/fir/plugin/AddAnnotations|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final class Some : R|kotlin/Any| { + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final fun foo(): R|kotlin/Unit| - public final val x: R|kotlin/Int| - public get(): R|kotlin/Int| + @PROPERTY:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final val x: R|kotlin/Int| + @PROPERTY_GETTER:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY_GETTER:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY_GETTER:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY_GETTER:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @PROPERTY_GETTER:R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public get(): R|kotlin/Int| - public constructor(x: R|kotlin/Int|): R|test/Some| + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public constructor(@R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() x: R|kotlin/Int|): R|test/Some| - public final class Derived : R|kotlin/Any| { - public constructor(): R|test/Some.Derived| + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public final class Derived : R|kotlin/Any| { + @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() @R|org/jetbrains/kotlin/fir/plugin/AnnotationToAdd|() public constructor(): R|test/Some.Derived| }