diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 02ed8a7c2a3..655ad5be1df 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -467,6 +467,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/annotations/instances/multifileEqHc.kt"); } + @Test + @TestMetadata("multimoduleCreation.kt") + public void testMultimoduleCreation() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/multimoduleCreation.kt"); + } + @Test @TestMetadata("multimoduleInlining.kt") public void testMultimoduleInlining() throws Exception { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt index da058f0e04e..70ed2be12f5 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt @@ -80,17 +80,20 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko } } - override fun visitClassLiteral(name: Name, value: ClassLiteralValue) { + override fun visitClassLiteral(name: Name?, value: ClassLiteralValue) { + if (name == null) return argumentMap[name] = buildGetClassCall { argumentList = buildUnaryArgumentList(value.toFirClassReferenceExpression()) } } - override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) { + override fun visitEnum(name: Name?, enumClassId: ClassId, enumEntryName: Name) { + if (name == null) return argumentMap[name] = enumClassId.toEnumEntryReferenceExpression(enumEntryName) } - override fun visitArray(name: Name): KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor { + override fun visitArray(name: Name?): KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor? { + if (name == null) return null return object : KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor { private val elements = mutableListOf() @@ -131,7 +134,8 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko } } - override fun visitAnnotation(name: Name, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor { + override fun visitAnnotation(name: Name?, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + if (name == null) return null val list = mutableListOf() val visitor = loadAnnotation(classId, list) return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/JvmBinaryAnnotationDeserializer.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/JvmBinaryAnnotationDeserializer.kt index bfc2977e3c7..ada624fad76 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/JvmBinaryAnnotationDeserializer.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/JvmBinaryAnnotationDeserializer.kt @@ -322,6 +322,11 @@ private fun FirSession.loadMemberAnnotations( } return annotationsLoader.loadAnnotationIfNotSpecial(classId, result) } + + override fun visitAnnotationMemberDefaultValue(): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + // TODO: load annotation default values to properly support annotation instantiation feature + return null + } } open inner class MemberAnnotationVisitor(protected val signature: MemberSignature) : KotlinJvmBinaryClass.AnnotationVisitor { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java index 75d1ae89a3e..68649234e73 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java @@ -173,17 +173,18 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { return new org.jetbrains.org.objectweb.asm.AnnotationVisitor(API_VERSION) { @Override public void visit(String name, @NotNull Object value) { + Name identifier = name == null ? null : Name.identifier(name); if (value instanceof Type) { - v.visitClassLiteral(Name.identifier(name), resolveKotlinNameByType((Type) value, innerClasses)); + v.visitClassLiteral(identifier, resolveKotlinNameByType((Type) value, innerClasses)); } else { - v.visit(name == null ? null : Name.identifier(name), value); + v.visit(identifier, value); } } @Override public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitArray(String name) { - AnnotationArrayArgumentVisitor arv = v.visitArray(Name.identifier(name)); + AnnotationArrayArgumentVisitor arv = v.visitArray(name == null ? null : Name.identifier(name)); return arv == null ? null : new org.jetbrains.org.objectweb.asm.AnnotationVisitor(API_VERSION) { @Override public void visit(String name, @NotNull Object value) { @@ -215,13 +216,14 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { @Override public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitAnnotation(String name, @NotNull String desc) { - AnnotationArgumentVisitor arv = v.visitAnnotation(Name.identifier(name), resolveNameByDesc(desc, innerClasses)); + AnnotationArgumentVisitor arv = + v.visitAnnotation(name == null ? null : Name.identifier(name), resolveNameByDesc(desc, innerClasses)); return arv == null ? null : convertAnnotationVisitor(arv, innerClasses); } @Override public void visitEnum(String name, @NotNull String desc, @NotNull String value) { - v.visitEnum(Name.identifier(name), resolveNameByDesc(desc, innerClasses), Name.identifier(value)); + v.visitEnum(name == null ? null : Name.identifier(name), resolveNameByDesc(desc, innerClasses), Name.identifier(value)); } @Override @@ -269,6 +271,12 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { return convertAnnotationVisitor(v, desc, innerClasses); } + @Override + public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitAnnotationDefault() { + AnnotationArgumentVisitor av = v.visitAnnotationMemberDefaultValue(); + return av == null ? null : convertAnnotationVisitor(av, innerClasses); + } + @Override public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitParameterAnnotation(int parameter, @NotNull String desc, boolean visible) { int parameterIndex = parameter + methodParamCount - (visible ? visibleAnnotableParameterCount : invisibleAnnotableParameterCount); diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt index f010998dba0..194c927ec51 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt @@ -15,12 +15,12 @@ import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope import org.jetbrains.kotlin.backend.jvm.ir.javaClassReference import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl @@ -136,11 +136,16 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext, }.also { it.parent = implClass } val parameter = generatedConstructor.addValueParameter(propName.asString(), propType) - // VALUE_FROM_PARAMETER - val originalParameter = ((property.backingField?.initializer?.expression as? IrGetValue)?.symbol?.owner as? IrValueParameter) - if (originalParameter?.defaultValue != null) { - parameter.defaultValue = originalParameter.defaultValue!!.deepCopyWithVariables().also { it.transformChildrenVoid() } - } + + val defaultExpression = property.backingField?.initializer?.expression + val newDefaultValue: IrExpressionBody? = + if (defaultExpression is IrGetValue && defaultExpression.symbol.owner is IrValueParameter) { + // INITIALIZE_PROPERTY_FROM_PARAMETER + (defaultExpression.symbol.owner as IrValueParameter).defaultValue + } else if (defaultExpression != null) { + property.backingField!!.initializer + } else null + parameter.defaultValue = newDefaultValue?.deepCopyWithVariables()?.also { it.transformChildrenVoid() } ctorBody.statements += IrSetFieldImpl( SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, field.symbol, diff --git a/compiler/testData/codegen/box/annotations/instances/multimoduleCreation.kt b/compiler/testData/codegen/box/annotations/instances/multimoduleCreation.kt new file mode 100644 index 00000000000..3ffc2a27eb2 --- /dev/null +++ b/compiler/testData/codegen/box/annotations/instances/multimoduleCreation.kt @@ -0,0 +1,66 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM_IR +// IGNORE_DEXING +// WITH_RUNTIME +// !LANGUAGE: +InstantiationOfAnnotationClasses + +// MODULE: lib +// FILE: lib.kt + +package a + +import kotlin.reflect.KClass + +annotation class A(val kClass: KClass<*> = Int::class) + +annotation class OtherArrays( + val doublesArray: DoubleArray = [], + val enumArray: Array = [], + val annotationsArray: Array = [], + val namesArray: Array = [JvmName("foo")] +) + +// Uncomment when KT-49998 is resolved +//annotation class UnsignedValue( +// val uint: UInt = 2147483657U // Int.MAX_VALUE + 10 +//) + +// MODULE: app(lib) +// FILE: app.kt + +// kotlin.Metadata: IntArray, Array +// kotlin.Deprecated: Nested annotation, enum instance +// a.A: KClass +// a.OtherArrays: Arrays of enums and other annotations + +package test + +import a.* +import kotlin.test.* + +class C { + fun one(): A = A() + fun two(): Metadata = Metadata() + fun three(): Deprecated = Deprecated("foo") + fun four(): OtherArrays = OtherArrays() +// fun five(): UnsignedValue = UnsignedValue() +} + +fun box(): String { + val a = C().one() + assertEquals(Int::class, a.kClass) + assertEquals( + """@kotlin.Metadata(bytecodeVersion=[1, 0, 3], data1=[], data2=[], extraInt=0, extraString=, kind=1, metadataVersion=[], packageName=)""", + C().two().toString() + ) + assertEquals( + """@kotlin.Deprecated(level=WARNING, message=foo, replaceWith=@kotlin.ReplaceWith(expression=, imports=[]))""", + C().three().toString() + ) + assertEquals( + """@a.OtherArrays(annotationsArray=[], doublesArray=[], enumArray=[], namesArray=[@kotlin.jvm.JvmName(name=foo)])""", + C().four().toString() + ) +// assertEquals(Int.MAX_VALUE.toUInt() + 10.toUInt(), C().five().uint) + return "OK" +} diff --git a/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.kt b/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.kt index 02061bacb02..11d3dd45b4e 100644 --- a/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.kt +++ b/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.kt @@ -1,4 +1,6 @@ // ALLOW_AST_ACCESS +// NO_CHECK_SOURCE_VS_BINARY +//^ While compiling source, we do not store annotation default values, but we load them when reading compiled files package test annotation class Anno(val value: String = "0", val x: Int = 0) diff --git a/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.txt b/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.txt index d9b81945c4e..ca6dc47a962 100644 --- a/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.txt +++ b/compiler/testData/loadJava/compiledKotlin/annotations/classMembers/EnumEntry.txt @@ -2,9 +2,9 @@ package test public final annotation class Anno : kotlin.Annotation { /*primary*/ public constructor Anno(/*0*/ value: kotlin.String = ..., /*1*/ x: kotlin.Int = ...) - public final val value: kotlin.String + public final val value: kotlin.String = "0" public final fun (): kotlin.String - public final val x: kotlin.Int + public final val x: kotlin.Int = 0 public final fun (): kotlin.Int } diff --git a/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.kt b/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.kt index 3b74a0843c0..38ebc070f9d 100644 --- a/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.kt +++ b/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.kt @@ -1,4 +1,6 @@ //ALLOW_AST_ACCESS +// NO_CHECK_SOURCE_VS_BINARY +//^ While compiling source, we do not store annotation default values, but we load them when reading compiled files package test @Target(AnnotationTarget.TYPEALIAS) diff --git a/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.txt b/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.txt index e989be45cef..6244848433e 100644 --- a/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.txt +++ b/compiler/testData/loadJava/compiledKotlin/typealias/Annotations.txt @@ -2,7 +2,7 @@ package test @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPEALIAS}) public final annotation class Ann : kotlin.Annotation { /*primary*/ public constructor Ann(/*0*/ value: kotlin.String = ...) - public final val value: kotlin.String + public final val value: kotlin.String = "" public final fun (): kotlin.String } @test.Ann public typealias A1 = kotlin.String diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 7ecd8808b8d..9d7405619d7 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -467,6 +467,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/annotations/instances/multifileEqHc.kt"); } + @Test + @TestMetadata("multimoduleCreation.kt") + public void testMultimoduleCreation() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/multimoduleCreation.kt"); + } + @Test @TestMetadata("multimoduleInlining.kt") public void testMultimoduleInlining() throws Exception { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt index 7dfd5fd9f22..fdffe8b653e 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.serialization.deserialization.AnnotationAndConstantL import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.KotlinType -import java.util.* abstract class AbstractBinaryClassAnnotationAndConstantLoader( storageManager: StorageManager, @@ -48,6 +47,12 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( protected abstract fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): A + protected abstract fun loadAnnotationMethodDefaultValue( + annotationClass: KotlinJvmBinaryClass, + methodSignature: MemberSignature, + visitResult: (C) -> Unit + ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? + private fun loadAnnotationIfNotSpecial( annotationClassId: ClassId, source: SourceElement, @@ -210,7 +215,30 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( return proto.getExtension(JvmProtoBuf.typeParameterAnnotation).map { loadTypeAnnotation(it, nameResolver) } } + override fun loadAnnotationDefaultValue( + container: ProtoContainer, + proto: ProtoBuf.Property, + expectedType: KotlinType + ): C? { + return loadConstantFromProperty( + container, + proto, + AnnotatedCallableKind.PROPERTY_GETTER, + expectedType + ) { annotationParametersDefaultValues[it] } + } + override fun loadPropertyConstant(container: ProtoContainer, proto: ProtoBuf.Property, expectedType: KotlinType): C? { + return loadConstantFromProperty(container, proto, AnnotatedCallableKind.PROPERTY, expectedType) { propertyConstants[it] } + } + + private fun loadConstantFromProperty( + container: ProtoContainer, + proto: ProtoBuf.Property, + annotatedCallableKind: AnnotatedCallableKind, + expectedType: KotlinType, + loader: Storage.(MemberSignature) -> C? + ): C? { val specialCase = getSpecialCaseContainerClass( container, property = true, @@ -225,11 +253,11 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( ) val signature = getCallableSignature( - proto, container.nameResolver, container.typeTable, AnnotatedCallableKind.PROPERTY, requireHasFieldFlag + proto, container.nameResolver, container.typeTable, annotatedCallableKind, requireHasFieldFlag ) ?: return null - val constant = storage(kotlinClass).propertyConstants[signature] ?: return null - return if (UnsignedTypes.isUnsignedType(expectedType)) transformToUnsignedConstant(constant) else constant + val result = storage(kotlinClass).loader(signature) ?: return null + return if (UnsignedTypes.isUnsignedType(expectedType)) transformToUnsignedConstant(result) else result } private fun findClassWithAnnotationsAndInitializers( @@ -291,6 +319,7 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( private fun loadAnnotationsAndInitializers(kotlinClass: KotlinJvmBinaryClass): Storage { val memberAnnotations = HashMap>() val propertyConstants = HashMap() + val annotationParametersDefaultValues = HashMap() kotlinClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor { override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? { @@ -323,6 +352,12 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( } return loadAnnotationIfNotSpecial(classId, source, result) } + + override fun visitAnnotationMemberDefaultValue(): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + return loadAnnotationMethodDefaultValue(kotlinClass, signature) { + annotationParametersDefaultValues[signature] = it + } + } } open inner class MemberAnnotationVisitor(protected val signature: MemberSignature) : KotlinJvmBinaryClass.AnnotationVisitor { @@ -340,7 +375,7 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( } }, getCachedFileContent(kotlinClass)) - return Storage(memberAnnotations, propertyConstants) + return Storage(memberAnnotations, propertyConstants, annotationParametersDefaultValues) } private fun getPropertySignature( @@ -415,6 +450,7 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( private class Storage( val memberAnnotations: Map>, - val propertyConstants: Map + val propertyConstants: Map, + val annotationParametersDefaultValues: Map ) } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt index c8e4c41da32..ddb60d4a250 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt @@ -14,9 +14,13 @@ import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.NameResolver import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.constants.* +import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.serialization.deserialization.AnnotationDeserializer import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.compact class BinaryClassAnnotationAndConstantLoaderImpl( @@ -66,73 +70,24 @@ class BinaryClassAnnotationAndConstantLoaderImpl( ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { val annotationClass = resolveClass(annotationClassId) - return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor { + return object : AbstractAnnotationArgumentVisitor() { private val arguments = HashMap>() - override fun visit(name: Name?, value: Any?) { - if (name != null) { - arguments[name] = createConstant(name, value) - } + override fun visitConstantValue(name: Name?, value: ConstantValue<*>) { + if (name != null) arguments[name] = value } - override fun visitClassLiteral(name: Name, value: ClassLiteralValue) { - arguments[name] = KClassValue(value) - } - - override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) { - arguments[name] = EnumValue(enumClassId, enumEntryName) - } - - override fun visitArray(name: Name): AnnotationArrayArgumentVisitor? { - return object : AnnotationArrayArgumentVisitor { - private val elements = ArrayList>() - - override fun visit(value: Any?) { - elements.add(createConstant(name, value)) - } - - override fun visitEnum(enumClassId: ClassId, enumEntryName: Name) { - elements.add(EnumValue(enumClassId, enumEntryName)) - } - - override fun visitClassLiteral(value: ClassLiteralValue) { - elements.add(KClassValue(value)) - } - - override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { - val list = ArrayList() - val visitor = loadAnnotation(classId, SourceElement.NO_SOURCE, list)!! - return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor { - override fun visitEnd() { - visitor.visitEnd() - elements.add(AnnotationValue(list.single())) - } - } - } - - override fun visitEnd() { - val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) - if (parameter != null) { - arguments[name] = ConstantValueFactory.createArrayValue(elements.compact(), parameter.type) - } else if (isImplicitRepeatableContainer(annotationClassId) && name.asString() == "value") { - // In case this is an implicit repeatable annotation container, its class descriptor can't be resolved by the - // frontend, so we'd like to flatten its value and add repeated annotations to the list. - // E.g. if we see `@Foo.Container(@Foo(1), @Foo(2))` in the bytecode on some declaration where `Foo` is some - // Kotlin-repeatable annotation, we want to read annotations on that declaration as a list `[@Foo(1), @Foo(2)]`. - elements.filterIsInstance().mapTo(result, AnnotationValue::value) - } - } - } - } - - override fun visitAnnotation(name: Name, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { - val list = ArrayList() - val visitor = loadAnnotation(classId, SourceElement.NO_SOURCE, list)!! - return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor { - override fun visitEnd() { - visitor.visitEnd() - arguments[name] = AnnotationValue(list.single()) - } + override fun visitArrayValue(name: Name?, elements: ArrayList>) { + if (name == null) return + val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) + if (parameter != null) { + arguments[name] = ConstantValueFactory.createArrayValue(elements.compact(), parameter.type) + } else if (isImplicitRepeatableContainer(annotationClassId) && name.asString() == "value") { + // In case this is an implicit repeatable annotation container, its class descriptor can't be resolved by the + // frontend, so we'd like to flatten its value and add repeated annotations to the list. + // E.g. if we see `@Foo.Container(@Foo(1), @Foo(2))` in the bytecode on some declaration where `Foo` is some + // Kotlin-repeatable annotation, we want to read annotations on that declaration as a list `[@Foo(1), @Foo(2)]`. + elements.filterIsInstance().mapTo(result, AnnotationValue::value) } } @@ -148,14 +103,123 @@ class BinaryClassAnnotationAndConstantLoaderImpl( result.add(AnnotationDescriptorImpl(annotationClass.defaultType, arguments, source)) } + } + } - private fun createConstant(name: Name?, value: Any?): ConstantValue<*> { - return ConstantValueFactory.createConstantValue(value) - ?: ErrorValue.create("Unsupported annotation argument: $name") + override fun loadAnnotationMethodDefaultValue( + annotationClass: KotlinJvmBinaryClass, + methodSignature: MemberSignature, + visitResult: (ConstantValue<*>) -> Unit + ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + return object : AbstractAnnotationArgumentVisitor() { + private var defaultValue: ConstantValue<*>? = null + + override fun visitConstantValue(name: Name?, value: ConstantValue<*>) { + defaultValue = value + } + + override fun visitArrayValue(name: Name?, elements: ArrayList>) { + defaultValue = ArrayValue(elements.compact()) { moduleDescriptor -> + guessArrayType(moduleDescriptor) + } + } + + override fun visitEnd() { + defaultValue?.let(visitResult) + } + + private fun guessArrayType( + moduleDescriptor: ModuleDescriptor + ): KotlinType { + val elementDesc = methodSignature.signature.substringAfterLast(')').removePrefix("[") + // Some fast-path guesses + JvmPrimitiveType.getByDesc(elementDesc) + ?.let { return moduleDescriptor.builtIns.getPrimitiveArrayKotlinType(it.primitiveType) } + if (elementDesc == "Ljava/lang/String;") return moduleDescriptor.builtIns.getArrayType( + Variance.INVARIANT, + moduleDescriptor.builtIns.stringType + ) + // Slow path resolving @JvmName + val propertiesNames = moduleDescriptor.findNonGenericClassAcrossDependencies(annotationClass.classId, notFoundClasses) + .unsubstitutedMemberScope.getContributedDescriptors().filterIsInstance() + .filter { prop -> + val name = prop.getter?.let { DescriptorUtils.getJvmName(it) ?: prop.name.asString() } + name == methodSignature.signature.substringBefore('(') + } + val requiredProp = propertiesNames.singleOrNull() + ?: error("Signature ${methodSignature.signature} does not belong to class ${annotationClass.classId} or multiple duplicates found") + return requiredProp.type } } } + private abstract inner class AbstractAnnotationArgumentVisitor : KotlinJvmBinaryClass.AnnotationArgumentVisitor { + abstract fun visitConstantValue(name: Name?, value: ConstantValue<*>) + abstract override fun visitEnd() + abstract fun visitArrayValue(name: Name?, elements: ArrayList>) + + override fun visit(name: Name?, value: Any?) { + visitConstantValue(name, createConstant(name, value)) + } + + override fun visitClassLiteral(name: Name?, value: ClassLiteralValue) { + visitConstantValue(name, KClassValue(value)) + } + + override fun visitEnum(name: Name?, enumClassId: ClassId, enumEntryName: Name) { + visitConstantValue(name, EnumValue(enumClassId, enumEntryName)) + } + + override fun visitArray(name: Name?): AnnotationArrayArgumentVisitor? { + return object : AnnotationArrayArgumentVisitor { + private val elements = ArrayList>() + + override fun visit(value: Any?) { + elements.add(createConstant(name, value)) + } + + override fun visitEnum(enumClassId: ClassId, enumEntryName: Name) { + elements.add(EnumValue(enumClassId, enumEntryName)) + } + + override fun visitClassLiteral(value: ClassLiteralValue) { + elements.add(KClassValue(value)) + } + + override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + val list = ArrayList() + val visitor = loadAnnotation(classId, SourceElement.NO_SOURCE, list)!! + return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor { + override fun visitEnd() { + visitor.visitEnd() + elements.add(AnnotationValue(list.single())) + } + } + } + + override fun visitEnd() { + visitArrayValue(name, elements) + } + } + } + + override fun visitAnnotation(name: Name?, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + val list = ArrayList() + val visitor = loadAnnotation(classId, SourceElement.NO_SOURCE, list)!! + return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor { + override fun visitEnd() { + visitor.visitEnd() + visitConstantValue(name, AnnotationValue(list.single())) + } + } + } + } + + private fun createConstant(name: Name?, value: Any?): ConstantValue<*> { + return ConstantValueFactory.createConstantValue(value) + ?: ErrorValue.create("Unsupported annotation argument: $name") + } + private fun resolveClass(classId: ClassId): ClassDescriptor { return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses) } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java index f79ea59f7a6..e8ed6294175 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java @@ -168,13 +168,13 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } @Override - public void visitClassLiteral(@NotNull Name name, @NotNull ClassLiteralValue classLiteralValue) { + public void visitClassLiteral(@Nullable Name name, @NotNull ClassLiteralValue classLiteralValue) { } @Override @Nullable - public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) { - String string = name.asString(); + public AnnotationArrayArgumentVisitor visitArray(@Nullable Name name) { + String string = name != null ? name.asString() : null; if (METADATA_DATA_FIELD_NAME.equals(string)) { return dataArrayVisitor(); } @@ -207,12 +207,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } @Override - public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) { + public void visitEnum(@Nullable Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) { } @Nullable @Override - public AnnotationArgumentVisitor visitAnnotation(@NotNull Name name, @NotNull ClassId classId) { + public AnnotationArgumentVisitor visitAnnotation(@Nullable Name name, @NotNull ClassId classId) { return null; } @@ -238,13 +238,13 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } @Override - public void visitClassLiteral(@NotNull Name name, @NotNull ClassLiteralValue classLiteralValue) { + public void visitClassLiteral(@Nullable Name name, @NotNull ClassLiteralValue classLiteralValue) { } @Override @Nullable - public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) { - String string = name.asString(); + public AnnotationArrayArgumentVisitor visitArray(@Nullable Name name) { + String string = name != null ? name.asString() : null; if ("data".equals(string) || "filePartClassNames".equals(string)) { return dataArrayVisitor(); } @@ -277,12 +277,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } @Override - public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) { + public void visitEnum(@Nullable Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) { } @Nullable @Override - public AnnotationArgumentVisitor visitAnnotation(@NotNull Name name, @NotNull ClassId classId) { + public AnnotationArgumentVisitor visitAnnotation(@Nullable Name name, @NotNull ClassId classId) { return null; } @@ -297,13 +297,13 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } @Override - public void visitClassLiteral(@NotNull Name name, @NotNull ClassLiteralValue classLiteralValue) { + public void visitClassLiteral(@Nullable Name name, @NotNull ClassLiteralValue classLiteralValue) { } @Override @Nullable - public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) { - String string = name.asString(); + public AnnotationArrayArgumentVisitor visitArray(@Nullable Name name) { + String string = name != null ? name.asString() : null; if (SERIALIZED_IR_BYTES_FIELD_NAME.equals(string)) { return serializedIrArrayVisitor(); } @@ -323,12 +323,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } @Override - public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) { + public void visitEnum(@Nullable Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) { } @Nullable @Override - public AnnotationArgumentVisitor visitAnnotation(@NotNull Name name, @NotNull ClassId classId) { + public AnnotationArgumentVisitor visitAnnotation(@Nullable Name name, @NotNull ClassId classId) { return null; } diff --git a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt index 059ddfbe7a4..9b5217e178a 100644 --- a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt +++ b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt @@ -44,18 +44,20 @@ interface KotlinJvmBinaryClass { interface MethodAnnotationVisitor : AnnotationVisitor { fun visitParameterAnnotation(index: Int, classId: ClassId, source: SourceElement): AnnotationArgumentVisitor? + + fun visitAnnotationMemberDefaultValue(): AnnotationArgumentVisitor? } interface AnnotationArgumentVisitor { fun visit(name: Name?, value: Any?) - fun visitClassLiteral(name: Name, value: ClassLiteralValue) + fun visitClassLiteral(name: Name?, value: ClassLiteralValue) - fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) + fun visitEnum(name: Name?, enumClassId: ClassId, enumEntryName: Name) - fun visitAnnotation(name: Name, classId: ClassId): AnnotationArgumentVisitor? + fun visitAnnotation(name: Name?, classId: ClassId): AnnotationArgumentVisitor? - fun visitArray(name: Name): AnnotationArrayArgumentVisitor? + fun visitArray(name: Name?): AnnotationArrayArgumentVisitor? fun visitEnd() } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoader.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoader.kt index 04df924de52..b86a40f74a5 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoader.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoader.kt @@ -78,4 +78,10 @@ interface AnnotationAndConstantLoader { proto: ProtoBuf.Property, expectedType: KotlinType ): C? + + fun loadAnnotationDefaultValue( + container: ProtoContainer, + proto: ProtoBuf.Property, + expectedType: KotlinType + ): C? } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoaderImpl.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoaderImpl.kt index f313308b2fb..b0e71ae3783 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoaderImpl.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationAndConstantLoaderImpl.kt @@ -104,4 +104,13 @@ class AnnotationAndConstantLoaderImpl( val value = proto.getExtensionOrNull(protocol.compileTimeValue) ?: return null return deserializer.resolveValue(expectedType, value, container.nameResolver) } + + override fun loadAnnotationDefaultValue( + container: ProtoContainer, + proto: ProtoBuf.Property, + expectedType: KotlinType + ): ConstantValue<*>? { + // Implement this method to properly support Annotations Instantiation feature + return null + } } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt index 1d021df57b2..c2e1a0a70fe 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt @@ -140,6 +140,15 @@ class MemberDeserializer(private val c: DeserializationContext) { ) } + if ((c.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.ANNOTATION_CLASS) { + property.setCompileTimeInitializer( + c.storageManager.createNullableLazyValue { + val container = c.containingDeclaration.asProtoContainer()!! + c.components.annotationAndConstantLoader.loadAnnotationDefaultValue(container, proto, property.returnType) + } + ) + } + property.initialize( getter, setter, FieldDescriptorImpl(getPropertyFieldAnnotations(proto, isDelegate = false), property),