Generate container class for repeatable annotations
#KT-12794
This commit is contained in:
+12
@@ -516,6 +516,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
public void testJvmRepeatableKotlinAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/repeatable/jvmRepeatableKotlinAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnnotation.kt")
|
||||
public void testKotlinAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/repeatable/kotlinAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnnotationWithBothRepeatables.kt")
|
||||
public void testKotlinAnnotationWithBothRepeatables() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/repeatable/kotlinAnnotationWithBothRepeatables.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+36
-2
@@ -7,11 +7,16 @@ package org.jetbrains.kotlin.ir.builders.declarations
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
@@ -106,6 +111,35 @@ inline fun IrProperty.addGetter(builder: IrFunctionBuilder.() -> Unit = {}): IrS
|
||||
}
|
||||
}
|
||||
|
||||
fun IrProperty.addDefaultGetter(parentClass: IrClass, builtIns: IrBuiltIns) {
|
||||
val field = backingField!!
|
||||
addGetter {
|
||||
origin = IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
|
||||
returnType = field.type
|
||||
}.apply {
|
||||
dispatchReceiverParameter = parentClass.thisReceiver!!.copyTo(this)
|
||||
body = factory.createBlockBody(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(
|
||||
IrReturnImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
builtIns.nothingType,
|
||||
symbol,
|
||||
IrGetFieldImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
field.symbol,
|
||||
field.type,
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
dispatchReceiverParameter!!.type,
|
||||
dispatchReceiverParameter!!.symbol
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun IrFactory.buildFunction(builder: IrFunctionBuilder): IrSimpleFunction = with(builder) {
|
||||
createFunction(
|
||||
|
||||
+49
-3
@@ -13,16 +13,17 @@ import org.jetbrains.kotlin.backend.jvm.ir.copyCorrespondingPropertyFrom
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.replaceThisByStaticReference
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.isMappedIntrinsicCompanionObjectClassId
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
@@ -43,6 +44,8 @@ class JvmCachedDeclarations(
|
||||
private val defaultImplsRedirections = ConcurrentHashMap<IrSimpleFunction, IrSimpleFunction>()
|
||||
private val defaultImplsOriginalMethods = ConcurrentHashMap<IrSimpleFunction, IrSimpleFunction>()
|
||||
|
||||
private val repeatedAnnotationSyntheticContainers = ConcurrentHashMap<IrClass, IrClass>()
|
||||
|
||||
fun getFieldForEnumEntry(enumEntry: IrEnumEntry): IrField =
|
||||
singletonFieldDeclarations.getOrPut(enumEntry) {
|
||||
context.irFactory.buildField {
|
||||
@@ -272,6 +275,49 @@ class JvmCachedDeclarations(
|
||||
copyCorrespondingPropertyFrom(fakeOverride)
|
||||
}
|
||||
}
|
||||
|
||||
fun getRepeatedAnnotationSyntheticContainer(annotationClass: IrClass): IrClass =
|
||||
repeatedAnnotationSyntheticContainers.getOrPut(annotationClass) {
|
||||
val containerClass = context.irFactory.buildClass {
|
||||
kind = ClassKind.ANNOTATION_CLASS
|
||||
name = Name.identifier(JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME)
|
||||
}.apply {
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
parent = annotationClass
|
||||
superTypes = listOf(context.irBuiltIns.annotationType)
|
||||
}
|
||||
|
||||
val propertyName = Name.identifier("value")
|
||||
val propertyType = context.irBuiltIns.arrayClass.typeWith(annotationClass.typeWith())
|
||||
|
||||
containerClass.addConstructor {
|
||||
isPrimary = true
|
||||
}.apply {
|
||||
addValueParameter(propertyName, propertyType)
|
||||
}
|
||||
|
||||
containerClass.addProperty {
|
||||
name = propertyName
|
||||
}.apply property@{
|
||||
backingField = context.irFactory.buildField {
|
||||
name = propertyName
|
||||
type = propertyType
|
||||
}.apply {
|
||||
parent = containerClass
|
||||
correspondingPropertySymbol = this@property.symbol
|
||||
}
|
||||
addDefaultGetter(containerClass, context.irBuiltIns)
|
||||
}
|
||||
|
||||
containerClass.annotations = annotationClass.annotations
|
||||
.filter {
|
||||
it.isAnnotationWithEqualFqName(StandardNames.FqNames.retention) ||
|
||||
it.isAnnotationWithEqualFqName(StandardNames.FqNames.target)
|
||||
}
|
||||
.map { it.deepCopyWithSymbols(containerClass) }
|
||||
|
||||
containerClass
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+2
-6
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.getAnnotationRetention
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.lang.annotation.ElementType
|
||||
|
||||
internal val additionalClassAnnotationPhase = makeIrFilePhase(
|
||||
@@ -60,10 +59,7 @@ private class AdditionalClassAnnotationLowering(private val context: JvmBackendC
|
||||
|
||||
private fun generateRetentionAnnotation(irClass: IrClass) {
|
||||
if (irClass.hasAnnotation(JvmAnnotationNames.RETENTION_ANNOTATION)) return
|
||||
val kotlinRetentionPolicyCall = irClass.getAnnotation(StandardNames.FqNames.retention)
|
||||
val kotlinRetentionPolicyName =
|
||||
kotlinRetentionPolicyCall?.getValueArgument(0)?.safeAs<IrGetEnumValue>()?.symbol?.owner?.name?.asString()
|
||||
val kotlinRetentionPolicy = kotlinRetentionPolicyName?.let { KotlinRetention.valueOf(it) }
|
||||
val kotlinRetentionPolicy = irClass.getAnnotationRetention()
|
||||
val javaRetentionPolicy = kotlinRetentionPolicy?.let { symbols.annotationRetentionMap[it] } ?: symbols.rpRuntime
|
||||
|
||||
irClass.annotations +=
|
||||
|
||||
+14
-1
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.codegen.AnnotationCodegen.Companion.annotationClass
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
@@ -21,6 +23,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.isAnnotation
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
@@ -53,6 +56,16 @@ class RepeatedAnnotationLowering(private val context: JvmBackendContext) : FileL
|
||||
super.visitDeclaration(declaration)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (declaration.kind == ClassKind.ANNOTATION_CLASS &&
|
||||
declaration.hasAnnotation(StandardNames.FqNames.repeatable) &&
|
||||
!declaration.hasAnnotation(JvmAnnotationNames.REPEATABLE_ANNOTATION)
|
||||
) {
|
||||
declaration.declarations.add(context.cachedDeclarations.getRepeatedAnnotationSyntheticContainer(declaration))
|
||||
}
|
||||
super.visitClass(declaration)
|
||||
}
|
||||
|
||||
private fun transformAnnotations(annotations: List<IrConstructorCall>): List<IrConstructorCall> {
|
||||
if (annotations.size < 2) return annotations
|
||||
|
||||
@@ -85,7 +98,7 @@ class RepeatedAnnotationLowering(private val context: JvmBackendContext) : FileL
|
||||
(containerClassReference.symbol as? IrClassSymbol)?.owner
|
||||
?: error("Repeatable annotation container must be a class: $annotationClass")
|
||||
} else {
|
||||
TODO("Kotlin repeatable annotations")
|
||||
context.cachedDeclarations.getRepeatedAnnotationSyntheticContainer(annotationClass)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-30
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeCustomPhase
|
||||
@@ -19,11 +18,14 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.toIrConst
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -276,36 +278,10 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
|
||||
field.initializer = initializer
|
||||
}
|
||||
|
||||
property.addSimpleFieldGetter(from.type, this, field)
|
||||
property.addDefaultGetter(this, context.irBuiltIns)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrProperty.addSimpleFieldGetter(type: IrType, irScriptClass: IrClass, field: IrField) =
|
||||
addGetter {
|
||||
returnType = type
|
||||
}.apply {
|
||||
dispatchReceiverParameter = irScriptClass.thisReceiver!!.copyTo(this)
|
||||
body = IrBlockBodyImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(
|
||||
IrReturnImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
context.irBuiltIns.nothingType,
|
||||
symbol,
|
||||
IrGetFieldImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
field.symbol,
|
||||
type,
|
||||
IrGetValueImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
dispatchReceiverParameter!!.type,
|
||||
dispatchReceiverParameter!!.symbol
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class ScriptToClassTransformerContext(
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
// java.lang.NoSuchMethodError: java.lang.Class.getAnnotationsByType
|
||||
// IGNORE_BACKEND: ANDROID
|
||||
|
||||
// FILE: box.kt
|
||||
|
||||
@Repeatable
|
||||
annotation class A(val value: String)
|
||||
|
||||
@A("O")
|
||||
@A("")
|
||||
@A("K")
|
||||
class Z
|
||||
|
||||
fun box(): String {
|
||||
val annotations = Z::class.java.annotations.filter { it.annotationClass != Metadata::class }
|
||||
val aa = annotations.singleOrNull() ?: return "Fail 1: $annotations"
|
||||
|
||||
val a = ContainerSupport.load(aa)
|
||||
if (a.size != 3) return "Fail 2: $a"
|
||||
|
||||
val bytype = Z::class.java.getAnnotationsByType(A::class.java)
|
||||
if (a.toList() != bytype.toList()) return "Fail 3: ${a.toList()} != ${bytype.toList()}"
|
||||
|
||||
return a.fold("") { acc, it -> acc + it.value }
|
||||
}
|
||||
|
||||
// FILE: ContainerSupport.java
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public class ContainerSupport {
|
||||
public static A[] load(Annotation container) {
|
||||
return ((A.Container) container).value();
|
||||
}
|
||||
}
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
// java.lang.NoSuchMethodError: java.lang.Class.getAnnotationsByType
|
||||
// IGNORE_BACKEND: ANDROID
|
||||
|
||||
@Repeatable
|
||||
@java.lang.annotation.Repeatable(As::class)
|
||||
annotation class A(val value: String)
|
||||
|
||||
annotation class As(val value: Array<A>)
|
||||
|
||||
@A("O")
|
||||
@A("")
|
||||
@A("K")
|
||||
class Z
|
||||
|
||||
fun box(): String {
|
||||
val annotations = Z::class.java.annotations.filter { it.annotationClass != Metadata::class }
|
||||
val aa = annotations.singleOrNull() ?: return "Fail 1: $annotations"
|
||||
if (aa !is As) return "Fail 2: $aa"
|
||||
|
||||
val a = aa.value.asList()
|
||||
if (a.size != 3) return "Fail 3: $a"
|
||||
|
||||
val bytype = Z::class.java.getAnnotationsByType(A::class.java)
|
||||
if (a.toList() != bytype.toList()) return "Fail 4: ${a.toList()} != ${bytype.toList()}"
|
||||
|
||||
return a.fold("") { acc, it -> acc + it.value }
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
package test
|
||||
|
||||
@Repeatable
|
||||
annotation class A(val value: String)
|
||||
|
||||
@A("class1") @A("class2")
|
||||
class Z @A("constructor1") @A("constructor2") constructor() {
|
||||
@A("nestedClass1") @A("nestedClass2")
|
||||
annotation class Nested
|
||||
|
||||
@A("memberFunction1") @A("memberFunction2")
|
||||
fun memberFunction() {}
|
||||
|
||||
@A("memberProperty1") @A("memberProperty2")
|
||||
var memberProperty: Int
|
||||
@A("propertyGetter1") @A("propertyGetter2")
|
||||
get() = 0
|
||||
@A("propertySetter1") @A("propertySetter2")
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
@A("topLevelFunction1") @A("topLevelFunction2")
|
||||
fun topLevelFunction2(
|
||||
@A("parameter1") @A("parameter2")
|
||||
parameter: String
|
||||
) {}
|
||||
|
||||
@A("topLevelProperty1") @A("topLevelProperty2")
|
||||
var String.z: Z
|
||||
@A("propertyGetter1") @A("propertyGetter2")
|
||||
get() = Z()
|
||||
@A("propertySetter1") @A("propertySetter2")
|
||||
set(value) {}
|
||||
|
||||
@get:A("useSitePropertyGetter1")
|
||||
@get:A("useSitePropertyGetter2")
|
||||
@field:A("field1")
|
||||
@field:A("field2")
|
||||
val o: String = ""
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/A$Container {
|
||||
// source: 'kotlinAnnotation.kt'
|
||||
public abstract method value(): test.A[]
|
||||
public inner class test/A$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/A {
|
||||
// source: 'kotlinAnnotation.kt'
|
||||
public abstract method value(): java.lang.String
|
||||
public inner class test/A$Container
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class test/KotlinAnnotationKt {
|
||||
// source: 'kotlinAnnotation.kt'
|
||||
private final static @test.A$Container(value=[test.A(value="field1"), test.A(value="field2")]) @org.jetbrains.annotations.NotNull field o: java.lang.String
|
||||
static method <clinit>(): void
|
||||
public final static @test.A$Container(value=[test.A(value="useSitePropertyGetter1"), test.A(value="useSitePropertyGetter2")]) @org.jetbrains.annotations.NotNull method getO(): java.lang.String
|
||||
public synthetic deprecated static @test.A$Container(value=[test.A(value="topLevelProperty1"), test.A(value="topLevelProperty2")]) method getZ$annotations(p0: java.lang.String): void
|
||||
public final static @test.A$Container(value=[test.A(value="propertyGetter1"), test.A(value="propertyGetter2")]) @org.jetbrains.annotations.NotNull method getZ(@org.jetbrains.annotations.NotNull p0: java.lang.String): test.Z
|
||||
public final static @test.A$Container(value=[test.A(value="propertySetter1"), test.A(value="propertySetter2")]) method setZ(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: test.Z): void
|
||||
public final static @test.A$Container(value=[test.A(value="topLevelFunction1"), test.A(value="topLevelFunction2")]) method topLevelFunction2(@test.A$Container(value=[test.A(value="parameter1"), test.A(value="parameter2")]) @org.jetbrains.annotations.NotNull p0: java.lang.String): void
|
||||
public inner class test/A$Container
|
||||
}
|
||||
|
||||
@test.A$Container(value=[test.A(value="nestedClass1"), test.A(value="nestedClass2")])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/Z$Nested {
|
||||
// source: 'kotlinAnnotation.kt'
|
||||
public inner class test/A$Container
|
||||
public inner class test/Z$Nested
|
||||
}
|
||||
|
||||
@test.A$Container(value=[test.A(value="class1"), test.A(value="class2")])
|
||||
@kotlin.Metadata
|
||||
public final class test/Z {
|
||||
// source: 'kotlinAnnotation.kt'
|
||||
public @test.A$Container(value=[test.A(value="constructor1"), test.A(value="constructor2")]) method <init>(): void
|
||||
public synthetic deprecated static @test.A$Container(value=[test.A(value="memberProperty1"), test.A(value="memberProperty2")]) method getMemberProperty$annotations(): void
|
||||
public final @test.A$Container(value=[test.A(value="propertyGetter1"), test.A(value="propertyGetter2")]) method getMemberProperty(): int
|
||||
public final @test.A$Container(value=[test.A(value="memberFunction1"), test.A(value="memberFunction2")]) method memberFunction(): void
|
||||
public final @test.A$Container(value=[test.A(value="propertySetter1"), test.A(value="propertySetter2")]) method setMemberProperty(p0: int): void
|
||||
public inner class test/A$Container
|
||||
public inner class test/Z$Nested
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
package test
|
||||
|
||||
@Repeatable
|
||||
@java.lang.annotation.Repeatable(As::class)
|
||||
annotation class A(val value: String)
|
||||
|
||||
annotation class As(val value: Array<A>)
|
||||
|
||||
@A("a1")
|
||||
@A("a2")
|
||||
class Z
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
@kotlin.annotation.Repeatable
|
||||
@java.lang.annotation.Repeatable(value=test.As::class)
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/A {
|
||||
// source: 'kotlinAnnotationWithBothRepeatables.kt'
|
||||
public abstract method value(): java.lang.String
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/As {
|
||||
// source: 'kotlinAnnotationWithBothRepeatables.kt'
|
||||
public abstract method value(): test.A[]
|
||||
}
|
||||
|
||||
@test.As(value=[test.A(value="a1"), test.A(value="a2")])
|
||||
@kotlin.Metadata
|
||||
public final class test/Z {
|
||||
// source: 'kotlinAnnotationWithBothRepeatables.kt'
|
||||
public method <init>(): void
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
@file:A("file1")
|
||||
@file:A("file2")
|
||||
package test
|
||||
|
||||
@Repeatable
|
||||
@Target(AnnotationTarget.FILE, AnnotationTarget.TYPEALIAS)
|
||||
annotation class A(val value: String)
|
||||
|
||||
@A("typealias1")
|
||||
@A("typealias2")
|
||||
typealias TA<X> = List<X>
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
@kotlin.annotation.Target(allowedTargets=[FILE, TYPEALIAS])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[])
|
||||
@kotlin.Metadata
|
||||
public annotation class test/A$Container {
|
||||
// source: 'kotlinSpecificTargets.kt'
|
||||
public abstract method value(): test.A[]
|
||||
public inner class test/A$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@kotlin.annotation.Target(allowedTargets=[FILE, TYPEALIAS])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[])
|
||||
@kotlin.Metadata
|
||||
public annotation class test/A {
|
||||
// source: 'kotlinSpecificTargets.kt'
|
||||
public abstract method value(): java.lang.String
|
||||
public inner class test/A$Container
|
||||
}
|
||||
|
||||
@test.A$Container(value=[test.A(value="file1"), test.A(value="file2")])
|
||||
@kotlin.Metadata
|
||||
public final class test/KotlinSpecificTargetsKt {
|
||||
// source: 'kotlinSpecificTargets.kt'
|
||||
public synthetic deprecated static @test.A$Container(value=[test.A(value="typealias1"), test.A(value="typealias2")]) method TA$annotations(): void
|
||||
public inner class test/A$Container
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
package test
|
||||
|
||||
@Repeatable
|
||||
annotation class A(val value: String)
|
||||
@Repeatable
|
||||
annotation class B(val value: String)
|
||||
@Repeatable
|
||||
annotation class C(val value: String)
|
||||
|
||||
annotation class Z(val value: String)
|
||||
|
||||
// Expected annotation order (as in Java): all @A, then all @B, then @Z, then all @C.
|
||||
@A("a1")
|
||||
@B("b1")
|
||||
@A("a2")
|
||||
@Z("z")
|
||||
@C("c1")
|
||||
@C("c2")
|
||||
@B("b2")
|
||||
class Test
|
||||
Vendored
+70
@@ -0,0 +1,70 @@
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/A$Container {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public abstract method value(): test.A[]
|
||||
public inner class test/A$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/A {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public abstract method value(): java.lang.String
|
||||
public inner class test/A$Container
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/B$Container {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public abstract method value(): test.B[]
|
||||
public inner class test/B$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/B {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public abstract method value(): java.lang.String
|
||||
public inner class test/B$Container
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/C$Container {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public abstract method value(): test.C[]
|
||||
public inner class test/C$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/C {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public abstract method value(): java.lang.String
|
||||
public inner class test/C$Container
|
||||
}
|
||||
|
||||
@test.A$Container(value=[test.A(value="a1"), test.A(value="a2")])
|
||||
@test.B$Container(value=[test.B(value="b1"), test.B(value="b2")])
|
||||
@test.Z(value="z")
|
||||
@test.C$Container(value=[test.C(value="c1"), test.C(value="c2")])
|
||||
@kotlin.Metadata
|
||||
public final class test/Test {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public method <init>(): void
|
||||
public inner class test/A$Container
|
||||
public inner class test/B$Container
|
||||
public inner class test/C$Container
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class test/Z {
|
||||
// source: 'multipleRepeatableOrder.kt'
|
||||
public abstract method value(): java.lang.String
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
@Repeatable
|
||||
annotation class RetentionRuntime
|
||||
|
||||
@Repeatable
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class RetentionBinary
|
||||
|
||||
@Repeatable
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class RetentionSource
|
||||
|
||||
@Repeatable
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class TargetClassOnly
|
||||
|
||||
@Repeatable
|
||||
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.TYPE)
|
||||
annotation class TargetAnnotationClassAndTypeOnly
|
||||
|
||||
@Repeatable
|
||||
@Target()
|
||||
annotation class TargetEmpty
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
@kotlin.annotation.Retention(value=BINARY)
|
||||
@java.lang.annotation.Retention(value=CLASS)
|
||||
@kotlin.Metadata
|
||||
public annotation class RetentionBinary$Container {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public abstract method value(): RetentionBinary[]
|
||||
public inner class RetentionBinary$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@kotlin.annotation.Retention(value=BINARY)
|
||||
@java.lang.annotation.Retention(value=CLASS)
|
||||
@kotlin.Metadata
|
||||
public annotation class RetentionBinary {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public inner class RetentionBinary$Container
|
||||
}
|
||||
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class RetentionRuntime$Container {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public abstract method value(): RetentionRuntime[]
|
||||
public inner class RetentionRuntime$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@kotlin.Metadata
|
||||
public annotation class RetentionRuntime {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public inner class RetentionRuntime$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Retention(value=SOURCE)
|
||||
@java.lang.annotation.Retention(value=SOURCE)
|
||||
@kotlin.Metadata
|
||||
public annotation class RetentionSource$Container {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public abstract method value(): RetentionSource[]
|
||||
public inner class RetentionSource$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@kotlin.annotation.Retention(value=SOURCE)
|
||||
@java.lang.annotation.Retention(value=SOURCE)
|
||||
@kotlin.Metadata
|
||||
public annotation class RetentionSource {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public inner class RetentionSource$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Target(allowedTargets=[ANNOTATION_CLASS, TYPE])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[ANNOTATION_TYPE, TYPE_USE])
|
||||
@kotlin.Metadata
|
||||
public annotation class TargetAnnotationClassAndTypeOnly$Container {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public abstract method value(): TargetAnnotationClassAndTypeOnly[]
|
||||
public inner class TargetAnnotationClassAndTypeOnly$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@kotlin.annotation.Target(allowedTargets=[ANNOTATION_CLASS, TYPE])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[ANNOTATION_TYPE, TYPE_USE])
|
||||
@kotlin.Metadata
|
||||
public annotation class TargetAnnotationClassAndTypeOnly {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public inner class TargetAnnotationClassAndTypeOnly$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Target(allowedTargets=[CLASS])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[TYPE])
|
||||
@kotlin.Metadata
|
||||
public annotation class TargetClassOnly$Container {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public abstract method value(): TargetClassOnly[]
|
||||
public inner class TargetClassOnly$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@kotlin.annotation.Target(allowedTargets=[CLASS])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[TYPE])
|
||||
@kotlin.Metadata
|
||||
public annotation class TargetClassOnly {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public inner class TargetClassOnly$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Target(allowedTargets=[])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[])
|
||||
@kotlin.Metadata
|
||||
public annotation class TargetEmpty$Container {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public abstract method value(): TargetEmpty[]
|
||||
public inner class TargetEmpty$Container
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable
|
||||
@kotlin.annotation.Target(allowedTargets=[])
|
||||
@java.lang.annotation.Retention(value=RUNTIME)
|
||||
@java.lang.annotation.Target(value=[])
|
||||
@kotlin.Metadata
|
||||
public annotation class TargetEmpty {
|
||||
// source: 'retentionAndTarget.kt'
|
||||
public inner class TargetEmpty$Container
|
||||
}
|
||||
+12
@@ -516,6 +516,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
public void testJvmRepeatableKotlinAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/repeatable/jvmRepeatableKotlinAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnnotation.kt")
|
||||
public void testKotlinAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/repeatable/kotlinAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnnotationWithBothRepeatables.kt")
|
||||
public void testKotlinAnnotationWithBothRepeatables() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/repeatable/kotlinAnnotationWithBothRepeatables.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+30
@@ -439,11 +439,41 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
||||
runTest("compiler/testData/codegen/bytecodeListing/annotations/repeatable/javaAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnnotation.kt")
|
||||
public void testKotlinAnnotation() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/annotations/repeatable/kotlinAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnnotationWithBothRepeatables.kt")
|
||||
public void testKotlinAnnotationWithBothRepeatables() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/annotations/repeatable/kotlinAnnotationWithBothRepeatables.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinSpecificTargets.kt")
|
||||
public void testKotlinSpecificTargets() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/annotations/repeatable/kotlinSpecificTargets.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multipleRepeatableOrder.kt")
|
||||
public void testMultipleRepeatableOrder() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/annotations/repeatable/multipleRepeatableOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nonRepeatedAnnotationWithItsContainer.kt")
|
||||
public void testNonRepeatedAnnotationWithItsContainer() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/annotations/repeatable/nonRepeatedAnnotationWithItsContainer.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("retentionAndTarget.kt")
|
||||
public void testRetentionAndTarget() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/annotations/repeatable/retentionAndTarget.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ object JvmAbi {
|
||||
|
||||
const val IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS = "-impl"
|
||||
|
||||
const val REPEATABLE_ANNOTATION_CONTAINER_NAME = "Container"
|
||||
|
||||
/**
|
||||
* @param baseName JVM name of the property getter since Kotlin 1.4, or Kotlin name of the property otherwise.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user