Remove mapping of java.Repeatable to kotlin.Repeatable in JavaAnnotationMapper

The main motivation for this change is that
java.lang.annotation.Repeatable has a parameter for the container
annotation, which is lost during conversion to
kotlin.annotation.Repeatable. To support j.l.a.Repeatable in backend
properly, it's absolutely necessary to be able to load the container
annotation for any repeatable annotation class, so the original
j.l.a.Repeatable needs to be stored in the descriptor and accessible
from the backend.

Instead of mapping j.l.a.Repeatable -> k.a.Repeatable, add a frontend
service PlatformAnnotationFeaturesSupport that will determine if an
annotation is repeatable "according to the platform rules", which for
JVM means that it's annotated with j.l.a.Repeatable.

Some effects of this change include:
- Usages of j.l.a.Repeatable are no longer reported as "deprecated", the
  corresponding test is deleted
- Usages of repeatable annotations declared in Java with non-SOURCE
  retention with LV 1.5 and earlier will now result in a slightly
  different error (REPEATED_ANNOTATION instead of
  NON_SOURCE_REPEATED_ANNOTATION)

 #KT-12794
This commit is contained in:
Alexander Udalov
2021-07-20 18:08:10 +02:00
parent ebf837c135
commit f723389565
15 changed files with 64 additions and 90 deletions
@@ -1139,12 +1139,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("deprecatedRepeatable.kt")
public void testDeprecatedRepeatable() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/deprecatedRepeatable.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {
@@ -1139,12 +1139,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("deprecatedRepeatable.kt")
public void testDeprecatedRepeatable() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/deprecatedRepeatable.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.jvm
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.REPEATABLE_ANNOTATION
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.resolve.PlatformAnnotationFeaturesSupport
import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention
class JvmPlatformAnnotationFeaturesSupport(
private val languageVersionSettings: LanguageVersionSettings,
) : PlatformAnnotationFeaturesSupport {
override fun isRepeatableAnnotationClass(descriptor: ClassDescriptor): Boolean {
check(descriptor.kind == ClassKind.ANNOTATION_CLASS) { descriptor }
// This service only handles annotation classes annotated with java.lang.annotation.Repeatable.
if (!descriptor.annotations.hasAnnotation(REPEATABLE_ANNOTATION)) return false
// Before 1.6, only Java annotations with SOURCE retention could be used as repeatable.
// (Note that _Kotlin_ annotations must have been annotated with kotlin.annotation.Repeatable, not j.l.a.Repeatable!)
return languageVersionSettings.supportsFeature(LanguageFeature.RepeatableAnnotations) ||
descriptor.getAnnotationRetention() == KotlinRetention.SOURCE && descriptor is JavaClassDescriptor
}
}
@@ -115,6 +115,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
container.useImpl<JvmSamConversionOracle>()
container.useImpl<JvmAdditionalClassPartsProvider>()
container.useImpl<JvmRecordApplicabilityChecker>()
container.useImpl<JvmPlatformAnnotationFeaturesSupport>()
container.useInstance(FunctionWithBigAritySupport.LanguageVersionDependent)
container.useInstance(GenericArrayClassLiteralSupport.Enabled)
@@ -34,7 +34,8 @@ import org.jetbrains.kotlin.types.isError
class AnnotationChecker(
private val additionalCheckers: Iterable<AdditionalAnnotationChecker>,
private val languageVersionSettings: LanguageVersionSettings
private val languageVersionSettings: LanguageVersionSettings,
private val platformAnnotationFeaturesSupport: PlatformAnnotationFeaturesSupport,
) {
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
val actualTargets = getActualTargetList(annotated, descriptor, trace.bindingContext)
@@ -132,7 +133,7 @@ class AnnotationChecker(
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() ?: property.getDefaultUseSiteTarget(descriptor)
val existingAnnotations = propertyAnnotations[useSiteTarget] ?: continue
if (classDescriptor in existingAnnotations && !classDescriptor.isRepeatableAnnotation()) {
if (classDescriptor in existingAnnotations && !isRepeatableAnnotation(classDescriptor)) {
if (reportError) {
trace.reportDiagnosticOnce(Errors.REPEATED_ANNOTATION.on(entry))
} else {
@@ -231,7 +232,7 @@ class AnnotationChecker(
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation
|| (existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) })
if (duplicateAnnotation && !classDescriptor.isRepeatableAnnotation()) {
if (duplicateAnnotation && !isRepeatableAnnotation(classDescriptor)) {
trace.report(Errors.REPEATED_ANNOTATION.on(entry))
}
@@ -292,6 +293,9 @@ class AnnotationChecker(
}
}
private fun isRepeatableAnnotation(descriptor: ClassDescriptor): Boolean =
descriptor.isRepeatableAnnotation() || platformAnnotationFeaturesSupport.isRepeatableAnnotationClass(descriptor)
companion object {
private val TARGET_ALLOWED_TARGETS = Name.identifier("allowedTargets")
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.container.DefaultImplementation
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@DefaultImplementation(PlatformAnnotationFeaturesSupport.Default::class)
interface PlatformAnnotationFeaturesSupport {
fun isRepeatableAnnotationClass(descriptor: ClassDescriptor): Boolean
object Default : PlatformAnnotationFeaturesSupport {
override fun isRepeatableAnnotationClass(descriptor: ClassDescriptor): Boolean = false
}
}
@@ -1,11 +0,0 @@
// FULL_JDK
import java.lang.annotation.Repeatable
@java.lang.annotation.Repeatable(Annotations::class) annotation class RepAnn
@Repeatable(OtherAnnotations::class) annotation class OtherAnn
annotation class Annotations(vararg val value: RepAnn)
annotation class OtherAnnotations(vararg val value: OtherAnn)
@@ -1,11 +0,0 @@
// FULL_JDK
import java.lang.annotation.Repeatable
<!DEPRECATED_JAVA_ANNOTATION!>@java.lang.annotation.Repeatable(Annotations::class)<!> annotation class RepAnn
<!DEPRECATED_JAVA_ANNOTATION!>@Repeatable(OtherAnnotations::class)<!> annotation class OtherAnn
annotation class Annotations(vararg val value: RepAnn)
annotation class OtherAnnotations(vararg val value: OtherAnn)
@@ -1,31 +0,0 @@
package
public final annotation class Annotations : kotlin.Annotation {
public constructor Annotations(/*0*/ vararg value: RepAnn /*kotlin.Array<out RepAnn>*/)
public final val value: kotlin.Array<out RepAnn>
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 = OtherAnnotations::class) public final annotation class OtherAnn : kotlin.Annotation {
public constructor OtherAnn()
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 annotation class OtherAnnotations : kotlin.Annotation {
public constructor OtherAnnotations(/*0*/ vararg value: OtherAnn /*kotlin.Array<out OtherAnn>*/)
public final val value: kotlin.Array<out OtherAnn>
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 = Annotations::class) public final annotation class RepAnn : kotlin.Annotation {
public constructor RepAnn()
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
}
@@ -37,10 +37,10 @@ public @interface Source {
// FILE: usage.kt
@Runtime <!NON_SOURCE_REPEATED_ANNOTATION!>@Runtime<!>
@Runtime <!REPEATED_ANNOTATION!>@Runtime<!>
class UseRuntime
@Clazz <!NON_SOURCE_REPEATED_ANNOTATION!>@Clazz<!>
@Clazz <!REPEATED_ANNOTATION!>@Clazz<!>
class UseClazz
@Source @Source
@@ -1,6 +1,6 @@
package
@kotlin.annotation.Repeatable @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class Clazz : kotlin.Annotation {
@java.lang.annotation.Repeatable(value = Clazz.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class Clazz : kotlin.Annotation {
public constructor Clazz()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -15,7 +15,7 @@ package
}
}
@kotlin.annotation.Repeatable @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class Runtime : kotlin.Annotation {
@java.lang.annotation.Repeatable(value = Runtime.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class Runtime : kotlin.Annotation {
public constructor Runtime()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -30,7 +30,7 @@ package
}
}
@kotlin.annotation.Repeatable @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class Source : kotlin.Annotation {
@java.lang.annotation.Repeatable(value = Source.Container::class) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class Source : kotlin.Annotation {
public constructor Source()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -1145,12 +1145,6 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("deprecatedRepeatable.kt")
public void testDeprecatedRepeatable() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/deprecatedRepeatable.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {
@@ -218,6 +218,7 @@ enum class LanguageFeature(
InstantiationOfAnnotationClasses(KOTLIN_1_6),
OptInOnOverrideForbidden(KOTLIN_1_6, kind = BUG_FIX),
OptInContagiousSignatures(KOTLIN_1_6, kind = BUG_FIX),
RepeatableAnnotations(KOTLIN_1_6),
// 1.7
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.types.SimpleType
import java.util.*
object JavaAnnotationMapper {
// Java8-specific thing
internal val DEPRECATED_ANNOTATION_MESSAGE = Name.identifier("message")
internal val TARGET_ANNOTATION_ALLOWED_TARGETS = Name.identifier("allowedTargets")
internal val RETENTION_ANNOTATION_VALUE = Name.identifier("value")
@@ -52,7 +51,6 @@ object JavaAnnotationMapper {
when (annotation.classId) {
ClassId.topLevel(TARGET_ANNOTATION) -> JavaTargetAnnotationDescriptor(annotation, c)
ClassId.topLevel(RETENTION_ANNOTATION) -> JavaRetentionAnnotationDescriptor(annotation, c)
ClassId.topLevel(REPEATABLE_ANNOTATION) -> JavaAnnotationDescriptor(c, annotation, StandardNames.FqNames.repeatable)
ClassId.topLevel(DOCUMENTED_ANNOTATION) -> JavaAnnotationDescriptor(c, annotation, StandardNames.FqNames.mustBeDocumented)
ClassId.topLevel(DEPRECATED_ANNOTATION) -> null
else -> LazyJavaAnnotationDescriptor(c, annotation, isFreshlySupportedAnnotation)
@@ -76,12 +74,10 @@ object JavaAnnotationMapper {
}
}
// kotlin.annotation.annotation is treated separately
private val kotlinToJavaNameMap: Map<FqName, FqName> =
mapOf(
StandardNames.FqNames.target to TARGET_ANNOTATION,
StandardNames.FqNames.retention to RETENTION_ANNOTATION,
StandardNames.FqNames.repeatable to REPEATABLE_ANNOTATION,
StandardNames.FqNames.mustBeDocumented to DOCUMENTED_ANNOTATION
)
@@ -90,7 +86,6 @@ object JavaAnnotationMapper {
TARGET_ANNOTATION to StandardNames.FqNames.target,
RETENTION_ANNOTATION to StandardNames.FqNames.retention,
DEPRECATED_ANNOTATION to StandardNames.FqNames.deprecated,
REPEATABLE_ANNOTATION to StandardNames.FqNames.repeatable,
DOCUMENTED_ANNOTATION to StandardNames.FqNames.mustBeDocumented
)
}
@@ -1139,12 +1139,6 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/annotations/Deprecated.kt");
}
@Test
@TestMetadata("deprecatedRepeatable.kt")
public void testDeprecatedRepeatable() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/deprecatedRepeatable.kt");
}
@Test
@TestMetadata("dontReportWarningAboutChangingExecutionOrderForVararg.kt")
public void testDontReportWarningAboutChangingExecutionOrderForVararg() throws Exception {