Generate container class for repeatable annotations

#KT-12794
This commit is contained in:
Alexander Udalov
2021-07-20 23:02:38 +02:00
parent 87130edfa2
commit 92a73d7636
21 changed files with 652 additions and 42 deletions
@@ -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
@@ -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(
@@ -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
}
}
/*
@@ -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 +=
@@ -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)
}
}
@@ -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();
}
}
@@ -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 }
}
@@ -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 = ""
@@ -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
}
@@ -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
@@ -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
}
@@ -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>
@@ -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
}
@@ -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
@@ -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
}
@@ -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
@@ -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
}
@@ -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
@@ -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.
*/