Report error on class named Container inside repeatable annotation
#KT-12794 #KT-47971
This commit is contained in:
+12
@@ -2177,6 +2177,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
public void testKotlinRepeatable_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_6.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_5.kt")
|
||||
public void testNestedClassContainer_1_5() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_5.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_6.kt")
|
||||
public void testNestedClassContainer_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_6.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+12
@@ -2177,6 +2177,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
public void testKotlinRepeatable_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_6.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_5.kt")
|
||||
public void testNestedClassContainer_1_5() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_5.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_6.kt")
|
||||
public void testNestedClassContainer_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_6.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+43
-8
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.resolve.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
@@ -16,7 +17,9 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -63,19 +66,51 @@ class RepeatableAnnotationChecker(
|
||||
|
||||
if (annotated is KtClassOrObject && annotated.hasModifier(KtTokens.ANNOTATION_KEYWORD)) {
|
||||
val annotationClass = trace.get(BindingContext.CLASS, annotated)
|
||||
val repeatable = annotations.find { it.descriptor.fqName == JvmAnnotationNames.REPEATABLE_ANNOTATION }
|
||||
if (annotationClass != null && repeatable != null) {
|
||||
val containerKClassValue = repeatable.descriptor.allValueArguments[Name.identifier("value")]
|
||||
if (containerKClassValue is KClassValue) {
|
||||
val containerClass = TypeUtils.getClassDescriptor(containerKClassValue.getArgumentType(module))
|
||||
if (containerClass != null) {
|
||||
checkRepeatableAnnotationContainer(annotationClass, containerClass, trace, repeatable.entry)
|
||||
}
|
||||
if (annotationClass != null) {
|
||||
val javaRepeatable = annotations.find { it.descriptor.fqName == JvmAnnotationNames.REPEATABLE_ANNOTATION }
|
||||
val kotlinRepeatable = annotations.find { it.descriptor.fqName == StandardNames.FqNames.repeatable }
|
||||
when {
|
||||
javaRepeatable != null -> checkJavaRepeatableAnnotationDeclaration(javaRepeatable, annotationClass, trace)
|
||||
kotlinRepeatable != null -> checkKotlinRepeatableAnnotationDeclaration(kotlinRepeatable, annotationClass, trace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkJavaRepeatableAnnotationDeclaration(
|
||||
javaRepeatable: ResolvedAnnotation,
|
||||
annotationClass: ClassDescriptor,
|
||||
trace: BindingTrace,
|
||||
) {
|
||||
val containerKClassValue = javaRepeatable.descriptor.allValueArguments[Name.identifier("value")]
|
||||
if (containerKClassValue is KClassValue) {
|
||||
val containerClass = TypeUtils.getClassDescriptor(containerKClassValue.getArgumentType(module))
|
||||
if (containerClass != null) {
|
||||
checkRepeatableAnnotationContainer(annotationClass, containerClass, trace, javaRepeatable.entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkKotlinRepeatableAnnotationDeclaration(
|
||||
kotlinRepeatable: ResolvedAnnotation,
|
||||
annotationClass: ClassDescriptor,
|
||||
trace: BindingTrace,
|
||||
) {
|
||||
val nestedClassNamedContainer =
|
||||
annotationClass.unsubstitutedInnerClassesScope.getContributedClassifier(
|
||||
Name.identifier(JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME),
|
||||
NoLookupLocation.FOR_ALREADY_TRACKED
|
||||
)
|
||||
if (nestedClassNamedContainer != null) {
|
||||
trace.report(
|
||||
select(
|
||||
ErrorsJvm.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER,
|
||||
ErrorsJvm.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER_ERROR
|
||||
).on(kotlinRepeatable.entry)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkRepeatedEntries(annotations: List<ResolvedAnnotation>, trace: BindingTrace) {
|
||||
val entryTypesWithAnnotations = hashMapOf<FqName, MutableList<AnnotationUseSiteTarget?>>()
|
||||
|
||||
|
||||
+2
@@ -83,6 +83,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION_ERROR, "Container annotation ''{0}'' has shorter retention (''{1}'') than the repeatable annotation ''{2}'' (''{3}'')", TO_STRING, TO_STRING, TO_STRING, TO_STRING);
|
||||
MAP.put(REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET, "Target set of container annotation ''{0}'' must be a subset of the target set of contained annotation ''{1}''. This code will be prohibited in Kotlin 1.6", TO_STRING, TO_STRING);
|
||||
MAP.put(REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET_ERROR, "Target set of container annotation ''{0}'' must be a subset of the target set of contained annotation ''{1}''", TO_STRING, TO_STRING);
|
||||
MAP.put(REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER, "Repeatable annotation cannot have a nested class named 'Container'. This name is reserved for auto-generated container class");
|
||||
MAP.put(REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER_ERROR, "Repeatable annotation cannot have a nested class named 'Container'. This name is reserved for auto-generated container class");
|
||||
|
||||
MAP.put(JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, "''@JvmPackageName'' annotation value cannot be empty");
|
||||
MAP.put(JVM_PACKAGE_NAME_MUST_BE_VALID_NAME, "''@JvmPackageName'' annotation value must be a valid dot-qualified name of a package");
|
||||
|
||||
@@ -83,6 +83,8 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory4<KtAnnotationEntry, FqName, String, FqName, String> REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION_ERROR = DiagnosticFactory4.create(ERROR);
|
||||
DiagnosticFactory2<KtAnnotationEntry, FqName, FqName> REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<KtAnnotationEntry, FqName, FqName> REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET_ERROR = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtAnnotationEntry> REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER_ERROR = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<KtAnnotationEntry, FqName> ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// !LANGUAGE: -RepeatableAnnotations -RepeatableAnnotationContainerConstraints
|
||||
// FULL_JDK
|
||||
|
||||
@Repeatable
|
||||
annotation class A1 {
|
||||
class Container
|
||||
}
|
||||
|
||||
|
||||
@java.lang.annotation.Repeatable(D1::class)
|
||||
annotation class B1 {
|
||||
class Container
|
||||
}
|
||||
annotation class D1(val value: Array<B1>)
|
||||
|
||||
@Repeatable
|
||||
@java.lang.annotation.Repeatable(D2::class)
|
||||
annotation class B2 {
|
||||
class Container
|
||||
}
|
||||
annotation class D2(val value: Array<B2>)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// !LANGUAGE: -RepeatableAnnotations -RepeatableAnnotationContainerConstraints
|
||||
// FULL_JDK
|
||||
|
||||
<!REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER!>@Repeatable<!>
|
||||
annotation class A1 {
|
||||
class Container
|
||||
}
|
||||
|
||||
|
||||
@java.lang.annotation.Repeatable(D1::class)
|
||||
annotation class B1 {
|
||||
class Container
|
||||
}
|
||||
annotation class D1(val value: Array<B1>)
|
||||
|
||||
@Repeatable
|
||||
@java.lang.annotation.Repeatable(D2::class)
|
||||
annotation class B2 {
|
||||
class Container
|
||||
}
|
||||
annotation class D2(val value: Array<B2>)
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package
|
||||
|
||||
@kotlin.annotation.Repeatable public final annotation class A1 : kotlin.Annotation {
|
||||
public constructor A1()
|
||||
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 Container {
|
||||
public constructor Container()
|
||||
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 = D1::class) public final annotation class B1 : kotlin.Annotation {
|
||||
public constructor B1()
|
||||
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 Container {
|
||||
public constructor Container()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable @java.lang.annotation.Repeatable(value = D2::class) public final annotation class B2 : kotlin.Annotation {
|
||||
public constructor B2()
|
||||
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 Container {
|
||||
public constructor Container()
|
||||
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 D1 : kotlin.Annotation {
|
||||
public constructor D1(/*0*/ value: kotlin.Array<B1>)
|
||||
public final val value: kotlin.Array<B1>
|
||||
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 D2 : kotlin.Annotation {
|
||||
public constructor D2(/*0*/ value: kotlin.Array<B2>)
|
||||
public final val value: kotlin.Array<B2>
|
||||
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
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
|
||||
// FULL_JDK
|
||||
|
||||
@Repeatable
|
||||
annotation class A1 {
|
||||
class Container
|
||||
}
|
||||
|
||||
|
||||
@java.lang.annotation.Repeatable(D1::class)
|
||||
annotation class B1 {
|
||||
class Container
|
||||
}
|
||||
annotation class D1(val value: Array<B1>)
|
||||
|
||||
@Repeatable
|
||||
@java.lang.annotation.Repeatable(D2::class)
|
||||
annotation class B2 {
|
||||
class Container
|
||||
}
|
||||
annotation class D2(val value: Array<B2>)
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
|
||||
// FULL_JDK
|
||||
|
||||
<!REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER_ERROR!>@Repeatable<!>
|
||||
annotation class A1 {
|
||||
class Container
|
||||
}
|
||||
|
||||
|
||||
@java.lang.annotation.Repeatable(D1::class)
|
||||
annotation class B1 {
|
||||
class Container
|
||||
}
|
||||
annotation class D1(val value: Array<B1>)
|
||||
|
||||
@Repeatable
|
||||
@java.lang.annotation.Repeatable(D2::class)
|
||||
annotation class B2 {
|
||||
class Container
|
||||
}
|
||||
annotation class D2(val value: Array<B2>)
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package
|
||||
|
||||
@kotlin.annotation.Repeatable public final annotation class A1 : kotlin.Annotation {
|
||||
public constructor A1()
|
||||
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 Container {
|
||||
public constructor Container()
|
||||
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 = D1::class) public final annotation class B1 : kotlin.Annotation {
|
||||
public constructor B1()
|
||||
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 Container {
|
||||
public constructor Container()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.annotation.Repeatable @java.lang.annotation.Repeatable(value = D2::class) public final annotation class B2 : kotlin.Annotation {
|
||||
public constructor B2()
|
||||
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 Container {
|
||||
public constructor Container()
|
||||
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 D1 : kotlin.Annotation {
|
||||
public constructor D1(/*0*/ value: kotlin.Array<B1>)
|
||||
public final val value: kotlin.Array<B1>
|
||||
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 D2 : kotlin.Annotation {
|
||||
public constructor D2(/*0*/ value: kotlin.Array<B2>)
|
||||
public final val value: kotlin.Array<B2>
|
||||
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
|
||||
}
|
||||
Generated
+12
@@ -2183,6 +2183,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
public void testKotlinRepeatable_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_6.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_5.kt")
|
||||
public void testNestedClassContainer_1_5() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_5.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_6.kt")
|
||||
public void testNestedClassContainer_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_6.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
+12
@@ -2177,6 +2177,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
public void testKotlinRepeatable_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/kotlinRepeatable_1_6.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_5.kt")
|
||||
public void testNestedClassContainer_1_5() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_5.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassContainer_1_6.kt")
|
||||
public void testNestedClassContainer_1_6() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/annotations/repeatable/nestedClassContainer_1_6.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
Reference in New Issue
Block a user