java Retention + Repeatable = kotlin.annotation.annotation (but java Repeatable is still intact), a few tests
This commit is contained in:
+18
@@ -48,5 +48,23 @@ public class JetDiagnosticsWithJava8TestGenerated extends AbstractJetDiagnostics
|
|||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/annotations/deprecatedRepeatable.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/annotations/deprecatedRepeatable.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaRepeatable.kt")
|
||||||
|
public void testJavaRepeatable() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaRepeatableRetention.kt")
|
||||||
|
public void testJavaRepeatableRetention() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/annotations/javaRepeatableRetention.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("javaUnrepeatable.kt")
|
||||||
|
public void testJavaUnrepeatable() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJava8/annotations/javaUnrepeatable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// FILE: RepeatableAnnotation.java
|
||||||
|
|
||||||
|
import java.lang.annotation.Repeatable
|
||||||
|
|
||||||
|
@Repeatable(RepeatableAnnotations.class)
|
||||||
|
public @interface RepeatableAnnotation {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: RepeatableAnnotations.java
|
||||||
|
|
||||||
|
public @interface RepeatableAnnotations {
|
||||||
|
RepeatableAnnotation[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: RepeatableUse.kt
|
||||||
|
|
||||||
|
RepeatableAnnotation RepeatableAnnotation class My
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
RepeatableAnnotation() RepeatableAnnotation() internal final class My {
|
||||||
|
public constructor My()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
java.lang.annotation.Repeatable(value = RepeatableAnnotations::class) kotlin.annotation.annotation(repeatable = true) public final class RepeatableAnnotation : kotlin.Annotation {
|
||||||
|
public constructor RepeatableAnnotation()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class RepeatableAnnotations : kotlin.Annotation {
|
||||||
|
public constructor RepeatableAnnotations(/*0*/ vararg value: RepeatableAnnotation /*kotlin.Array<out RepeatableAnnotation>*/)
|
||||||
|
public final val value: kotlin.Array<RepeatableAnnotation>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
public abstract fun value(): kotlin.Array<RepeatableAnnotation>
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// FILE: RepeatableAnnotation.java
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Repeatable(RepeatableAnnotations.class)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface RepeatableAnnotation {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: RepeatableAnnotations.java
|
||||||
|
|
||||||
|
public @interface RepeatableAnnotations {
|
||||||
|
RepeatableAnnotation[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: RepeatableUse.kt
|
||||||
|
|
||||||
|
RepeatableAnnotation RepeatableAnnotation class My
|
||||||
|
|
||||||
|
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
RepeatableAnnotation() RepeatableAnnotation() internal final class My {
|
||||||
|
public constructor My()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
java.lang.annotation.Repeatable(value = RepeatableAnnotations::class) kotlin.annotation.annotation(repeatable = true, retention = AnnotationRetention.RUNTIME) public final class RepeatableAnnotation : kotlin.Annotation {
|
||||||
|
public constructor RepeatableAnnotation()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class RepeatableAnnotations : kotlin.Annotation {
|
||||||
|
public constructor RepeatableAnnotations(/*0*/ vararg value: RepeatableAnnotation /*kotlin.Array<out RepeatableAnnotation>*/)
|
||||||
|
public final val value: kotlin.Array<RepeatableAnnotation>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
public abstract fun value(): kotlin.Array<RepeatableAnnotation>
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// FILE: UnrepeatableAnnotation.java
|
||||||
|
|
||||||
|
public @interface UnrepeatableAnnotation {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: UnrepeatableUse.kt
|
||||||
|
|
||||||
|
UnrepeatableAnnotation <!REPEATED_ANNOTATION!>UnrepeatableAnnotation<!> class My
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
UnrepeatableAnnotation() UnrepeatableAnnotation() internal final class My {
|
||||||
|
public constructor My()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class UnrepeatableAnnotation : kotlin.Annotation {
|
||||||
|
public constructor UnrepeatableAnnotation()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ public final class JvmAnnotationNames {
|
|||||||
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
|
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
|
||||||
public static final Name TARGET_ANNOTATION_MEMBER_NAME = Name.identifier("allowedTargets");
|
public static final Name TARGET_ANNOTATION_MEMBER_NAME = Name.identifier("allowedTargets");
|
||||||
public static final Name RETENTION_ANNOTATION_PARAMETER_NAME = Name.identifier("retention");
|
public static final Name RETENTION_ANNOTATION_PARAMETER_NAME = Name.identifier("retention");
|
||||||
|
public static final Name REPEATABLE_ANNOTATION_PARAMETER_NAME = Name.identifier("repeatable");
|
||||||
|
|
||||||
public static final FqName TARGET_ANNOTATION = new FqName("java.lang.annotation.Target");
|
public static final FqName TARGET_ANNOTATION = new FqName("java.lang.annotation.Target");
|
||||||
public static final FqName RETENTION_ANNOTATION = new FqName("java.lang.annotation.Retention");
|
public static final FqName RETENTION_ANNOTATION = new FqName("java.lang.annotation.Retention");
|
||||||
|
|||||||
+45
-14
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||||
|
import org.jetbrains.kotlin.load.java.lazy.descriptors.resolveAnnotation
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument
|
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument
|
||||||
import org.jetbrains.kotlin.load.java.structure.JavaArrayAnnotationArgument
|
import org.jetbrains.kotlin.load.java.structure.JavaArrayAnnotationArgument
|
||||||
@@ -34,6 +35,8 @@ import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
|||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.*
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.*
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
|
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
|
||||||
import java.lang.annotation.Retention
|
import java.lang.annotation.Retention
|
||||||
import java.lang.annotation.Target
|
import java.lang.annotation.Target
|
||||||
@@ -47,17 +50,39 @@ public object JavaAnnotationMapper {
|
|||||||
// Java8-specific thing
|
// Java8-specific thing
|
||||||
private val javaRepeatableFqName = FqName("java.lang.annotation.Repeatable")
|
private val javaRepeatableFqName = FqName("java.lang.annotation.Repeatable")
|
||||||
|
|
||||||
public fun mapJavaAnnotation(annotation: JavaAnnotation, c: LazyJavaResolverContext): AnnotationDescriptor? =
|
public fun mapOrResolveJavaAnnotation(annotation: JavaAnnotation, c: LazyJavaResolverContext): AnnotationDescriptor? =
|
||||||
when (annotation.classId) {
|
when (annotation.classId) {
|
||||||
ClassId.topLevel(javaTargetFqName) -> JavaTargetAnnotationDescriptor(annotation, c)
|
ClassId.topLevel(javaTargetFqName) -> JavaTargetAnnotationDescriptor(annotation, c)
|
||||||
ClassId.topLevel(javaRetentionFqName) -> JavaRetentionAnnotationDescriptor(annotation, c)
|
|
||||||
ClassId.topLevel(javaDeprecatedFqName) -> JavaDeprecatedAnnotationDescriptor(annotation, c)
|
ClassId.topLevel(javaDeprecatedFqName) -> JavaDeprecatedAnnotationDescriptor(annotation, c)
|
||||||
else -> null
|
ClassId.topLevel(javaRetentionFqName) -> null
|
||||||
|
else -> c.resolveAnnotation(annotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
public val kotlinToJavaNameMap: Map<FqName, FqName> =
|
public fun findMappedJavaAnnotation(kotlinName: FqName,
|
||||||
|
annotationOwner: JavaAnnotationOwner,
|
||||||
|
c: LazyJavaResolverContext
|
||||||
|
): AnnotationDescriptor? {
|
||||||
|
if (kotlinName == KotlinBuiltIns.FQ_NAMES.annotation) {
|
||||||
|
// Construct kotlin.annotation.annotation from Retention & Repeatable
|
||||||
|
val retentionAnnotation = annotationOwner.findAnnotation(javaRetentionFqName)
|
||||||
|
val repeatableAnnotation = annotationOwner.findAnnotation(javaRepeatableFqName)
|
||||||
|
return if (retentionAnnotation != null || repeatableAnnotation != null) {
|
||||||
|
JavaRetentionRepeatableAnnotationDescriptor(retentionAnnotation, repeatableAnnotation != null, c)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kotlinToJavaNameMap[kotlinName]?.let {
|
||||||
|
annotationOwner.findAnnotation(it)?.let {
|
||||||
|
mapOrResolveJavaAnnotation(it, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kotlin.annotation.annotation is treated separately
|
||||||
|
private val kotlinToJavaNameMap: Map<FqName, FqName> =
|
||||||
mapOf(KotlinBuiltIns.FQ_NAMES.target to javaTargetFqName,
|
mapOf(KotlinBuiltIns.FQ_NAMES.target to javaTargetFqName,
|
||||||
KotlinBuiltIns.FQ_NAMES.annotation to javaRetentionFqName,
|
|
||||||
KotlinBuiltIns.FQ_NAMES.deprecated to javaDeprecatedFqName)
|
KotlinBuiltIns.FQ_NAMES.deprecated to javaDeprecatedFqName)
|
||||||
|
|
||||||
public val javaToKotlinNameMap: Map<FqName, FqName> =
|
public val javaToKotlinNameMap: Map<FqName, FqName> =
|
||||||
@@ -68,7 +93,7 @@ public object JavaAnnotationMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractJavaAnnotationDescriptor(
|
abstract class AbstractJavaAnnotationDescriptor(
|
||||||
annotation: JavaAnnotation,
|
annotation: JavaAnnotation?,
|
||||||
private val kotlinAnnotationClassDescriptor: ClassDescriptor
|
private val kotlinAnnotationClassDescriptor: ClassDescriptor
|
||||||
): AnnotationDescriptor {
|
): AnnotationDescriptor {
|
||||||
override fun getType() = kotlinAnnotationClassDescriptor.defaultType
|
override fun getType() = kotlinAnnotationClassDescriptor.defaultType
|
||||||
@@ -76,7 +101,7 @@ abstract class AbstractJavaAnnotationDescriptor(
|
|||||||
protected val valueParameters: List<ValueParameterDescriptor>
|
protected val valueParameters: List<ValueParameterDescriptor>
|
||||||
get() = kotlinAnnotationClassDescriptor.constructors.single().valueParameters
|
get() = kotlinAnnotationClassDescriptor.constructors.single().valueParameters
|
||||||
|
|
||||||
protected val firstArgument: JavaAnnotationArgument? = annotation.arguments.firstOrNull()
|
protected val firstArgument: JavaAnnotationArgument? = annotation?.arguments?.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaDeprecatedAnnotationDescriptor(
|
class JavaDeprecatedAnnotationDescriptor(
|
||||||
@@ -94,20 +119,26 @@ class JavaDeprecatedAnnotationDescriptor(
|
|||||||
override fun getAllValueArguments() = valueArguments()
|
override fun getAllValueArguments() = valueArguments()
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaRetentionAnnotationDescriptor(
|
class JavaRetentionRepeatableAnnotationDescriptor(
|
||||||
annotation: JavaAnnotation,
|
retentionAnnotation: JavaAnnotation?,
|
||||||
|
repeatable: Boolean,
|
||||||
c: LazyJavaResolverContext
|
c: LazyJavaResolverContext
|
||||||
): AbstractJavaAnnotationDescriptor(annotation, c.module.builtIns.annotationAnnotation) {
|
): AbstractJavaAnnotationDescriptor(retentionAnnotation, c.module.builtIns.annotationAnnotation) {
|
||||||
|
|
||||||
private val valueArguments = c.storageManager.createLazyValue {
|
private val valueArguments = c.storageManager.createLazyValue {
|
||||||
val targetArgument = when (firstArgument) {
|
val retentionArgument = when (firstArgument) {
|
||||||
is JavaEnumValueAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaRetentionArgument(firstArgument, c.module.builtIns)
|
is JavaEnumValueAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaRetentionArgument(firstArgument, c.module.builtIns)
|
||||||
else -> return@createLazyValue emptyMap<ValueParameterDescriptor, ConstantValue<*>>()
|
else -> null
|
||||||
}
|
}
|
||||||
val parameterDescriptor = valueParameters.firstOrNull {
|
val retentionParameterDescriptor = valueParameters.first {
|
||||||
it.name == JvmAnnotationNames.RETENTION_ANNOTATION_PARAMETER_NAME
|
it.name == JvmAnnotationNames.RETENTION_ANNOTATION_PARAMETER_NAME
|
||||||
}
|
}
|
||||||
parameterDescriptor?.let { mapOf(it to targetArgument) } ?: emptyMap()
|
val repeatableArgument = if (repeatable) BooleanValue(true, c.module.builtIns) else null
|
||||||
|
val repeatableParameterDescriptor = valueParameters.first {
|
||||||
|
it.name == JvmAnnotationNames.REPEATABLE_ANNOTATION_PARAMETER_NAME
|
||||||
|
}
|
||||||
|
(retentionArgument?.let { mapOf(retentionParameterDescriptor to it) } ?: emptyMap()) +
|
||||||
|
(repeatableArgument?.let { mapOf(repeatableParameterDescriptor to it) } ?: emptyMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAllValueArguments() = valueArguments()
|
override fun getAllValueArguments() = valueArguments()
|
||||||
|
|||||||
+5
-4
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.load.java.lazy
|
package org.jetbrains.kotlin.load.java.lazy
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.load.java.components.JavaAnnotationMapper
|
import org.jetbrains.kotlin.load.java.components.JavaAnnotationMapper
|
||||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.resolveAnnotation
|
import org.jetbrains.kotlin.load.java.lazy.descriptors.resolveAnnotation
|
||||||
@@ -29,19 +30,19 @@ class LazyJavaAnnotations(
|
|||||||
private val annotationOwner: JavaAnnotationOwner
|
private val annotationOwner: JavaAnnotationOwner
|
||||||
) : Annotations {
|
) : Annotations {
|
||||||
private val annotationDescriptors = c.storageManager.createMemoizedFunctionWithNullableValues {
|
private val annotationDescriptors = c.storageManager.createMemoizedFunctionWithNullableValues {
|
||||||
annotation: JavaAnnotation ->
|
annotation: JavaAnnotation -> JavaAnnotationMapper.mapOrResolveJavaAnnotation(annotation, c)
|
||||||
JavaAnnotationMapper.mapJavaAnnotation(annotation, c) ?: c.resolveAnnotation(annotation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findAnnotation(fqName: FqName) =
|
override fun findAnnotation(fqName: FqName) =
|
||||||
annotationOwner.findAnnotation(fqName)?.let(annotationDescriptors)
|
annotationOwner.findAnnotation(fqName)?.let(annotationDescriptors)
|
||||||
?: JavaAnnotationMapper.kotlinToJavaNameMap[fqName]?.let { annotationOwner.findAnnotation(it)?.let(annotationDescriptors) }
|
?: JavaAnnotationMapper.findMappedJavaAnnotation(fqName, annotationOwner, c)
|
||||||
|
|
||||||
override fun findExternalAnnotation(fqName: FqName) =
|
override fun findExternalAnnotation(fqName: FqName) =
|
||||||
c.externalAnnotationResolver.findExternalAnnotation(annotationOwner, fqName)?.let(annotationDescriptors)
|
c.externalAnnotationResolver.findExternalAnnotation(annotationOwner, fqName)?.let(annotationDescriptors)
|
||||||
|
|
||||||
override fun iterator() =
|
override fun iterator() =
|
||||||
annotationOwner.annotations.asSequence().map(annotationDescriptors).filterNotNull().iterator()
|
(annotationOwner.annotations.asSequence().map(annotationDescriptors)
|
||||||
|
+ JavaAnnotationMapper.findMappedJavaAnnotation(KotlinBuiltIns.FQ_NAMES.annotation, annotationOwner, c)).filterNotNull().iterator()
|
||||||
|
|
||||||
override fun isEmpty() = !iterator().hasNext()
|
override fun isEmpty() = !iterator().hasNext()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user