FIR deserializer: signature-aware annotation loading for functions

This commit is contained in:
Jinseong Jeon
2020-06-11 12:56:49 -07:00
committed by Denis Zharkov
parent 11a680d7d8
commit b076bec07f
32 changed files with 68 additions and 42 deletions
@@ -1,5 +1,5 @@
public open class AnnotatedMethod : R|kotlin/Any| { public open class AnnotatedMethod : R|kotlin/Any| {
public open fun f(): R|kotlin/Unit| @R|kotlin/Deprecated|(message = String(Deprecated in Java)) public open fun f(): R|kotlin/Unit|
public constructor(): R|test/AnnotatedMethod| public constructor(): R|test/AnnotatedMethod|
@@ -19,7 +19,7 @@ public final annotation class EnumAnno : R|kotlin/Annotation| {
} }
public final class EnumArgumentWithCustomToString : R|kotlin/Any| { public final class EnumArgumentWithCustomToString : R|kotlin/Any| {
public final fun annotated(): R|kotlin/Unit| @R|test/EnumAnno|(value = R|test/E.CAKE|()) @R|test/EnumArrayAnno|(value = <implicitArrayOf>(R|test/E.CAKE|(), R|test/E.CAKE|())) public final fun annotated(): R|kotlin/Unit|
public constructor(): R|test/EnumArgumentWithCustomToString| public constructor(): R|test/EnumArgumentWithCustomToString|
@@ -7,7 +7,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
} }
public abstract interface T : R|kotlin/Any| { public abstract interface T : R|kotlin/Any| {
public abstract fun foo(): R|kotlin/Array<kotlin/Array<kotlin/Array<test/T>>>| @R|test/Anno|(s = String(foo)) public abstract fun foo(): R|kotlin/Array<kotlin/Array<kotlin/Array<test/T>>>|
public abstract val bar: R|kotlin/Array<kotlin/Array<kotlin/BooleanArray>>| public abstract val bar: R|kotlin/Array<kotlin/Array<kotlin/BooleanArray>>|
public get(): R|kotlin/Array<kotlin/Array<kotlin/BooleanArray>>| public get(): R|kotlin/Array<kotlin/Array<kotlin/BooleanArray>>|
@@ -7,7 +7,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
} }
public final class Class : R|kotlin/Any| { public final class Class : R|kotlin/Any| {
public final fun foo(): R|kotlin/Unit| @R|test/Anno|(t = R|java/lang/annotation/ElementType.METHOD|()) public final fun foo(): R|kotlin/Unit|
public final var bar: R|kotlin/Int| public final var bar: R|kotlin/Int|
public get(): R|kotlin/Int| public get(): R|kotlin/Int|
@@ -4,7 +4,7 @@ public final annotation class Anno : R|kotlin/Annotation| {
} }
public final class Class : R|kotlin/Any| { public final class Class : R|kotlin/Any| {
public final fun foo(): R|kotlin/Unit| @R|test/Anno|() public final fun foo(): R|kotlin/Unit|
public constructor(): R|test/Class| public constructor(): R|test/Class|
@@ -9,7 +9,7 @@ public final class A : R|kotlin/Any| {
} }
@R|test/A.Anno|() public final class B : R|kotlin/Any| { @R|test/A.Anno|() public final class B : R|kotlin/Any| {
public final fun f(): R|kotlin/Unit| @R|test/A.Anno|() public final fun f(): R|kotlin/Unit|
public constructor(): R|test/B| public constructor(): R|test/B|
@@ -1,4 +1,4 @@
public final fun foo(): R|kotlin/Unit| @R|test/Anno|(t = R|java/lang/annotation/ElementType.METHOD|()) public final fun foo(): R|kotlin/Unit|
public final annotation class Anno : R|kotlin/Annotation| { public final annotation class Anno : R|kotlin/Annotation| {
public final val t: R|java/lang/annotation/ElementType| public final val t: R|java/lang/annotation/ElementType|
@@ -1,6 +1,6 @@
public final fun baz(): R|kotlin/Unit| @R|test/Anno|(t = <implicitArrayOf>()) public final fun baz(): R|kotlin/Unit|
public final fun foo(): R|kotlin/Unit| @R|test/Anno|(t = <implicitArrayOf>(R|java/lang/annotation/ElementType.METHOD|(), R|java/lang/annotation/ElementType.FIELD|())) public final fun foo(): R|kotlin/Unit|
public final annotation class Anno : R|kotlin/Annotation| { public final annotation class Anno : R|kotlin/Annotation| {
public final val t: R|kotlin/Array<out java/lang/annotation/ElementType>| public final val t: R|kotlin/Array<out java/lang/annotation/ElementType>|
@@ -1,4 +1,4 @@
public final fun function(): R|kotlin/Unit| @R|test/Anno|() public final fun function(): R|kotlin/Unit|
public final annotation class Anno : R|kotlin/Annotation| { public final annotation class Anno : R|kotlin/Annotation| {
public constructor(): R|test/Anno| public constructor(): R|test/Anno|
@@ -1,6 +1,6 @@
public final fun baz(): R|kotlin/Unit| @R|test/Anno|(t = <implicitArrayOf>()) public final fun baz(): R|kotlin/Unit|
public final fun foo(): R|kotlin/Unit| @R|test/Anno|(t = <implicitArrayOf>(String(live), String(long))) public final fun foo(): R|kotlin/Unit|
public final annotation class Anno : R|kotlin/Annotation| { public final annotation class Anno : R|kotlin/Annotation| {
public final val t: R|kotlin/Array<out kotlin/String>| public final val t: R|kotlin/Array<out kotlin/String>|
@@ -17,8 +17,10 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.load.kotlin.MemberSignature import org.jetbrains.kotlin.load.kotlin.MemberSignature
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.protobuf.MessageLite
@@ -33,6 +35,7 @@ class JvmBinaryAnnotationDeserializer(
private data class MemberAnnotations(val memberAnnotations: Map<MemberSignature, MutableList<FirAnnotationCall>>) private data class MemberAnnotations(val memberAnnotations: Map<MemberSignature, MutableList<FirAnnotationCall>>)
private enum class CallableKind { private enum class CallableKind {
FUNCTION,
PROPERTY_GETTER, PROPERTY_GETTER,
PROPERTY_SETTER PROPERTY_SETTER
} }
@@ -42,36 +45,55 @@ class JvmBinaryAnnotationDeserializer(
return annotations.map { deserializeAnnotation(it, nameResolver) } return annotations.map { deserializeAnnotation(it, nameResolver) }
} }
override fun loadFunctionAnnotations(
containerSource: DeserializedContainerSource?,
functionProto: ProtoBuf.Function,
nameResolver: NameResolver,
typeTable: TypeTable
): List<FirAnnotationCall> {
val signature = getCallableSignature(functionProto, nameResolver, typeTable, CallableKind.FUNCTION) ?: return emptyList()
return findJvmBinaryClassAndLoadMemberAnnotations(containerSource, signature)
}
override fun loadPropertyGetterAnnotations( override fun loadPropertyGetterAnnotations(
containerSource: DeserializedContainerSource?, containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property, propertyProto: ProtoBuf.Property,
nameResolver: NameResolver, nameResolver: NameResolver,
typeTable: TypeTable,
getterFlags: Int getterFlags: Int
): List<FirAnnotationCall> { ): List<FirAnnotationCall> {
val signature = getCallableSignature(propertyProto, nameResolver, CallableKind.PROPERTY_GETTER) ?: return emptyList() val signature = getCallableSignature(propertyProto, nameResolver, typeTable, CallableKind.PROPERTY_GETTER) ?: return emptyList()
val kotlinClass = containerSource?.toKotlinJvmBinaryClass() ?: return emptyList() return findJvmBinaryClassAndLoadMemberAnnotations(containerSource, signature)
return loadMemberAnnotations(kotlinClass).memberAnnotations[signature] ?: emptyList()
} }
override fun loadPropertySetterAnnotations( override fun loadPropertySetterAnnotations(
containerSource: DeserializedContainerSource?, containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property, propertyProto: ProtoBuf.Property,
nameResolver: NameResolver, nameResolver: NameResolver,
typeTable: TypeTable,
setterFlags: Int setterFlags: Int
): List<FirAnnotationCall> { ): List<FirAnnotationCall> {
val signature = getCallableSignature(propertyProto, nameResolver, CallableKind.PROPERTY_SETTER) ?: return emptyList() val signature = getCallableSignature(propertyProto, nameResolver, typeTable, CallableKind.PROPERTY_SETTER) ?: return emptyList()
val kotlinClass = containerSource?.toKotlinJvmBinaryClass() ?: return emptyList() return findJvmBinaryClassAndLoadMemberAnnotations(containerSource, signature)
return loadMemberAnnotations(kotlinClass).memberAnnotations[signature] ?: emptyList()
} }
private fun getCallableSignature( private fun getCallableSignature(
proto: MessageLite, proto: MessageLite,
nameResolver: NameResolver, nameResolver: NameResolver,
typeTable: TypeTable,
kind: CallableKind kind: CallableKind
): MemberSignature? { ): MemberSignature? {
return when (proto) { return when (proto) {
// TODO: ProtoBuf.Constructor // TODO: ProtoBuf.Constructor
// TODO: ProtoBuf.Function is ProtoBuf.Function -> {
val signature = JvmProtoBufUtil.getJvmMethodSignature(proto, nameResolver, typeTable) ?: return null
// TODO: Investigate why annotations for accessors affect resolution, resulting in dangling type parameter.
// regressions: Fir2IrTextTest.Declarations.test*LevelProperties
if (signature.name.startsWith("get") || signature.name.startsWith("set")) {
return null
}
MemberSignature.fromJvmMemberSignature(signature)
}
is ProtoBuf.Property -> { is ProtoBuf.Property -> {
val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) ?: return null val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) ?: return null
when (kind) { when (kind) {
@@ -80,12 +102,22 @@ class JvmBinaryAnnotationDeserializer(
CallableKind.PROPERTY_SETTER -> CallableKind.PROPERTY_SETTER ->
if (signature.hasSetter()) MemberSignature.fromMethod(nameResolver, signature.setter) else null if (signature.hasSetter()) MemberSignature.fromMethod(nameResolver, signature.setter) else null
// TODO: PROPERTY // TODO: PROPERTY
else ->
null
} }
} }
else -> null else -> null
} }
} }
private fun findJvmBinaryClassAndLoadMemberAnnotations(
containerSource: DeserializedContainerSource?,
memberSignature: MemberSignature
): List<FirAnnotationCall> {
val kotlinClass = containerSource?.toKotlinJvmBinaryClass() ?: return emptyList()
return loadMemberAnnotations(kotlinClass).memberAnnotations[memberSignature] ?: emptyList()
}
private fun DeserializedContainerSource.toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? = private fun DeserializedContainerSource.toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? =
when (this) { when (this) {
is JvmPackagePartSource -> this.knownJvmBinaryClass is JvmPackagePartSource -> this.knownJvmBinaryClass
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value.Type.* import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value.Type.*
import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
import org.jetbrains.kotlin.serialization.deserialization.getClassId import org.jetbrains.kotlin.serialization.deserialization.getClassId
@@ -45,7 +46,12 @@ abstract class AbstractAnnotationDeserializer(
return annotations.map { deserializeAnnotation(it, nameResolver) } return annotations.map { deserializeAnnotation(it, nameResolver) }
} }
fun loadFunctionAnnotations(functionProto: ProtoBuf.Function, nameResolver: NameResolver): List<FirAnnotationCall> { open fun loadFunctionAnnotations(
containerSource: DeserializedContainerSource?,
functionProto: ProtoBuf.Function,
nameResolver: NameResolver,
typeTable: TypeTable
): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(functionProto.flags)) return emptyList() if (!Flags.HAS_ANNOTATIONS.get(functionProto.flags)) return emptyList()
val annotations = functionProto.getExtension(protocol.functionAnnotation).orEmpty() val annotations = functionProto.getExtension(protocol.functionAnnotation).orEmpty()
return annotations.map { deserializeAnnotation(it, nameResolver) } return annotations.map { deserializeAnnotation(it, nameResolver) }
@@ -61,6 +67,7 @@ abstract class AbstractAnnotationDeserializer(
containerSource: DeserializedContainerSource?, containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property, propertyProto: ProtoBuf.Property,
nameResolver: NameResolver, nameResolver: NameResolver,
typeTable: TypeTable,
getterFlags: Int getterFlags: Int
): List<FirAnnotationCall> { ): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(getterFlags)) return emptyList() if (!Flags.HAS_ANNOTATIONS.get(getterFlags)) return emptyList()
@@ -72,6 +79,7 @@ abstract class AbstractAnnotationDeserializer(
containerSource: DeserializedContainerSource?, containerSource: DeserializedContainerSource?,
propertyProto: ProtoBuf.Property, propertyProto: ProtoBuf.Property,
nameResolver: NameResolver, nameResolver: NameResolver,
typeTable: TypeTable,
setterFlags: Int setterFlags: Int
): List<FirAnnotationCall> { ): List<FirAnnotationCall> {
if (!Flags.HAS_ANNOTATIONS.get(setterFlags)) return emptyList() if (!Flags.HAS_ANNOTATIONS.get(setterFlags)) return emptyList()
@@ -196,7 +196,9 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
isGetter = true isGetter = true
status = FirDeclarationStatusImpl(visibility, modality) status = FirDeclarationStatusImpl(visibility, modality)
annotations += annotations +=
c.annotationDeserializer.loadPropertyGetterAnnotations(c.containerSource, proto, local.nameResolver, getterFlags) c.annotationDeserializer.loadPropertyGetterAnnotations(
c.containerSource, proto, local.nameResolver, local.typeTable, getterFlags
)
this.symbol = FirPropertyAccessorSymbol() this.symbol = FirPropertyAccessorSymbol()
} }
} else { } else {
@@ -218,7 +220,9 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
isGetter = false isGetter = false
status = FirDeclarationStatusImpl(visibility, modality) status = FirDeclarationStatusImpl(visibility, modality)
annotations += annotations +=
c.annotationDeserializer.loadPropertySetterAnnotations(c.containerSource, proto, local.nameResolver, setterFlags) c.annotationDeserializer.loadPropertySetterAnnotations(
c.containerSource, proto, local.nameResolver, local.typeTable, setterFlags
)
this.symbol = FirPropertyAccessorSymbol() this.symbol = FirPropertyAccessorSymbol()
valueParameters += proto.setterValueParameter.let { valueParameters += proto.setterValueParameter.let {
val parameterFlags = if (it.hasFlags()) it.flags else 0 val parameterFlags = if (it.hasFlags()) it.flags else 0
@@ -316,7 +320,8 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES
typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir } typeParameters += local.typeDeserializer.ownTypeParameters.map { it.fir }
valueParameters += local.memberDeserializer.valueParameters(proto.valueParameterList) valueParameters += local.memberDeserializer.valueParameters(proto.valueParameterList)
annotations += local.annotationDeserializer.loadFunctionAnnotations(proto, local.nameResolver) annotations +=
c.annotationDeserializer.loadFunctionAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
this.containerSource = c.containerSource this.containerSource = c.containerSource
} }
if (proto.hasContract()) { if (proto.hasContract()) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
fun foo(): Array<Boolean> { fun foo(): Array<Boolean> {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
fun foo(): Array<Boolean> { fun foo(): Array<Boolean> {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by GenerateInRangeExpressionTestData. Do not edit! // Auto-generated by GenerateInRangeExpressionTestData. Do not edit!
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
fun inInt(x: Long): Boolean { fun inInt(x: Long): Boolean {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6 // IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not // TODO: muted automatically, investigate should it be ran for JS or not
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
fun box(): String { fun box(): String {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_REFLECT // WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_REFLECT // WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_REFLECT // WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_REFLECT // WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// WITH_REFLECT // WITH_REFLECT