[FIR] Add REPEATED_ANNOTATION, REPEATED_ANNOTATION_WARNING

This commit is contained in:
Ivan Kochurkin
2021-09-06 14:36:26 +03:00
committed by TeamCityServer
parent fa12e72551
commit 55f33999f1
40 changed files with 300 additions and 440 deletions
@@ -9,7 +9,7 @@ public @interface Ann {
// FILE: main.kt
@Ann(x = 10, s = "")
@Ann(<!ARGUMENT_TYPE_MISMATCH!>10<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>)
@Ann(x = 10, s = "", y = 10)
<!REPEATED_ANNOTATION!>@Ann(<!ARGUMENT_TYPE_MISMATCH!>10<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
<!REPEATED_ANNOTATION!>@Ann(x = 10, s = "", y = 10)<!>
class A
@@ -267,6 +267,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<String>("useSiteDescription")
}
val INAPPLICABLE_FILE_TARGET by error<KtAnnotationEntry>(PositioningStrategy.ANNOTATION_USE_SITE)
val REPEATED_ANNOTATION by error<KtAnnotationEntry>()
val REPEATED_ANNOTATION_WARNING by warning<KtAnnotationEntry>()
}
val EXPERIMENTAL by object : DiagnosticGroup("OptIn-related") {
@@ -7,14 +7,12 @@ 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.AnnotationUseSiteTarget
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.*
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
@@ -44,7 +42,7 @@ object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() {
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>()
val annotationsMap = hashMapOf<ConeKotlinType, MutableList<AnnotationUseSiteTarget?>>()
val session = context.session
val annotations = declaration.annotations
@@ -54,9 +52,13 @@ object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() {
if (annotationClassId.isLocal) continue
val annotationClass = session.symbolProvider.getClassLikeSymbolByClassId(annotationClassId) ?: continue
// TODO: consider REPEATED_ANNOTATION ?
if (fqName in annotationsSet &&
annotationClass.isRepeatableAnnotation(session) &&
val useSiteTarget = annotation.useSiteTarget
val existingTargetsForAnnotation = annotationsMap.getOrPut(annotation.annotationTypeRef.coneType) { arrayListOf() }
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation ||
existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) }
if (duplicateAnnotation &&
annotationClass.containsRepeatableAnnotation(session) &&
annotationClass.getAnnotationRetention() != AnnotationRetention.SOURCE
) {
if (context.isJvm6()) {
@@ -80,22 +82,44 @@ object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() {
}
}
annotationsSet.add(fqName)
existingTargetsForAnnotation.add(useSiteTarget)
}
if (declaration is FirRegularClass) {
val javaRepeatable = annotations.find { it.fqName(session) == JAVA_REPEATABLE_ANNOTATION }
if (javaRepeatable != null) {
checkJavaRepeatableAnnotationDeclaration(javaRepeatable, declaration, context, reporter)
withSuppressedDiagnostics(javaRepeatable, context) {
checkJavaRepeatableAnnotationDeclaration(javaRepeatable, declaration, context, reporter)
}
} else {
val kotlinRepeatable = annotations.find { it.fqName(session) == StandardNames.FqNames.repeatable }
if (kotlinRepeatable != null) {
checkKotlinRepeatableAnnotationDeclaration(kotlinRepeatable, declaration, context, reporter)
withSuppressedDiagnostics(kotlinRepeatable, context) {
checkKotlinRepeatableAnnotationDeclaration(kotlinRepeatable, declaration, context, reporter)
}
}
}
}
}
private fun FirClassLikeSymbol<*>.resolveContainerAnnotation(): FqName? {
val repeatableAnnotation =
getAnnotationByFqName(StandardNames.FqNames.repeatable) ?: getAnnotationByFqName(JAVA_REPEATABLE_ANNOTATION) ?: 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.classId
} else if (classCallArgument is FirClassReferenceExpression) {
val type = classCallArgument.classTypeRef.coneType.lowerBoundIfFlexible() as? ConeClassLikeType ?: return null
return type.lookupTag.classId
}
return null
}
private fun checkJavaRepeatableAnnotationDeclaration(
javaRepeatable: FirAnnotationCall,
annotationClass: FirRegularClass,
@@ -231,34 +255,4 @@ object FirRepeatableAnnotationChecker : FirAnnotatedDeclarationChecker() {
}
}
}
private fun FirClassLikeSymbol<*>.isRepeatableAnnotation(session: FirSession): Boolean {
if (getAnnotationByFqName(StandardNames.FqNames.repeatable) != null) return true
if (getAnnotationByFqName(JAVA_REPEATABLE_ANNOTATION) == null) return false
return session.languageVersionSettings.supportsFeature(LanguageFeature.RepeatableAnnotations) ||
getAnnotationRetention() == AnnotationRetention.SOURCE
}
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
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.classId
} else if (classCallArgument is FirClassReferenceExpression) {
val type = classCallArgument.classTypeRef.coneType.lowerBoundIfFlexible() as? ConeClassLikeType ?: return null
return type.lookupTag.classId
}
return null
}
}
@@ -234,6 +234,8 @@ object FirErrors {
val INAPPLICABLE_PARAM_TARGET by error0<KtAnnotationEntry>()
val REDUNDANT_ANNOTATION_TARGET by warning1<KtAnnotationEntry, String>()
val INAPPLICABLE_FILE_TARGET by error0<KtAnnotationEntry>(SourceElementPositioningStrategies.ANNOTATION_USE_SITE)
val REPEATED_ANNOTATION by error0<KtAnnotationEntry>()
val REPEATED_ANNOTATION_WARNING by warning0<KtAnnotationEntry>()
// OptIn-related
val EXPERIMENTAL_API_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -6,13 +6,24 @@
package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
@@ -21,10 +32,15 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.UseSiteTargetsList
private val RETENTION_PARAMETER_NAME = Name.identifier("value")
private val TARGET_PARAMETER_NAME = Name.identifier("allowedTargets")
private val JAVA_REPEATABLE_ANNOTATION = FqName("java.lang.annotation.Repeatable")
private val JAVA_REPEATABLE_ANNOTATION_CLASS_ID = ClassId.topLevel(JAVA_REPEATABLE_ANNOTATION)
private val JVM_REPEATABLE_ANNOTATION_CLASS_ID = ClassId.fromString("kotlin/jvm/JvmRepeatable")
fun FirRegularClass.getRetention(): AnnotationRetention {
return getRetentionAnnotation()?.getRetention() ?: AnnotationRetention.RUNTIME
@@ -90,6 +106,69 @@ fun FirExpression.extractClassesFromArgument(): List<FirRegularClassSymbol> {
}
}
fun checkRepeatedAnnotation(
useSiteTarget: AnnotationUseSiteTarget?,
existingTargetsForAnnotation: MutableList<AnnotationUseSiteTarget?>,
annotation: FirAnnotationCall,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
val duplicated = useSiteTarget in existingTargetsForAnnotation
|| existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) }
if (duplicated && !annotation.isRepeatable(context.session) && annotation.source?.kind !is FirFakeSourceElementKind) {
reporter.reportOn(annotation.source, FirErrors.REPEATED_ANNOTATION, context)
}
}
fun FirAnnotationCall.isRepeatable(session: FirSession): Boolean {
val annotationClassId = this.toAnnotationClassId() ?: return false
if (annotationClassId.isLocal) return false
val annotationClass = session.symbolProvider.getClassLikeSymbolByFqName(annotationClassId) ?: return false
return annotationClass.containsRepeatableAnnotation(session)
}
fun FirClassLikeSymbol<*>.containsRepeatableAnnotation(session: FirSession): Boolean {
if (getAnnotationByClassId(StandardNames.FqNames.repeatableClassId) != null) return true
if (getAnnotationByClassId(JAVA_REPEATABLE_ANNOTATION_CLASS_ID) != null ||
getAnnotationByClassId(JVM_REPEATABLE_ANNOTATION_CLASS_ID) != null
) {
return session.languageVersionSettings.supportsFeature(LanguageFeature.RepeatableAnnotations) ||
getAnnotationRetention() == AnnotationRetention.SOURCE && origin == FirDeclarationOrigin.Java
}
return false
}
fun FirClassLikeSymbol<*>.getAnnotationRetention(): AnnotationRetention {
return getAnnotationByFqName(StandardNames.FqNames.retention)?.getRetention() ?: AnnotationRetention.RUNTIME
}
fun FirAnnotationContainer.getDefaultUseSiteTarget(
annotation: FirAnnotationCall,
context: CheckerContext
): AnnotationUseSiteTarget? {
return getImplicitUseSiteTargetList(context).firstOrNull {
KotlinTarget.USE_SITE_MAPPING[it] in annotation.getAllowedAnnotationTargets(context.session)
}
}
fun FirAnnotationContainer.getImplicitUseSiteTargetList(context: CheckerContext): List<AnnotationUseSiteTarget> {
return when (this) {
is FirValueParameter -> {
return if (context.findClosest<FirDeclaration>() is FirPrimaryConstructor)
UseSiteTargetsList.T_CONSTRUCTOR_PARAMETER
else
emptyList()
}
is FirProperty ->
if (!isLocal) UseSiteTargetsList.T_PROPERTY else emptyList()
is FirPropertyAccessor ->
if (isGetter) listOf(AnnotationUseSiteTarget.PROPERTY_GETTER) else listOf(AnnotationUseSiteTarget.PROPERTY_SETTER)
else ->
emptyList()
}
}
private fun FirExpression.unfoldArrayOrVararg(): List<FirExpression> {
return when (this) {
is FirVarargArgumentsExpression -> arguments
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers
import com.intellij.lang.LighterASTNode
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement
@@ -74,13 +75,10 @@ open class LightTreeSourceNavigator : SourceNavigator {
}
override fun FirSourceElement.getRawIdentifier(): String? {
val tokenType = elementType
return if (tokenType is KtNameReferenceExpressionElementType || tokenType == KtTokens.IDENTIFIER) {
lighterASTNode.toString()
} else if (tokenType is KtTypeProjectionElementType) {
lighterASTNode.getChildren(treeStructure).last().toString()
} else {
null
return when (elementType) {
is KtNameReferenceExpressionElementType, KtTokens.IDENTIFIER -> lighterASTNode.toString()
is KtTypeProjectionElementType -> lighterASTNode.getChildren(treeStructure).last().toString()
else -> null
}
}
@@ -89,10 +87,14 @@ open class LightTreeSourceNavigator : SourceNavigator {
}
override fun FirValueParameterSymbol.isCatchElementParameter(): Boolean {
val localSource = source ?: return false
var parent = localSource.treeStructure.getParent(localSource.lighterASTNode)
parent?.let { parent = localSource.treeStructure.getParent(it) }
return parent?.tokenType == KtNodeTypes.CATCH
return source?.getParentOfParent()?.tokenType == KtNodeTypes.CATCH
}
private fun FirSourceElement?.getParentOfParent(): LighterASTNode? {
val source = this ?: return null
var parent = source.treeStructure.getParent(source.lighterASTNode)
parent?.let { parent = source.treeStructure.getParent(it) }
return parent
}
}
@@ -5,28 +5,26 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
import org.jetbrains.kotlin.fir.analysis.checkers.getActualTargetList
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.argumentMapping
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.packageFqName
import org.jetbrains.kotlin.fir.resolve.fqName
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.resolve.AnnotationTargetList
import org.jetbrains.kotlin.resolve.AnnotationTargetLists
object FirAnnotationChecker : FirAnnotatedDeclarationChecker() {
private val deprecatedClassId = FqName("kotlin.Deprecated")
@@ -41,12 +39,13 @@ object FirAnnotationChecker : FirAnnotatedDeclarationChecker() {
var deprecatedSinceKotlinCall: FirAnnotationCall? = null
for (annotation in declaration.annotations) {
val fqName = annotation.fqName(context.session)
val fqName = annotation.fqName(context.session) ?: continue
if (fqName == deprecatedClassId) {
deprecatedCall = annotation
} else if (fqName == deprecatedSinceKotlinClassId) {
deprecatedSinceKotlinCall = annotation
}
withSuppressedDiagnostics(annotation, context) {
checkAnnotationTarget(declaration, annotation, context, reporter)
}
@@ -56,6 +55,14 @@ object FirAnnotationChecker : FirAnnotatedDeclarationChecker() {
checkDeprecatedCalls(deprecatedSinceKotlinCall, deprecatedCall, context, reporter)
}
}
checkRepeatedAnnotations(declaration, context, reporter)
if (declaration is FirProperty) {
checkRepeatedAnnotationsInProperty(declaration, context, reporter)
} else if (declaration is FirTypeAlias) {
checkRepeatedAnnotations(declaration.expandedTypeRef, context, reporter)
// TODO: KT-48652, implement after KT-48651
}
}
private fun checkAnnotationTarget(
@@ -199,5 +206,54 @@ object FirAnnotationChecker : FirAnnotatedDeclarationChecker() {
}
}
}
private fun checkRepeatedAnnotations(
annotationContainer: FirAnnotationContainer,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val annotationsMap = hashMapOf<ConeKotlinType, MutableList<AnnotationUseSiteTarget?>>()
for (annotation in annotationContainer.annotations) {
val useSiteTarget = annotation.useSiteTarget ?: annotationContainer.getDefaultUseSiteTarget(annotation, context)
val existingTargetsForAnnotation = annotationsMap.getOrPut(annotation.annotationTypeRef.coneType) { arrayListOf() }
withSuppressedDiagnostics(annotation, context) {
checkRepeatedAnnotation(useSiteTarget, existingTargetsForAnnotation, annotation, context, reporter)
}
existingTargetsForAnnotation.add(useSiteTarget)
}
}
private fun checkRepeatedAnnotationsInProperty(
property: FirProperty,
context: CheckerContext,
reporter: DiagnosticReporter
) {
fun FirAnnotationContainer?.getAnnotationTypes(): List<ConeKotlinType> {
return this?.annotations?.map { it.annotationTypeRef.coneType } ?: listOf()
}
val propertyAnnotations = mapOf(
AnnotationUseSiteTarget.PROPERTY_GETTER to property.getter?.getAnnotationTypes(),
AnnotationUseSiteTarget.PROPERTY_SETTER to property.setter?.getAnnotationTypes(),
AnnotationUseSiteTarget.SETTER_PARAMETER to property.setter?.valueParameters?.single().getAnnotationTypes()
)
val isError = context.session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitRepeatedUseSiteTargetAnnotations)
for (annotation in property.annotations) {
val useSiteTarget = annotation.useSiteTarget ?: property.getDefaultUseSiteTarget(annotation, context)
val existingAnnotations = propertyAnnotations[useSiteTarget] ?: continue
if (annotation.annotationTypeRef.coneType in existingAnnotations && !annotation.isRepeatable(context.session)) {
val factory = if (isError) FirErrors.REPEATED_ANNOTATION else FirErrors.REPEATED_ANNOTATION_WARNING
if (annotation.source?.kind !is FirFakeSourceElementKind) {
reporter.reportOn(annotation.source, factory, context)
}
}
}
}
}
@@ -5,10 +5,13 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.checkRepeatedAnnotation
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
import org.jetbrains.kotlin.fir.analysis.checkers.getDefaultUseSiteTarget
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -17,6 +20,8 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
object FirExpressionAnnotationChecker : FirBasicExpressionChecker() {
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -26,12 +31,22 @@ object FirExpressionAnnotationChecker : FirBasicExpressionChecker() {
expression !is FirExpression ||
expression is FirBlock && expression.source?.kind == FirFakeSourceElementKind.DesugaredForLoop
) return
val annotationsMap = hashMapOf<ConeKotlinType, MutableList<AnnotationUseSiteTarget?>>()
for (annotation in expression.annotations) {
val useSiteTarget = annotation.useSiteTarget ?: expression.getDefaultUseSiteTarget(annotation, context)
val existingTargetsForAnnotation = annotationsMap.getOrPut(annotation.annotationTypeRef.coneType) { arrayListOf() }
withSuppressedDiagnostics(annotation, context) {
if (KotlinTarget.EXPRESSION !in annotation.getAllowedAnnotationTargets(context.session)) {
reporter.reportOn(annotation.source, FirErrors.WRONG_ANNOTATION_TARGET, "expression", context)
}
checkRepeatedAnnotation(useSiteTarget, existingTargetsForAnnotation, annotation, context, reporter)
}
existingTargetsForAnnotation.add(useSiteTarget)
}
}
}
@@ -363,6 +363,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_FORB
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_PARAMETER_IN_OVERRIDE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_PARAMETER_NO_INLINE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_ANNOTATION_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_BOUND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS
@@ -691,6 +693,8 @@ class FirDefaultErrorMessages {
TO_STRING,
TO_STRING
)
map.put(REPEATED_ANNOTATION, "This annotation is not repeatable")
map.put(REPEATED_ANNOTATION_WARNING, "This annotation is not repeatable")
// OptIn
map.put(EXPERIMENTAL_API_USAGE, "{1}", TO_STRING, STRING)
@@ -88,7 +88,6 @@ private val JAVA_TARGET_CLASS_ID = ClassId.topLevel(FqName(Target::class.java.ca
private val JAVA_RETENTION_CLASS_ID = ClassId.topLevel(FqName(Retention::class.java.canonicalName))
private val JAVA_DEPRECATED_CLASS_ID = ClassId.topLevel(FqName(Deprecated::class.java.canonicalName))
private val JAVA_DOCUMENTED_CLASS_ID = ClassId.topLevel(FqName(Documented::class.java.canonicalName))
private val JAVA_REPEATABLE_CLASS_ID = ClassId.topLevel(FqName("java.lang.annotation.Repeatable")) // since Java 8
private val JAVA_TARGETS_TO_KOTLIN = mapOf(
"TYPE" to EnumSet.of(AnnotationTarget.CLASS, AnnotationTarget.FILE),
@@ -171,7 +170,6 @@ private fun JavaAnnotation.toFirAnnotationCall(
val lookupTag = when (classId) {
JAVA_TARGET_CLASS_ID -> ClassId.topLevel(StandardNames.FqNames.target)
JAVA_RETENTION_CLASS_ID -> ClassId.topLevel(StandardNames.FqNames.retention)
JAVA_REPEATABLE_CLASS_ID -> ClassId.topLevel(StandardNames.FqNames.repeatable)
JAVA_DOCUMENTED_CLASS_ID -> ClassId.topLevel(StandardNames.FqNames.mustBeDocumented)
JAVA_DEPRECATED_CLASS_ID -> ClassId.topLevel(StandardNames.FqNames.deprecated)
else -> classId
@@ -1,6 +1,5 @@
// !LANGUAGE: +RepeatableAnnotations
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// FULL_JDK
// JVM_TARGET: 1.8
@@ -5,10 +5,10 @@ annotation class A1
@Target(AnnotationTarget.TYPE_PARAMETER)
annotation class A2(val some: Int = 12)
class TopLevelClass<@A1 @A2(3) @A2 @A1(<!TOO_MANY_ARGUMENTS!>12<!>) @A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> {
class InnerClass<@A1 @A2(3) @A2 @A1(<!TOO_MANY_ARGUMENTS!>12<!>) @A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> {
class TopLevelClass<@A1 @A2(3) <!REPEATED_ANNOTATION!>@A2<!> <!REPEATED_ANNOTATION!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class InnerClass<@A1 @A2(3) <!REPEATED_ANNOTATION!>@A2<!> <!REPEATED_ANNOTATION!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
fun test() {
class InFun<@A1 @A2(3) @A2 @A1(<!TOO_MANY_ARGUMENTS!>12<!>) @A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T>
class InFun<@A1 @A2(3) <!REPEATED_ANNOTATION!>@A2<!> <!REPEATED_ANNOTATION!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T>
}
}
}
}
@@ -8,18 +8,18 @@ annotation class TA1
@Target(AnnotationTarget.TYPE_PARAMETER)
annotation class TA2(val some: Int = 12)
class TopLevelClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class InnerClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class TopLevelClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class InnerClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
fun test() {
class InFun<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T>
class InFun<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T>
}
}
}
class TTopLevelClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) @TA2 <!WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> {
class TInnerClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) @TA2 <!WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> {
class TTopLevelClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) <!REPEATED_ANNOTATION!>@TA2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class TInnerClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) <!REPEATED_ANNOTATION!>@TA2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
fun test() {
class TInFun<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) @TA2 <!WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T>
class TInFun<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) <!REPEATED_ANNOTATION!>@TA2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T>
}
}
}
@@ -9,18 +9,18 @@ annotation class TA1
@Target(AnnotationTarget.TYPE_PARAMETER)
annotation class TA2(val some: Int = 12)
class TopLevelClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class InnerClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class TopLevelClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class InnerClass<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
fun test() {
class InFun<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T>
class InFun<<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T>
}
}
}
class TTopLevelClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) @TA2 <!WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> {
class TInnerClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) @TA2 <!WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> {
class TTopLevelClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) <!REPEATED_ANNOTATION!>@TA2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
class TInnerClass<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) <!REPEATED_ANNOTATION!>@TA2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> {
fun test() {
class TInFun<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) @TA2 <!WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T>
class TInFun<<!WRONG_ANNOTATION_TARGET!>@TA1<!> @TA2(3) <!REPEATED_ANNOTATION!>@TA2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TA2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T>
}
}
}
@@ -1,13 +1,13 @@
annotation class A1
annotation class A2(val some: Int = 12)
fun <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> topFun() = 12
fun <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> topFun() = 12
class SomeClass {
fun <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> method() = 12
fun <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> method() = 12
fun foo() {
fun <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> innerFun() = 12
fun <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> innerFun() = 12
}
}
@@ -16,12 +16,12 @@ annotation class TA
@Target(AnnotationTarget.TYPE_PARAMETER)
annotation class TPA(val some: Int = 12)
fun <<!WRONG_ANNOTATION_TARGET!>@TA<!> @TPA(3) @TPA <!WRONG_ANNOTATION_TARGET!>@TA(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TPA(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> topFunTPA() = 12
fun <<!WRONG_ANNOTATION_TARGET!>@TA<!> @TPA(3) <!REPEATED_ANNOTATION!>@TPA<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TPA(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> topFunTPA() = 12
class SomeClassTPA {
fun <<!WRONG_ANNOTATION_TARGET!>@TA<!> @TPA(3) @TPA <!WRONG_ANNOTATION_TARGET!>@TA(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TPA(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> method() = 12
fun <<!WRONG_ANNOTATION_TARGET!>@TA<!> @TPA(3) <!REPEATED_ANNOTATION!>@TPA<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TPA(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> method() = 12
fun foo() {
fun <<!WRONG_ANNOTATION_TARGET!>@TA<!> @TPA(3) @TPA <!WRONG_ANNOTATION_TARGET!>@TA(<!TOO_MANY_ARGUMENTS!>12<!>)<!> @TPA(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>) T> innerFun() = 12
fun <<!WRONG_ANNOTATION_TARGET!>@TA<!> @TPA(3) <!REPEATED_ANNOTATION!>@TPA<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@TA(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION!>@TPA(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> innerFun() = 12
}
}
@@ -3,10 +3,10 @@
annotation class A1
annotation class A2(val some: Int = 12)
val <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> T.topProp: Int get() = 12
val <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> T.topProp: Int get() = 12
class SomeClass {
val <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!WRONG_ANNOTATION_TARGET!>@A2<!> <!WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> T.field: Int get() = 12
val <<!WRONG_ANNOTATION_TARGET!>@A1<!> <!WRONG_ANNOTATION_TARGET!>@A2(3)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A1(<!TOO_MANY_ARGUMENTS!>12<!>)<!> <!REPEATED_ANNOTATION, WRONG_ANNOTATION_TARGET!>@A2(<!ARGUMENT_TYPE_MISMATCH!>"Test"<!>)<!> T> T.field: Int get() = 12
fun foo() {
val <!LOCAL_VARIABLE_WITH_TYPE_PARAMETERS!><@A1 @A2(3) @A2 @A1(12) @A2("Test") T><!> localVal = 12
@@ -1,23 +0,0 @@
annotation class unrepann(val x: Int)
annotation class ann(val y: Int)
@unrepann(1) @unrepann(2) class DoubleAnnotated
@ann(3) @ann(7) @ann(42) class TripleAnnotated
@Target(AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
annotation class annexpr
@ann(0) @ann(1) fun foo(@ann(7) @ann(2) x: Int): Int {
@annexpr @annexpr return x
}
@unrepann(0)
@get:unrepann(1)
var annotated = 1 // No errors should be here
@unrepann(0)
@property:unrepann(1)
var annotated2 = 2
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
annotation class unrepann(val x: Int)
annotation class ann(val y: Int)
@@ -1,142 +0,0 @@
// !LANGUAGE: -RepeatableAnnotations
// FULL_JDK
// FILE: JR.java
import java.lang.annotation.*;
@Repeatable(JR.Container.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface JR {
public @interface Container {
JR[] value();
}
}
// FILE: JS.java
import java.lang.annotation.*;
@Repeatable(JS.Container.class)
@Retention(RetentionPolicy.SOURCE)
public @interface JS {
public @interface Container {
JS[] value();
}
}
// FILE: KR.kt
@java.lang.annotation.Repeatable(KR.Container::class)
@Retention(AnnotationRetention.RUNTIME)
annotation class KR {
annotation class Container(val value: Array<KR>)
}
// FILE: KS.kt
@java.lang.annotation.Repeatable(KS.Container::class)
@Retention(AnnotationRetention.SOURCE)
annotation class KS {
annotation class Container(val value: Array<KS>)
}
// FILE: test.kt
// Java runtime-retained annotation
@JR
@JR.Container()
fun jr1() {}
@JR
@JR.Container()
<!NON_SOURCE_REPEATED_ANNOTATION!>@JR<!>
fun jr2() {}
@JR
@JR.Container(JR())
<!NON_SOURCE_REPEATED_ANNOTATION!>@JR<!>
fun jr3() {}
@JR
@JR.Container(JR())
fun jr4() {}
@JR
@JR.Container(JR(), JR())
fun jr5() {}
// Java source-retained annotation
@JS
@JS.Container()
fun js1() {}
@JS
@JS.Container()
@JS
fun js2() {}
@JS
@JS.Container(JS())
@JS
fun js3() {}
@JS
@JS.Container(JS())
fun js4() {}
@JS
@JS.Container(JS(), JS())
fun js5() {}
// Kotlin runtime-retained annotation
@KR.Container([])
@KR
fun kr1() {}
@KR.Container([])
@KR
@KR
fun kr2() {}
@KR
@KR
@KR.Container([KR()])
fun kr3() {}
@KR.Container([KR()])
@KR
fun kr4() {}
@KR
@KR.Container([KR(), KR()])
fun kr5() {}
// Kotlin source-retained annotation
@KS.Container([])
@KS
fun ks1() {}
@KS.Container([])
@KS
@KS
fun ks2() {}
@KS
@KS
@KS.Container([KS()])
fun ks3() {}
@KS.Container([KS()])
@KS
fun ks4() {}
@KS
@KS.Container([KS(), KS()])
fun ks5() {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -RepeatableAnnotations
// FULL_JDK
// FILE: JR.java
@@ -1,48 +0,0 @@
// !LANGUAGE: -RepeatableAnnotations
// FULL_JDK
// FILE: Runtime.java
import java.lang.annotation.*;
@Repeatable(Runtime.Container.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Runtime {
public @interface Container {
Runtime[] value();
}
}
// FILE: Clazz.java
import java.lang.annotation.*;
@Repeatable(Clazz.Container.class)
@Retention(RetentionPolicy.CLASS)
public @interface Clazz {
public @interface Container {
Clazz[] value();
}
}
// FILE: Source.java
import java.lang.annotation.*;
@Repeatable(Source.Container.class)
@Retention(RetentionPolicy.SOURCE)
public @interface Source {
public @interface Container {
Source[] value();
}
}
// FILE: usage.kt
@Runtime <!NON_SOURCE_REPEATED_ANNOTATION!>@Runtime<!>
class UseRuntime
@Clazz <!NON_SOURCE_REPEATED_ANNOTATION!>@Clazz<!>
class UseClazz
@Source @Source
class UseSource
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -RepeatableAnnotations
// FULL_JDK
// FILE: Runtime.java
@@ -1,33 +0,0 @@
// !LANGUAGE: -RepeatableAnnotations
// FULL_JDK
// FILE: Runtime.java
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
public @interface Runtime {}
// FILE: Clazz.java
import java.lang.annotation.*;
@Retention(RetentionPolicy.CLASS)
public @interface Clazz {}
// FILE: Source.java
import java.lang.annotation.*;
@Retention(RetentionPolicy.SOURCE)
public @interface Source {}
// FILE: usage.kt
@Runtime @Runtime
class UseRuntime
@Clazz @Clazz
class UseClazz
@Source @Source
class UseSource
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: -RepeatableAnnotations
// FULL_JDK
// FILE: Runtime.java
@@ -1,33 +0,0 @@
// !LANGUAGE: +RepeatableAnnotations
// FULL_JDK
// FILE: Runtime.java
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
public @interface Runtime {}
// FILE: Clazz.java
import java.lang.annotation.*;
@Retention(RetentionPolicy.CLASS)
public @interface Clazz {}
// FILE: Source.java
import java.lang.annotation.*;
@Retention(RetentionPolicy.SOURCE)
public @interface Source {}
// FILE: usage.kt
@Runtime @Runtime
class UseRuntime
@Clazz @Clazz
class UseClazz
@Source @Source
class UseSource
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +RepeatableAnnotations
// FULL_JDK
// FILE: Runtime.java
@@ -1,22 +0,0 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// !LANGUAGE: -ProhibitRepeatedUseSiteTargetAnnotations
// Ann is not repeatable
annotation class Ann(val x: Int)
@get:Ann(10)
val a: String
@Ann(20) get() = "foo"
@set:Ann(10)
var b: String = ""
@Ann(20) set(value) { field = value }
@setparam:Ann(10)
var c = " "
set(@Ann(20) x) {}
@get:Ann(10)
@get:Ann(20)
val d: String
@Ann(30) @Ann(40) get() = "foo"
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_PARAMETER
// !LANGUAGE: -ProhibitRepeatedUseSiteTargetAnnotations
@@ -19,4 +20,4 @@ var c = " "
<!REPEATED_ANNOTATION_WARNING!>@get:Ann(10)<!>
<!REPEATED_ANNOTATION, REPEATED_ANNOTATION_WARNING!>@get:Ann(20)<!>
val d: String
@Ann(30) <!REPEATED_ANNOTATION!>@Ann(40)<!> get() = "foo"
@Ann(30) <!REPEATED_ANNOTATION!>@Ann(40)<!> get() = "foo"
@@ -4,19 +4,19 @@
// Ann is not repeatable
annotation class Ann(val x: Int)
@get:Ann(10)
<!REPEATED_ANNOTATION!>@get:Ann(10)<!>
val a: String
@Ann(20) get() = "foo"
@set:Ann(10)
<!REPEATED_ANNOTATION!>@set:Ann(10)<!>
var b: String = ""
@Ann(20) set(value) { field = value }
@setparam:Ann(10)
<!REPEATED_ANNOTATION!>@setparam:Ann(10)<!>
var c = " "
set(@Ann(20) x) {}
@get:Ann(10)
@get:Ann(20)
<!REPEATED_ANNOTATION!>@get:Ann(10)<!>
<!REPEATED_ANNOTATION, REPEATED_ANNOTATION!>@get:Ann(20)<!>
val d: String
@Ann(30) @Ann(40) get() = "foo"
@Ann(30) <!REPEATED_ANNOTATION!>@Ann(40)<!> get() = "foo"
@@ -9,12 +9,12 @@ class CustomDelegate {
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String = prop.name
}
public class A(@param:Ann @Ann val x: Int, @param: RepeatableAnn @Ann val y: Int) {
public class A(@param:Ann <!REPEATED_ANNOTATION!>@Ann<!> val x: Int, @param: RepeatableAnn @Ann val y: Int) {
@field:Ann @property:Ann @RepeatableAnn @property:RepeatableAnn
val a: Int = 0
@Ann @field:Ann @property:Ann
@Ann @field:Ann <!REPEATED_ANNOTATION!>@property:Ann<!>
val b: Int = 0
@field:RepeatableAnn @field:RepeatableAnn
@@ -46,14 +46,14 @@ annotation class fieldOrPropAnn
annotation class getSetAndParamAnn
public class B(<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@param:fieldOrPropAnn<!> @fieldOrPropAnn val x: Int,
@property:fieldOrPropAnn @fieldOrPropAnn val y: Int) {
@property:fieldOrPropAnn <!REPEATED_ANNOTATION, REPEATED_ANNOTATION!>@fieldOrPropAnn<!> val y: Int) {
@fieldOrPropAnn @field:fieldOrPropAnn
val z: Int = 42
<!WRONG_ANNOTATION_TARGET!>@getSetAndParamAnn<!>
@setparam:getSetAndParamAnn
<!REPEATED_ANNOTATION!>@setparam:getSetAndParamAnn<!>
var w: Int
@getSetAndParamAnn @get:getSetAndParamAnn get() = 0
@getSetAndParamAnn <!REPEATED_ANNOTATION!>@get:getSetAndParamAnn<!> get() = 0
// See KT-15470: fake INAPPLICABLE_TARGET_ON_PROPERTY
@getSetAndParamAnn <!INAPPLICABLE_TARGET_ON_PROPERTY!>@set:getSetAndParamAnn<!> set(arg) {}
}
@getSetAndParamAnn <!INAPPLICABLE_TARGET_ON_PROPERTY, REPEATED_ANNOTATION!>@set:getSetAndParamAnn<!> set(arg) {}
}
@@ -1,5 +1,5 @@
class Test {
@`InnerAnnotation` @InnerAnnotation
@`InnerAnnotation` <!REPEATED_ANNOTATION!>@InnerAnnotation<!>
companion object : StaticClass(), <!MANY_CLASSES_IN_SUPERTYPE_LIST, UNRESOLVED_REFERENCE!>InnerClass<!>() {
}
@@ -5,7 +5,7 @@ annotation class A
annotation class B
typealias Test0 = @A @B Int
typealias Test1 = @A() (@A Int)
typealias Test1 = @A() (<!REPEATED_ANNOTATION!>@A<!> Int)
typealias Test2 = @A() (@B Int)
typealias Test3 = @A() (@A Int) -> Int
typealias Test4 = @A() (@B Int)?
@@ -13,4 +13,4 @@ typealias Test5 = @A() ( (@B Int)? )
typealias Test6 = (@A @B Int)
typealias Test7 = (@A @B Int)?
typealias Test8 = (@A() (@B Int)? )
typealias Test9 = (@A() (@B Int) )?
typealias Test9 = (@A() (@B Int) )?
@@ -1,4 +0,0 @@
@Target(AnnotationTarget.TYPE)
annotation class A
typealias Test1 = @A @A Int
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
@Target(AnnotationTarget.TYPE)
annotation class A
@@ -1,27 +0,0 @@
// !DIAGNOSTICS: -JAVA_LANG_CLASS_PARAMETER_IN_ANNOTATION
package a.b.c
@kotlin.Deprecated("aaa")
@ann1(kotlin.Deprecated("aaa"))
@a.b.c.ann1()
@ann2(a.b.c.ann1())
@A.IAnn()
@ann3(A.IAnn())
@a.b.c.A.IAnn()
@ann3(a.b.c.A.IAnn())
@annArray(kotlin.arrayOf("a"))
fun test() = 1
annotation class ann1(val p: Deprecated = kotlin.Deprecated("aaa"))
annotation class ann2(val p: ann1 = a.b.c.ann1())
annotation class ann3(val p: A.IAnn = A.IAnn(), val p2: A.IAnn = a.b.c.A.IAnn())
annotation class annArray(val p: Array<String> = kotlin.arrayOf("a"))
class A {
annotation class IAnn
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -JAVA_LANG_CLASS_PARAMETER_IN_ANNOTATION
package a.b.c
@@ -1,5 +1,4 @@
// FIR_IDENTICAL
// FIR_IDE_IGNORE
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn api.ExperimentalAPI
// MODULE: api
// FILE: api.kt
@@ -859,6 +859,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.REPEATED_ANNOTATION) { firDiagnostic ->
RepeatedAnnotationImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.REPEATED_ANNOTATION_WARNING) { firDiagnostic ->
RepeatedAnnotationWarningImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.EXPERIMENTAL_API_USAGE) { firDiagnostic ->
ExperimentalApiUsageImpl(
firDiagnostic.a,
@@ -618,6 +618,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = InapplicableFileTarget::class
}
abstract class RepeatedAnnotation : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatedAnnotation::class
}
abstract class RepeatedAnnotationWarning : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = RepeatedAnnotationWarning::class
}
abstract class ExperimentalApiUsage : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ExperimentalApiUsage::class
abstract val optInMarkerFqName: FqName
@@ -991,6 +991,20 @@ internal class InapplicableFileTargetImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatedAnnotationImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatedAnnotation(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class RepeatedAnnotationWarningImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RepeatedAnnotationWarning(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ExperimentalApiUsageImpl(
override val optInMarkerFqName: FqName,
override val message: String,