diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java index f64b2a53581..0c6bdae906e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.config.JvmTarget; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.*; import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; +import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; @@ -346,11 +347,22 @@ public abstract class AnnotationCodegen { } private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) { + ClassDescriptor annotationClass = DescriptorUtilsKt.getAnnotationClass(annotationDescriptor); for (Map.Entry> entry : annotationDescriptor.getAllValueArguments().entrySet()) { - genCompileTimeValue(entry.getKey().asString(), entry.getValue(), annotationVisitor); + genCompileTimeValue(getAnnotationArgumentJvmName(annotationClass, entry.getKey()), entry.getValue(), annotationVisitor); } } + private String getAnnotationArgumentJvmName(@Nullable ClassDescriptor annotationClass, @NotNull Name parameterName) { + if (annotationClass == null) return parameterName.asString(); + + Collection variables = + annotationClass.getUnsubstitutedMemberScope().getContributedVariables(parameterName, NoLookupLocation.FROM_BACKEND); + if (variables.size() != 1) return parameterName.asString(); + + return typeMapper.mapAnnotationParameterName(variables.iterator().next()); + } + private void genCompileTimeValue( @Nullable String name, @NotNull ConstantValue value, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 99836fdf66e..5150464a905 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -55,8 +55,7 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAn import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.DELEGATED_PROPERTIES; import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.DELEGATED_PROPERTY_METADATA_OWNER; -import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.FIELD_FOR_PROPERTY; -import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY; +import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*; import static org.jetbrains.kotlin.diagnostics.Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface; @@ -278,6 +277,7 @@ public class PropertyCodegen { PropertyGetterDescriptor getter = descriptor.getGetter(); assert getter != null : "Annotation property should have a getter: " + descriptor; + v.getSerializationBindings().put(METHOD_FOR_FUNCTION, getter, asmMethod); FunctionCodegen.generateMethodAnnotations(getter, asmMethod, mv, memberCodegen, typeMapper); KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index 1ed2860a91f..f4e9b40e8e8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -489,7 +489,13 @@ public class KotlinTypeMapper { sw.writeReturnType(); mapType(descriptor.getType(), sw, TypeMappingMode.VALUE_FOR_ANNOTATION); sw.writeReturnTypeEnd(); - return sw.makeJvmMethodSignature(descriptor.getName().asString()); + return sw.makeJvmMethodSignature(mapAnnotationParameterName(descriptor)); + } + + @NotNull + public String mapAnnotationParameterName(@NotNull PropertyDescriptor descriptor) { + PropertyGetterDescriptor getter = descriptor.getGetter(); + return getter != null ? mapFunctionName(getter, OwnerKind.IMPLEMENTATION) : descriptor.getName().asString(); } @NotNull diff --git a/compiler/testData/codegen/box/jvmName/annotationProperties.kt b/compiler/testData/codegen/box/jvmName/annotationProperties.kt new file mode 100644 index 00000000000..836c81eb8f7 --- /dev/null +++ b/compiler/testData/codegen/box/jvmName/annotationProperties.kt @@ -0,0 +1,29 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND: JVM_IR +// WITH_REFLECT + +import kotlin.test.assertEquals + +annotation class Anno(@get:JvmName("uglyJvmName") val value: String) + +@Anno(value = "OK") +class Foo + + +annotation class Meta(val anno: Anno) + +@Meta(Anno(value = "OK")) +fun bar() {} + + +fun box(): String { + val f = Foo::class.annotations.single() + assertEquals("@Anno(uglyJvmName=OK)", f.toString()) + assertEquals("OK", (f as Anno).value) + + val b = ::bar.annotations.single() + assertEquals("@Meta(anno=@Anno(uglyJvmName=OK))", b.toString()) + assertEquals("OK", (b as Meta).anno.value) + + return "OK" +} diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvmNames.kt b/compiler/testData/compileKotlinAgainstKotlin/jvmNames.kt index 9d3c1c411eb..dcac7911bb6 100644 --- a/compiler/testData/compileKotlinAgainstKotlin/jvmNames.kt +++ b/compiler/testData/compileKotlinAgainstKotlin/jvmNames.kt @@ -19,13 +19,22 @@ class A { @JvmName("OK") get } +annotation class Anno(@get:JvmName("uglyJvmName") val value: String) + // FILE: B.kt import lib.* +@Anno("OK") +fun annotated() {} + fun box(): String { foo() v = 1 consumeInt(v) + + val annoValue = (::annotated.annotations.single() as Anno).value + if (annoValue != "OK") return "Fail annotation value: $annoValue" + return A().OK } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index d608e2fe4b8..d7615784943 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12648,6 +12648,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/jvmName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("annotationProperties.kt") + public void testAnnotationProperties() throws Exception { + runTest("compiler/testData/codegen/box/jvmName/annotationProperties.kt"); + } + @TestMetadata("callableReference.kt") public void testCallableReference() throws Exception { runTest("compiler/testData/codegen/box/jvmName/callableReference.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 9ecc9c0efc9..752a3ca66c3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12648,6 +12648,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/jvmName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("annotationProperties.kt") + public void testAnnotationProperties() throws Exception { + runTest("compiler/testData/codegen/box/jvmName/annotationProperties.kt"); + } + @TestMetadata("callableReference.kt") public void testCallableReference() throws Exception { runTest("compiler/testData/codegen/box/jvmName/callableReference.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 19ecb9a9964..b5d840b5a12 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -12648,6 +12648,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/jvmName"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("annotationProperties.kt") + public void testAnnotationProperties() throws Exception { + runTest("compiler/testData/codegen/box/jvmName/annotationProperties.kt"); + } + @TestMetadata("callableReference.kt") public void testCallableReference() throws Exception { runTest("compiler/testData/codegen/box/jvmName/callableReference.kt"); diff --git a/libraries/tools/kotlinp/testData/Annotations.kt b/libraries/tools/kotlinp/testData/Annotations.kt index dc5004f538e..535a4601201 100644 --- a/libraries/tools/kotlinp/testData/Annotations.kt +++ b/libraries/tools/kotlinp/testData/Annotations.kt @@ -26,8 +26,11 @@ annotation class A( annotation class B(val value: String) +@Target(AnnotationTarget.TYPE) +annotation class JvmNamed(@get:JvmName("uglyJvmName") val value: String) + class C { - fun typeAnnotation(): @A( + fun returnTypeAnnotation(): @A( true, 'x', 1.toByte(), @@ -49,4 +52,6 @@ class C { C::class, B(value = "aba\ncaba'\"\t\u0001\u0002\uA66E") ) Unit {} + + fun parameterTypeAnnotation(p: @JvmNamed("Q_Q") Any): Any = p } diff --git a/libraries/tools/kotlinp/testData/Annotations.txt b/libraries/tools/kotlinp/testData/Annotations.txt index c6c49101949..fb8a4ebbb9b 100644 --- a/libraries/tools/kotlinp/testData/Annotations.txt +++ b/libraries/tools/kotlinp/testData/Annotations.txt @@ -5,63 +5,83 @@ public final annotation class A : kotlin/Annotation { // signature: (ZCBSIFJD[Z[C[B[S[I[F[J[DLjava/lang/String;Lkotlin/annotation/AnnotationTarget;Lkotlin/reflect/KClass;LB;)V public /* primary */ constructor(z: kotlin/Boolean, c: kotlin/Char, b: kotlin/Byte, s: kotlin/Short, i: kotlin/Int, f: kotlin/Float, j: kotlin/Long, d: kotlin/Double, za: kotlin/BooleanArray, ca: kotlin/CharArray, ba: kotlin/ByteArray, sa: kotlin/ShortArray, ia: kotlin/IntArray, fa: kotlin/FloatArray, ja: kotlin/LongArray, da: kotlin/DoubleArray, str: kotlin/String, enum: kotlin/annotation/AnnotationTarget, klass: kotlin/reflect/KClass<*>, anno: B) + // getter: anno()LB; public final val anno: B public final get + // getter: b()B public final val b: kotlin/Byte public final get + // getter: ba()[B public final val ba: kotlin/ByteArray public final get + // getter: c()C public final val c: kotlin/Char public final get + // getter: ca()[C public final val ca: kotlin/CharArray public final get + // getter: d()D public final val d: kotlin/Double public final get + // getter: da()[D public final val da: kotlin/DoubleArray public final get + // getter: enum()Lkotlin/annotation/AnnotationTarget; public final val enum: kotlin/annotation/AnnotationTarget public final get + // getter: f()F public final val f: kotlin/Float public final get + // getter: fa()[F public final val fa: kotlin/FloatArray public final get + // getter: i()I public final val i: kotlin/Int public final get + // getter: ia()[I public final val ia: kotlin/IntArray public final get + // getter: j()J public final val j: kotlin/Long public final get + // getter: ja()[J public final val ja: kotlin/LongArray public final get + // getter: klass()Ljava/lang/Class; public final val klass: kotlin/reflect/KClass<*> public final get + // getter: s()S public final val s: kotlin/Short public final get + // getter: sa()[S public final val sa: kotlin/ShortArray public final get + // getter: str()Ljava/lang/String; public final val str: kotlin/String public final get + // getter: z()Z public final val z: kotlin/Boolean public final get + // getter: za()[Z public final val za: kotlin/BooleanArray public final get } @@ -72,6 +92,7 @@ public final annotation class B : kotlin/Annotation { // signature: (Ljava/lang/String;)V public /* primary */ constructor(value: kotlin/String) + // getter: value()Ljava/lang/String; public final val value: kotlin/String public final get } @@ -82,8 +103,22 @@ public final class C : kotlin/Any { // signature: ()V public /* primary */ constructor() - // signature: typeAnnotation()V - public final fun typeAnnotation(): @A(z = true, c = 'x', b = 1.toByte(), s = 42.toShort(), i = 42424242, f = -2.72f, j = 239239239239239L, d = 3.14, za = [true], ca = ['\''], ba = [1.toByte()], sa = [42.toShort()], ia = [42424242], fa = [-2.72f], ja = [239239239239239L], da = [3.14], str = "aba\ncaba'\"\t\u0001\u0002ꙮ", enum = kotlin/annotation/AnnotationTarget.CLASS, klass = C::class, anno = B(value = "aba\ncaba'\"\t\u0001\u0002ꙮ")) kotlin/Unit + // signature: parameterTypeAnnotation(Ljava/lang/Object;)Ljava/lang/Object; + public final fun parameterTypeAnnotation(p: @JvmNamed(value = "Q_Q") kotlin/Any): kotlin/Any + + // signature: returnTypeAnnotation()V + public final fun returnTypeAnnotation(): @A(z = true, c = 'x', b = 1.toByte(), s = 42.toShort(), i = 42424242, f = -2.72f, j = 239239239239239L, d = 3.14, za = [true], ca = ['\''], ba = [1.toByte()], sa = [42.toShort()], ia = [42424242], fa = [-2.72f], ja = [239239239239239L], da = [3.14], str = "aba\ncaba'\"\t\u0001\u0002ꙮ", enum = kotlin/annotation/AnnotationTarget.CLASS, klass = C::class, anno = B(value = "aba\ncaba'\"\t\u0001\u0002ꙮ")) kotlin/Unit +} +// JvmNamed.class +// ------------------------------------------ +public final annotation class JvmNamed : kotlin/Annotation { + + // signature: (Ljava/lang/String;)V + public /* primary */ constructor(value: kotlin/String) + + // getter: uglyJvmName()Ljava/lang/String; + public final val value: kotlin/String + public final get } // META-INF/test-module.kotlin_module // ------------------------------------------