[FIR] Add REPEATABLE_CONTAINER_* diagnostics

REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY
REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER
REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION
REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET
REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER
This commit is contained in:
Ivan Kochurkin
2021-09-02 16:03:46 +03:00
committed by TeamCityServer
parent 6fa1c0353c
commit fa12e72551
24 changed files with 501 additions and 319 deletions
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.PositioningStrategy
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -122,6 +123,28 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
parameter<FqName>("name")
parameter<FqName>("explicitContainerName")
}
val REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY by deprecationError<KtAnnotationEntry>(RepeatableAnnotationContainerConstraints) {
parameter<ClassId>("container")
parameter<ClassId>("annotation")
}
val REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER by deprecationError<KtAnnotationEntry>(RepeatableAnnotationContainerConstraints) {
parameter<ClassId>("container")
parameter<Name>("nonDefault")
}
val REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION by deprecationError<KtAnnotationEntry>(RepeatableAnnotationContainerConstraints) {
parameter<ClassId>("container")
parameter<String>("retention")
parameter<ClassId>("annotation")
parameter<String>("annotationRetention")
}
val REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET by deprecationError<KtAnnotationEntry>(RepeatableAnnotationContainerConstraints) {
parameter<ClassId>("container")
parameter<ClassId>("annotation")
}
val REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER by deprecationError<KtAnnotationEntry>(
RepeatableAnnotationContainerConstraints
)
}
val MISC by object : DiagnosticGroup("Misc") {
@@ -8,10 +8,13 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature.DefaultMethodsCallFromJava6TargetError
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
import org.jetbrains.kotlin.config.LanguageFeature.RepeatableAnnotationContainerConstraints
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.SourceElementPositioningStrategies
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
@@ -95,6 +98,11 @@ object FirJvmErrors {
val NON_SOURCE_REPEATED_ANNOTATION by error0<KtAnnotationEntry>()
val REPEATED_ANNOTATION_TARGET6 by error0<KtAnnotationEntry>()
val REPEATED_ANNOTATION_WITH_CONTAINER by error2<KtAnnotationEntry, FqName, FqName>()
val REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY by deprecationError2<KtAnnotationEntry, ClassId, ClassId>(RepeatableAnnotationContainerConstraints)
val REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER by deprecationError2<KtAnnotationEntry, ClassId, Name>(RepeatableAnnotationContainerConstraints)
val REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION by deprecationError4<KtAnnotationEntry, ClassId, String, ClassId, String>(RepeatableAnnotationContainerConstraints)
val REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET by deprecationError2<KtAnnotationEntry, ClassId, ClassId>(RepeatableAnnotationContainerConstraints)
val REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER by deprecationError0<KtAnnotationEntry>(RepeatableAnnotationContainerConstraints)
// Misc
val INAPPLICABLE_JVM_FIELD by error1<KtAnnotationEntry, String>()
@@ -7,34 +7,41 @@ package org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAnnotatedDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
import org.jetbrains.kotlin.fir.analysis.checkers.getRetention
import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.isJvm6
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.fqName
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.scopes.getSingleClassifier
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirEnumEntrySymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() {
private val RETENTION_PARAMETER_NAME = Name.identifier("value")
private val REPEATABLE_PARAMETER_NAME = Name.identifier("value")
private val JAVA_REPEATABLE_ANNOTATION = FqName("java.lang.annotation.Repeatable")
private val JAVA_REPEATABLE_ANNOTATION = ClassId.fromString("java/lang/annotation/Repeatable")
private val REPEATABLE_ANNOTATION_CONTAINER_NAME = Name.identifier(JvmAbi.REPEATABLE_ANNOTATION_CONTAINER_NAME)
override fun check(declaration: FirAnnotatedDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
val annotationsSet = hashSetOf<FqName>()
@@ -75,6 +82,154 @@ object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() {
annotationsSet.add(fqName)
}
if (declaration is FirRegularClass) {
val javaRepeatable = annotations.find { it.fqName(session) == JAVA_REPEATABLE_ANNOTATION }
if (javaRepeatable != null) {
checkJavaRepeatableAnnotationDeclaration(javaRepeatable, declaration, context, reporter)
} else {
val kotlinRepeatable = annotations.find { it.fqName(session) == StandardNames.FqNames.repeatable }
if (kotlinRepeatable != null) {
checkKotlinRepeatableAnnotationDeclaration(kotlinRepeatable, declaration, context, reporter)
}
}
}
}
private fun checkJavaRepeatableAnnotationDeclaration(
javaRepeatable: FirAnnotationCall,
annotationClass: FirRegularClass,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val containerClassId = javaRepeatable.resolveContainerAnnotation() ?: return
val containerClassSymbol = context.session.symbolProvider.getClassLikeSymbolByClassId(containerClassId) as? FirRegularClassSymbol ?: return
checkRepeatableAnnotationContainer(annotationClass, containerClassSymbol, javaRepeatable.source, context, reporter)
}
private fun checkKotlinRepeatableAnnotationDeclaration(
kotlinRepeatable: FirAnnotationCall,
declaration: FirRegularClass,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val unsubsitutedScope = declaration.unsubstitutedScope(context)
if (unsubsitutedScope.getSingleClassifier(REPEATABLE_ANNOTATION_CONTAINER_NAME) != null) {
reporter.reportOn(kotlinRepeatable.source, FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER, context)
}
}
private fun checkRepeatableAnnotationContainer(
annotationClass: FirRegularClass,
containerClass: FirRegularClassSymbol,
annotationSource: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter
) {
checkContainerParameters(containerClass, annotationClass, annotationSource, context, reporter)
checkContainerRetention(containerClass, annotationClass, annotationSource, context, reporter)
checkContainerTarget(containerClass, annotationClass, annotationSource, context, reporter)
}
private fun checkContainerParameters(
containerClass: FirRegularClassSymbol,
annotationClass: FirRegularClass,
annotationSource: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val containerCtor =
containerClass.declarationSymbols.find { it is FirConstructorSymbol && it.isPrimary } as? FirConstructorSymbol
?: return
val valueParameterSymbols = containerCtor.valueParameterSymbols
val parameterName = JavaSymbolProvider.VALUE_METHOD_NAME
val value = valueParameterSymbols.find { it.name == parameterName }
if (value == null || !value.resolvedReturnTypeRef.isArrayType ||
value.resolvedReturnTypeRef.type.typeArguments.single().type != annotationClass.defaultType()
) {
reporter.reportOn(
annotationSource,
FirJvmErrors.REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY,
containerClass.classId,
annotationClass.classId,
context
)
return
}
val otherNonDefault = valueParameterSymbols.find { it.name != parameterName && !it.hasDefaultValue }
if (otherNonDefault != null) {
reporter.reportOn(
annotationSource,
FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER,
containerClass.classId,
otherNonDefault.name,
context
)
return
}
}
private fun checkContainerRetention(
containerClass: FirRegularClassSymbol,
annotationClass: FirRegularClass,
annotationSource: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val annotationRetention = annotationClass.symbol.getAnnotationRetention()
val containerRetention = containerClass.getAnnotationRetention()
if (containerRetention < annotationRetention) {
reporter.reportOn(
annotationSource,
FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION,
containerClass.classId,
containerRetention.name,
annotationClass.classId,
annotationRetention.name,
context
)
}
}
private fun checkContainerTarget(
containerClass: FirRegularClassSymbol,
annotationClass: FirRegularClass,
annotationSource: FirSourceElement?,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val annotationTargets = annotationClass.getAllowedAnnotationTargets()
val containerTargets = containerClass.getAllowedAnnotationTargets()
// See https://docs.oracle.com/javase/specs/jls/se16/html/jls-9.html#jls-9.6.3.
// (TBH, the rules about TYPE/TYPE_USE and TYPE_PARAMETER/TYPE_USE don't seem to make a lot of sense, but it's JLS
// so we better obey it for full interop with the Java language and reflection.)
for (target in containerTargets) {
val ok = when (target) {
in annotationTargets -> true
KotlinTarget.ANNOTATION_CLASS ->
KotlinTarget.CLASS in annotationTargets ||
KotlinTarget.TYPE in annotationTargets
KotlinTarget.CLASS ->
KotlinTarget.TYPE in annotationTargets
KotlinTarget.TYPE_PARAMETER ->
KotlinTarget.TYPE in annotationTargets
else -> false
}
if (!ok) {
reporter.reportOn(
annotationSource,
FirJvmErrors.REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET,
containerClass.classId,
annotationClass.classId,
context
)
return
}
}
}
private fun FirClassLikeSymbol<*>.isRepeatableAnnotation(session: FirSession): Boolean {
@@ -85,25 +240,24 @@ object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() {
getAnnotationRetention() == AnnotationRetention.SOURCE
}
private fun FirClassLikeSymbol<*>.getAnnotationRetention(): AnnotationRetention? {
val repeatableAnnotation = getAnnotationByFqName(StandardNames.FqNames.retention) ?: return null
val retentionValue = repeatableAnnotation.findArgumentByName(RETENTION_PARAMETER_NAME) ?: return null
val resolvedSymbol = retentionValue.toResolvedCallableSymbol() as? FirEnumEntrySymbol ?: return null
val name = resolvedSymbol.name.asString()
return AnnotationRetention.values().firstOrNull { it.name == name }
private fun FirClassLikeSymbol<*>.getAnnotationRetention(): AnnotationRetention {
return getAnnotationByFqName(StandardNames.FqNames.retention)?.getRetention() ?: AnnotationRetention.RUNTIME
}
private fun FirClassLikeSymbol<*>.resolveContainerAnnotation(): FqName? {
val repeatableAnnotation =
getAnnotationByFqName(StandardNames.FqNames.repeatable) ?: getAnnotationByFqName(JAVA_REPEATABLE_ANNOTATION) ?: return null
val value = repeatableAnnotation.findArgumentByName(REPEATABLE_PARAMETER_NAME) ?: return null
return repeatableAnnotation.resolveContainerAnnotation()?.asSingleFqName()
}
private fun FirAnnotationCall.resolveContainerAnnotation(): ClassId? {
val value = findArgumentByName(REPEATABLE_PARAMETER_NAME) ?: return null
val classCallArgument = (value as? FirGetClassCall)?.argument ?: return null
if (classCallArgument is FirResolvedQualifier) {
return classCallArgument.relativeClassFqName
return classCallArgument.classId
} else if (classCallArgument is FirClassReferenceExpression) {
val type = classCallArgument.classTypeRef.coneType.lowerBoundIfFlexible() as? ConeClassLikeType ?: return null
return type.lookupTag.classId.asSingleFqName()
return type.lookupTag.classId
}
return null
}
@@ -59,6 +59,11 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_PRIVATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATED_ANNOTATION_TARGET6
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATED_ANNOTATION_WITH_CONTAINER
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.STRICTFP_ON_CLASS
@@ -219,6 +224,37 @@ object FirJvmDefaultErrorMessages {
INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER,
"Interfaces can call default methods via super only within @JvmDefault members. Please annotate the containing interface member with @JvmDefault"
)
map.put(
REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY,
"Container annotation ''{0}'' must have a property ''value'' of type ''Array<{1}>''.",
TO_STRING,
TO_STRING
)
map.put(
REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER,
"Container annotation ''{0}'' does not have a default value for ''{1}''.",
TO_STRING,
TO_STRING
)
map.put(
REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION,
"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}''.",
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"
)
}
}
}
@@ -9,17 +9,13 @@ import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.findArgumentByName
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
@@ -30,19 +26,12 @@ import org.jetbrains.kotlin.name.Name
private val RETENTION_PARAMETER_NAME = Name.identifier("value")
private val TARGET_PARAMETER_NAME = Name.identifier("allowedTargets")
@OptIn(SymbolInternals::class)
fun FirAnnotationCall.getRetention(session: FirSession): AnnotationRetention {
val annotationClassSymbol =
(this.annotationTypeRef.coneType as? ConeClassLikeType)?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol
?: return AnnotationRetention.RUNTIME
annotationClassSymbol.ensureResolved(FirResolvePhase.BODY_RESOLVE)
val annotationClass = annotationClassSymbol.fir
return annotationClass.getRetention()
fun FirRegularClass.getRetention(): AnnotationRetention {
return getRetentionAnnotation()?.getRetention() ?: AnnotationRetention.RUNTIME
}
fun FirRegularClass.getRetention(): AnnotationRetention {
val retentionAnnotation = getRetentionAnnotation() ?: return AnnotationRetention.RUNTIME
val retentionArgument = retentionAnnotation.findArgumentByName(RETENTION_PARAMETER_NAME) as? FirQualifiedAccessExpression
fun FirAnnotationCall.getRetention(): AnnotationRetention {
val retentionArgument = findArgumentByName(RETENTION_PARAMETER_NAME) as? FirQualifiedAccessExpression
?: return AnnotationRetention.RUNTIME
val retentionName = (retentionArgument.calleeReference as? FirResolvedNamedReference)?.name?.asString()
?: return AnnotationRetention.RUNTIME
@@ -51,17 +40,19 @@ fun FirRegularClass.getRetention(): AnnotationRetention {
private val defaultAnnotationTargets = KotlinTarget.DEFAULT_TARGET_SET
@OptIn(SymbolInternals::class)
fun FirAnnotationCall.getAllowedAnnotationTargets(session: FirSession): Set<KotlinTarget> {
if (annotationTypeRef is FirErrorTypeRef) return KotlinTarget.values().toSet()
val annotationClassSymbol = (this.annotationTypeRef.coneType as? ConeClassLikeType)
?.fullyExpandedType(session)?.lookupTag?.toSymbol(session) ?: return defaultAnnotationTargets
annotationClassSymbol.ensureResolved(FirResolvePhase.BODY_RESOLVE)
val annotationClass = annotationClassSymbol.fir as? FirRegularClass
return annotationClass?.getAllowedAnnotationTargets() ?: defaultAnnotationTargets
return annotationClassSymbol.getAllowedAnnotationTargets()
}
fun FirRegularClass.getAllowedAnnotationTargets(): Set<KotlinTarget> {
return symbol.getAllowedAnnotationTargets()
}
fun FirClassLikeSymbol<*>.getAllowedAnnotationTargets(): Set<KotlinTarget> {
val targetAnnotation = getTargetAnnotation() ?: return defaultAnnotationTargets
if (targetAnnotation.argumentList.arguments.isEmpty()) return emptySet()
val arguments = targetAnnotation.findArgumentByName(TARGET_PARAMETER_NAME)?.unfoldArrayOrVararg().orEmpty()
@@ -81,6 +72,10 @@ fun FirAnnotatedDeclaration.getTargetAnnotation(): FirAnnotationCall? {
return getAnnotationByFqName(StandardNames.FqNames.target)
}
fun FirClassLikeSymbol<*>.getTargetAnnotation(): FirAnnotationCall? {
return getAnnotationByFqName(StandardNames.FqNames.target)
}
fun FirAnnotationContainer.getAnnotationByClassId(classId: ClassId): FirAnnotationCall? {
return annotations.find {
(it.annotationTypeRef.coneType as? ConeClassLikeType)?.lookupTag?.classId == classId
@@ -59,7 +59,7 @@ class JavaSymbolProvider(
private val searchScope: GlobalSearchScope,
) : FirSymbolProvider(session) {
companion object {
internal val VALUE_METHOD_NAME = Name.identifier("value")
val VALUE_METHOD_NAME = Name.identifier("value")
}
private val classCache =
@@ -1,50 +0,0 @@
// !LANGUAGE: -RepeatableAnnotations -RepeatableAnnotationContainerConstraints
// FULL_JDK
import java.lang.annotation.Repeatable as R
@R(C1::class)
annotation class A1
annotation class C1
@R(C2::class)
annotation class A2
annotation class C2(val value: A2)
@R(C3::class)
annotation class A3
annotation class C3(val value: Array<String>)
@R(C4::class)
annotation class A4
annotation class C4(val notValue: Array<A4>)
@R(C5::class)
annotation class A5
annotation class C5(val value: Array<A5>, val irrelevant: String)
@R(C6::class)
annotation class A6
annotation class C6(val irrelevant: Double, val value: Array<A6> = [])
// Should be an error after fixing KT-47932.
@R(A7::class)
annotation class A7(val value: Array<A7>)
@R(D1::class)
annotation class B1
annotation class D1(val value: Array<B1>)
@R(D2::class)
annotation class B2
annotation class D2(val value: Array<B2> = [])
@R(D3::class)
annotation class B3
annotation class D3(val value: Array<B3>, val other1: String = "", val other2: Int = 42)
@R(D4::class)
annotation class B4
annotation class D4(val value1: Array<B4> = [], val value: Array<B4>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -RepeatableAnnotations -RepeatableAnnotationContainerConstraints
// FULL_JDK
@@ -1,50 +0,0 @@
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
// FULL_JDK
import java.lang.annotation.Repeatable as R
@R(C1::class)
annotation class A1
annotation class C1
@R(C2::class)
annotation class A2
annotation class C2(val value: A2)
@R(C3::class)
annotation class A3
annotation class C3(val value: Array<String>)
@R(C4::class)
annotation class A4
annotation class C4(val notValue: Array<A4>)
@R(C5::class)
annotation class A5
annotation class C5(val value: Array<A5>, val irrelevant: String)
@R(C6::class)
annotation class A6
annotation class C6(val irrelevant: Double, val value: Array<A6> = [])
// Should be an error after fixing KT-47932.
@R(A7::class)
annotation class A7(val value: Array<A7>)
@R(D1::class)
annotation class B1
annotation class D1(val value: Array<B1>)
@R(D2::class)
annotation class B2
annotation class D2(val value: Array<B2> = [])
@R(D3::class)
annotation class B3
annotation class D3(val value: Array<B3>, val other1: String = "", val other2: Int = 42)
@R(D4::class)
annotation class B4
annotation class D4(val value1: Array<B4> = [], val value: Array<B4>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
// FULL_JDK
@@ -1,40 +0,0 @@
// !LANGUAGE: -RepeatableAnnotations -RepeatableAnnotationContainerConstraints
// FULL_JDK
import java.lang.annotation.Repeatable as R
import kotlin.annotation.AnnotationRetention.*
@R(C1::class)
@Retention(RUNTIME)
annotation class A1
@Retention(BINARY)
annotation class C1(val value: Array<A1>)
@R(C2::class)
@Retention(BINARY)
annotation class A2
@Retention(SOURCE)
annotation class C2(val value: Array<A2>)
@R(C3::class)
annotation class A3
@Retention(SOURCE)
annotation class C3(val value: Array<A3>)
@R(D1::class)
annotation class B1
@Retention(RUNTIME)
annotation class D1(val value: Array<B1>)
@R(D2::class)
@Retention(SOURCE)
annotation class B2
@Retention(BINARY)
annotation class D2(val value: Array<B2>)
@R(D3::class)
@Retention(BINARY)
annotation class B3
annotation class D3(val value: Array<B3>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -RepeatableAnnotations -RepeatableAnnotationContainerConstraints
// FULL_JDK
@@ -1,40 +0,0 @@
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
// FULL_JDK
import java.lang.annotation.Repeatable as R
import kotlin.annotation.AnnotationRetention.*
@R(C1::class)
@Retention(RUNTIME)
annotation class A1
@Retention(BINARY)
annotation class C1(val value: Array<A1>)
@R(C2::class)
@Retention(BINARY)
annotation class A2
@Retention(SOURCE)
annotation class C2(val value: Array<A2>)
@R(C3::class)
annotation class A3
@Retention(SOURCE)
annotation class C3(val value: Array<A3>)
@R(D1::class)
annotation class B1
@Retention(RUNTIME)
annotation class D1(val value: Array<B1>)
@R(D2::class)
@Retention(SOURCE)
annotation class B2
@Retention(BINARY)
annotation class D2(val value: Array<B2>)
@R(D3::class)
@Retention(BINARY)
annotation class B3
annotation class D3(val value: Array<B3>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
// FULL_JDK
@@ -1,53 +0,0 @@
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
// FULL_JDK
import java.lang.annotation.Repeatable as R
import kotlin.annotation.AnnotationTarget.*
@R(C1::class)
annotation class A1
@Target(FILE)
annotation class C1(val value: Array<A1>)
@R(C2::class)
@Target(CLASS)
annotation class A2
@Target(CLASS, FUNCTION)
annotation class C2(val value: Array<A2>)
@R(C3::class)
@Target(TYPE)
annotation class A3
annotation class C3(val value: Array<A3>)
@R(C4::class)
@Target(ANNOTATION_CLASS)
annotation class A4
@Target(CLASS)
annotation class C4(val value: Array<A4>)
@R(D1::class)
annotation class B1
@Target(CLASS, ANNOTATION_CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER) // Default target set
annotation class D1(val value: Array<B1>)
@R(D2::class)
@Target(CLASS, FILE)
annotation class B2
@Target(CLASS)
annotation class D2(val value: Array<B2>)
@R(D3::class)
@Target(CLASS)
annotation class B3
@Target(ANNOTATION_CLASS)
annotation class D3(val value: Array<B3>)
@R(D4::class)
@Target(TYPE)
annotation class B4
@Target(ANNOTATION_CLASS, CLASS, TYPE_PARAMETER)
annotation class D4(val value: Array<B4>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
// FULL_JDK
@@ -1,21 +0,0 @@
// !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>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -RepeatableAnnotations -RepeatableAnnotationContainerConstraints
// FULL_JDK
@@ -1,21 +0,0 @@
// !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>)
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +RepeatableAnnotations +RepeatableAnnotationContainerConstraints
// FULL_JDK
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
@@ -335,6 +336,7 @@ private object FirToKtConversionCreator {
LanguageVersionSettings::class,
Variance::class,
FqName::class,
ClassId::class,
FirModuleData::class,
ExpectActualCompatibility.Incompatible::class,
DeprecationInfo::class,
@@ -2526,7 +2526,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
firDiagnostic.b,
firDiagnostic.c.mapKeys { (incompatible, _) ->
incompatible
}.mapValues { (_, collection) ->
}.mapValues { (_, collection) ->
collection.map { firBasedSymbol ->
firSymbolBuilder.buildSymbol(firBasedSymbol.fir)
}
@@ -2540,7 +2540,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir),
firDiagnostic.b.mapKeys { (incompatible, _) ->
incompatible
}.mapValues { (_, collection) ->
}.mapValues { (_, collection) ->
collection.map { firBasedSymbol ->
firSymbolBuilder.buildSymbol(firBasedSymbol.fir)
}
@@ -2575,7 +2575,7 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
firDiagnostic.b.map { pair ->
firSymbolBuilder.buildSymbol(pair.first.fir) to pair.second.mapKeys { (incompatible, _) ->
incompatible
}.mapValues { (_, collection) ->
}.mapValues { (_, collection) ->
collection.map { firBasedSymbol ->
firSymbolBuilder.buildSymbol(firBasedSymbol.fir)
}
@@ -3806,6 +3806,86 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY.errorFactory) { firDiagnostic ->
RepeatableContainerMustHaveValueArrayErrorImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_MUST_HAVE_VALUE_ARRAY.warningFactory) { firDiagnostic ->
RepeatableContainerMustHaveValueArrayWarningImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER.errorFactory) { firDiagnostic ->
RepeatableContainerHasNonDefaultParameterErrorImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER.warningFactory) { firDiagnostic ->
RepeatableContainerHasNonDefaultParameterWarningImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION.errorFactory) { firDiagnostic ->
RepeatableContainerHasShorterRetentionErrorImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic.c,
firDiagnostic.d,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION.warningFactory) { firDiagnostic ->
RepeatableContainerHasShorterRetentionWarningImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic.c,
firDiagnostic.d,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET.errorFactory) { firDiagnostic ->
RepeatableContainerTargetSetNotASubsetErrorImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_CONTAINER_TARGET_SET_NOT_A_SUBSET.warningFactory) { firDiagnostic ->
RepeatableContainerTargetSetNotASubsetWarningImpl(
firDiagnostic.a,
firDiagnostic.b,
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER.errorFactory) { firDiagnostic ->
RepeatableAnnotationHasNestedClassNamedContainerErrorImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER.warningFactory) { firDiagnostic ->
RepeatableAnnotationHasNestedClassNamedContainerWarningImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.INAPPLICABLE_JVM_FIELD) { firDiagnostic ->
InapplicableJvmFieldImpl(
firDiagnostic.a,
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtVariableSymbol
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -2646,6 +2647,66 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val explicitContainerName: FqName
}
abstract class RepeatableContainerMustHaveValueArrayError : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerMustHaveValueArrayError::class
abstract val container: ClassId
abstract val annotation: ClassId
}
abstract class RepeatableContainerMustHaveValueArrayWarning : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerMustHaveValueArrayWarning::class
abstract val container: ClassId
abstract val annotation: ClassId
}
abstract class RepeatableContainerHasNonDefaultParameterError : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerHasNonDefaultParameterError::class
abstract val container: ClassId
abstract val nonDefault: Name
}
abstract class RepeatableContainerHasNonDefaultParameterWarning : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerHasNonDefaultParameterWarning::class
abstract val container: ClassId
abstract val nonDefault: Name
}
abstract class RepeatableContainerHasShorterRetentionError : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerHasShorterRetentionError::class
abstract val container: ClassId
abstract val retention: String
abstract val annotation: ClassId
abstract val annotationRetention: String
}
abstract class RepeatableContainerHasShorterRetentionWarning : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerHasShorterRetentionWarning::class
abstract val container: ClassId
abstract val retention: String
abstract val annotation: ClassId
abstract val annotationRetention: String
}
abstract class RepeatableContainerTargetSetNotASubsetError : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerTargetSetNotASubsetError::class
abstract val container: ClassId
abstract val annotation: ClassId
}
abstract class RepeatableContainerTargetSetNotASubsetWarning : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableContainerTargetSetNotASubsetWarning::class
abstract val container: ClassId
abstract val annotation: ClassId
}
abstract class RepeatableAnnotationHasNestedClassNamedContainerError : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableAnnotationHasNestedClassNamedContainerError::class
}
abstract class RepeatableAnnotationHasNestedClassNamedContainerWarning : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatableAnnotationHasNestedClassNamedContainerWarning::class
}
abstract class InapplicableJvmField : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = InapplicableJvmField::class
abstract val message: String
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.lexer.KtKeywordToken
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry
@@ -4303,6 +4304,96 @@ internal class RepeatedAnnotationWithContainerImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerMustHaveValueArrayErrorImpl(
override val container: ClassId,
override val annotation: ClassId,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerMustHaveValueArrayError(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerMustHaveValueArrayWarningImpl(
override val container: ClassId,
override val annotation: ClassId,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerMustHaveValueArrayWarning(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerHasNonDefaultParameterErrorImpl(
override val container: ClassId,
override val nonDefault: Name,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerHasNonDefaultParameterError(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerHasNonDefaultParameterWarningImpl(
override val container: ClassId,
override val nonDefault: Name,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerHasNonDefaultParameterWarning(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerHasShorterRetentionErrorImpl(
override val container: ClassId,
override val retention: String,
override val annotation: ClassId,
override val annotationRetention: String,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerHasShorterRetentionError(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerHasShorterRetentionWarningImpl(
override val container: ClassId,
override val retention: String,
override val annotation: ClassId,
override val annotationRetention: String,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerHasShorterRetentionWarning(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerTargetSetNotASubsetErrorImpl(
override val container: ClassId,
override val annotation: ClassId,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerTargetSetNotASubsetError(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableContainerTargetSetNotASubsetWarningImpl(
override val container: ClassId,
override val annotation: ClassId,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableContainerTargetSetNotASubsetWarning(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableAnnotationHasNestedClassNamedContainerErrorImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableAnnotationHasNestedClassNamedContainerError(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatableAnnotationHasNestedClassNamedContainerWarningImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatableAnnotationHasNestedClassNamedContainerWarning(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class InapplicableJvmFieldImpl(
override val message: String,
firDiagnostic: FirPsiDiagnostic,