[FIR/IR] Introduce an ability to propagate generated IR annotation to metadata

^KT-58638 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-05-30 13:05:17 +03:00
committed by Space Team
parent 24e07fdfe0
commit 5717b59f52
21 changed files with 222 additions and 27 deletions
@@ -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<FirAnnotation>
abstract fun hasGeneratedAnnotationsFor(declaration: FirDeclaration): Boolean
}
@@ -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!!),
@@ -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
@@ -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 <T> 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<FirAnnotation> {
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")
}
}
@@ -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<FirAnnotation>()
val delegatePropertyAnnotations = mutableListOf<FirAnnotation>()
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<MessageType, List<ProtoBuf.Annotation>>?
) {
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<FirAnnotation> {
val nonSourceAnnotations = nonSourceAnnotations(session)
val additionalMetadataAnnotationsProvider = additionalAnnotationsProvider
return if (this is FirDeclaration && additionalMetadataAnnotationsProvider != null) {
nonSourceAnnotations + additionalMetadataAnnotationsProvider.findGeneratedAnnotationsFor(this)
} else {
nonSourceAnnotations
}
}
}