Support JvmName on annotation constructor parameters
#KT-25372 Fixed
This commit is contained in:
committed by
Ilya Gorbunov
parent
dc1f4c7d5b
commit
b55fc818d1
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.config.JvmTarget;
|
|||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.*;
|
import org.jetbrains.kotlin.descriptors.annotations.*;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
|
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.load.java.JvmAnnotationNames;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
@@ -346,11 +347,22 @@ public abstract class AnnotationCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
|
private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
|
||||||
|
ClassDescriptor annotationClass = DescriptorUtilsKt.getAnnotationClass(annotationDescriptor);
|
||||||
for (Map.Entry<Name, ConstantValue<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
|
for (Map.Entry<Name, ConstantValue<?>> 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<PropertyDescriptor> variables =
|
||||||
|
annotationClass.getUnsubstitutedMemberScope().getContributedVariables(parameterName, NoLookupLocation.FROM_BACKEND);
|
||||||
|
if (variables.size() != 1) return parameterName.asString();
|
||||||
|
|
||||||
|
return typeMapper.mapAnnotationParameterName(variables.iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
private void genCompileTimeValue(
|
private void genCompileTimeValue(
|
||||||
@Nullable String name,
|
@Nullable String name,
|
||||||
@NotNull ConstantValue<?> value,
|
@NotNull ConstantValue<?> value,
|
||||||
|
|||||||
@@ -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.JvmCodegenUtil.isJvmInterface;
|
||||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.DELEGATED_PROPERTIES;
|
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.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.*;
|
||||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.SYNTHETIC_METHOD_FOR_PROPERTY;
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND;
|
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.isCompanionObject;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
|
||||||
@@ -278,6 +277,7 @@ public class PropertyCodegen {
|
|||||||
|
|
||||||
PropertyGetterDescriptor getter = descriptor.getGetter();
|
PropertyGetterDescriptor getter = descriptor.getGetter();
|
||||||
assert getter != null : "Annotation property should have a getter: " + descriptor;
|
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);
|
FunctionCodegen.generateMethodAnnotations(getter, asmMethod, mv, memberCodegen, typeMapper);
|
||||||
|
|
||||||
KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor);
|
KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor);
|
||||||
|
|||||||
@@ -489,7 +489,13 @@ public class KotlinTypeMapper {
|
|||||||
sw.writeReturnType();
|
sw.writeReturnType();
|
||||||
mapType(descriptor.getType(), sw, TypeMappingMode.VALUE_FOR_ANNOTATION);
|
mapType(descriptor.getType(), sw, TypeMappingMode.VALUE_FOR_ANNOTATION);
|
||||||
sw.writeReturnTypeEnd();
|
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
|
@NotNull
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -19,13 +19,22 @@ class A {
|
|||||||
@JvmName("OK") get
|
@JvmName("OK") get
|
||||||
}
|
}
|
||||||
|
|
||||||
|
annotation class Anno(@get:JvmName("uglyJvmName") val value: String)
|
||||||
|
|
||||||
// FILE: B.kt
|
// FILE: B.kt
|
||||||
|
|
||||||
import lib.*
|
import lib.*
|
||||||
|
|
||||||
|
@Anno("OK")
|
||||||
|
fun annotated() {}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
foo()
|
foo()
|
||||||
v = 1
|
v = 1
|
||||||
consumeInt(v)
|
consumeInt(v)
|
||||||
|
|
||||||
|
val annoValue = (::annotated.annotations.single() as Anno).value
|
||||||
|
if (annoValue != "OK") return "Fail annotation value: $annoValue"
|
||||||
|
|
||||||
return A().OK
|
return A().OK
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -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);
|
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")
|
@TestMetadata("callableReference.kt")
|
||||||
public void testCallableReference() throws Exception {
|
public void testCallableReference() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/jvmName/callableReference.kt");
|
runTest("compiler/testData/codegen/box/jvmName/callableReference.kt");
|
||||||
|
|||||||
+5
@@ -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);
|
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")
|
@TestMetadata("callableReference.kt")
|
||||||
public void testCallableReference() throws Exception {
|
public void testCallableReference() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/jvmName/callableReference.kt");
|
runTest("compiler/testData/codegen/box/jvmName/callableReference.kt");
|
||||||
|
|||||||
+5
@@ -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);
|
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")
|
@TestMetadata("callableReference.kt")
|
||||||
public void testCallableReference() throws Exception {
|
public void testCallableReference() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/jvmName/callableReference.kt");
|
runTest("compiler/testData/codegen/box/jvmName/callableReference.kt");
|
||||||
|
|||||||
+6
-1
@@ -26,8 +26,11 @@ annotation class A(
|
|||||||
|
|
||||||
annotation class B(val value: String)
|
annotation class B(val value: String)
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.TYPE)
|
||||||
|
annotation class JvmNamed(@get:JvmName("uglyJvmName") val value: String)
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
fun typeAnnotation(): @A(
|
fun returnTypeAnnotation(): @A(
|
||||||
true,
|
true,
|
||||||
'x',
|
'x',
|
||||||
1.toByte(),
|
1.toByte(),
|
||||||
@@ -49,4 +52,6 @@ class C {
|
|||||||
C::class,
|
C::class,
|
||||||
B(value = "aba\ncaba'\"\t\u0001\u0002\uA66E")
|
B(value = "aba\ncaba'\"\t\u0001\u0002\uA66E")
|
||||||
) Unit {}
|
) Unit {}
|
||||||
|
|
||||||
|
fun parameterTypeAnnotation(p: @JvmNamed("Q_Q") Any): Any = p
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-2
@@ -5,63 +5,83 @@ public final annotation class A : kotlin/Annotation {
|
|||||||
// signature: <init>(ZCBSIFJD[Z[C[B[S[I[F[J[DLjava/lang/String;Lkotlin/annotation/AnnotationTarget;Lkotlin/reflect/KClass;LB;)V
|
// signature: <init>(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)
|
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 val anno: B
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: b()B
|
||||||
public final val b: kotlin/Byte
|
public final val b: kotlin/Byte
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: ba()[B
|
||||||
public final val ba: kotlin/ByteArray
|
public final val ba: kotlin/ByteArray
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: c()C
|
||||||
public final val c: kotlin/Char
|
public final val c: kotlin/Char
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: ca()[C
|
||||||
public final val ca: kotlin/CharArray
|
public final val ca: kotlin/CharArray
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: d()D
|
||||||
public final val d: kotlin/Double
|
public final val d: kotlin/Double
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: da()[D
|
||||||
public final val da: kotlin/DoubleArray
|
public final val da: kotlin/DoubleArray
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: enum()Lkotlin/annotation/AnnotationTarget;
|
||||||
public final val enum: kotlin/annotation/AnnotationTarget
|
public final val enum: kotlin/annotation/AnnotationTarget
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: f()F
|
||||||
public final val f: kotlin/Float
|
public final val f: kotlin/Float
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: fa()[F
|
||||||
public final val fa: kotlin/FloatArray
|
public final val fa: kotlin/FloatArray
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: i()I
|
||||||
public final val i: kotlin/Int
|
public final val i: kotlin/Int
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: ia()[I
|
||||||
public final val ia: kotlin/IntArray
|
public final val ia: kotlin/IntArray
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: j()J
|
||||||
public final val j: kotlin/Long
|
public final val j: kotlin/Long
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: ja()[J
|
||||||
public final val ja: kotlin/LongArray
|
public final val ja: kotlin/LongArray
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: klass()Ljava/lang/Class;
|
||||||
public final val klass: kotlin/reflect/KClass<*>
|
public final val klass: kotlin/reflect/KClass<*>
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: s()S
|
||||||
public final val s: kotlin/Short
|
public final val s: kotlin/Short
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: sa()[S
|
||||||
public final val sa: kotlin/ShortArray
|
public final val sa: kotlin/ShortArray
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: str()Ljava/lang/String;
|
||||||
public final val str: kotlin/String
|
public final val str: kotlin/String
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: z()Z
|
||||||
public final val z: kotlin/Boolean
|
public final val z: kotlin/Boolean
|
||||||
public final get
|
public final get
|
||||||
|
|
||||||
|
// getter: za()[Z
|
||||||
public final val za: kotlin/BooleanArray
|
public final val za: kotlin/BooleanArray
|
||||||
public final get
|
public final get
|
||||||
}
|
}
|
||||||
@@ -72,6 +92,7 @@ public final annotation class B : kotlin/Annotation {
|
|||||||
// signature: <init>(Ljava/lang/String;)V
|
// signature: <init>(Ljava/lang/String;)V
|
||||||
public /* primary */ constructor(value: kotlin/String)
|
public /* primary */ constructor(value: kotlin/String)
|
||||||
|
|
||||||
|
// getter: value()Ljava/lang/String;
|
||||||
public final val value: kotlin/String
|
public final val value: kotlin/String
|
||||||
public final get
|
public final get
|
||||||
}
|
}
|
||||||
@@ -82,8 +103,22 @@ public final class C : kotlin/Any {
|
|||||||
// signature: <init>()V
|
// signature: <init>()V
|
||||||
public /* primary */ constructor()
|
public /* primary */ constructor()
|
||||||
|
|
||||||
// signature: typeAnnotation()V
|
// signature: parameterTypeAnnotation(Ljava/lang/Object;)Ljava/lang/Object;
|
||||||
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
|
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: <init>(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
|
// META-INF/test-module.kotlin_module
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user