diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 4f3e5a06bcf..e16ebb9daf9 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -914,6 +914,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NOT_A_CLASS) { firDiagnostic -> + NotAClassImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.OPT_IN_USAGE) { firDiagnostic -> OptInUsageImpl( firDiagnostic.a, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 25c7f6e93f6..d8e9f15a2da 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -659,6 +659,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = RepeatedAnnotationWarning::class } + abstract class NotAClass : KtFirDiagnostic() { + override val diagnosticClass get() = NotAClass::class + } + abstract class OptInUsage : KtFirDiagnostic() { override val diagnosticClass get() = OptInUsage::class abstract val optInMarkerFqName: FqName diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 506eaf04d82..e2299dd3cc0 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -790,6 +790,11 @@ internal class RepeatedAnnotationWarningImpl( override val token: ValidityToken, ) : KtFirDiagnostic.RepeatedAnnotationWarning(), KtAbstractFirDiagnostic +internal class NotAClassImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.NotAClass(), KtAbstractFirDiagnostic + internal class OptInUsageImpl( override val optInMarkerFqName: FqName, override val message: String, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 3094fea933f..c9d2a37db83 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -281,6 +281,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val INAPPLICABLE_FILE_TARGET by error(PositioningStrategy.ANNOTATION_USE_SITE) val REPEATED_ANNOTATION by error() val REPEATED_ANNOTATION_WARNING by warning() + val NOT_A_CLASS by error() } val OPT_IN by object : DiagnosticGroup("OptIn") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 2c427713a23..2b887a671ef 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -247,6 +247,7 @@ object FirErrors { val INAPPLICABLE_FILE_TARGET by error0(SourceElementPositioningStrategies.ANNOTATION_USE_SITE) val REPEATED_ANNOTATION by error0() val REPEATED_ANNOTATION_WARNING by warning0() + val NOT_A_CLASS by error0() // OptIn val OPT_IN_USAGE by warning2(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt index dc0c5265dbc..76fafec0b2a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonExpressionCheckers.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirUnderscoredTypeArgum object CommonExpressionCheckers : ExpressionCheckers() { override val annotationCallCheckers: Set get() = setOf( - FirAnnotationArgumentChecker, + FirAnnotationExpressionChecker, FirOptInAnnotationCallChecker, ) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAnnotationArgumentChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAnnotationExpressionChecker.kt similarity index 88% rename from compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAnnotationArgumentChecker.kt rename to compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAnnotationExpressionChecker.kt index af6140ea448..0efb195fcd0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAnnotationArgumentChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirAnnotationExpressionChecker.kt @@ -7,23 +7,27 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.config.ApiVersion +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0 +import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.checkers.ConstantArgumentKind import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext -import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors -import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory0 -import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.findArgumentByName import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.resolve.fqName +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.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.RequireKotlinConstants -object FirAnnotationArgumentChecker : FirAnnotationCallChecker() { +object FirAnnotationExpressionChecker : FirAnnotationCallChecker() { private val versionArgumentName = Name.identifier("version") private val deprecatedSinceKotlinFqName = FqName("kotlin.DeprecatedSinceKotlin") private val sinceKotlinFqName = FqName("kotlin.SinceKotlin") @@ -44,13 +48,8 @@ object FirAnnotationArgumentChecker : FirAnnotationCallChecker() { checkAnnotationsWithVersion(fqName, expression, context, reporter) checkDeprecatedSinceKotlin(expression.source, fqName, argumentMapping, context, reporter) - - val args = expression.argumentList.arguments - for (arg in args) { - for (ann in arg.unwrapArgument().annotations) { - reporter.reportOn(ann.source, FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT, context) - } - } + checkAnnotationUsedAsAnnotationArgument(expression, context, reporter) + checkNotAClass(expression, context, reporter) } private fun checkAnnotationArgumentWithSubElements( @@ -194,4 +193,31 @@ object FirAnnotationArgumentChecker : FirAnnotationCallChecker() { reporter.reportOn(source, FirErrors.DEPRECATED_SINCE_KOTLIN_WITH_UNORDERED_VERSIONS, context) } } + + private fun checkAnnotationUsedAsAnnotationArgument( + expression: FirAnnotationCall, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + val args = expression.argumentList.arguments + for (arg in args) { + for (ann in arg.unwrapArgument().annotations) { + reporter.reportOn(ann.source, FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT, context) + } + } + } + + private fun checkNotAClass( + expression: FirAnnotationCall, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + val annotationTypeRef = expression.annotationTypeRef + if (expression.calleeReference is FirErrorNamedReference && + annotationTypeRef !is FirErrorTypeRef && + annotationTypeRef.coneType !is ConeClassLikeType + ) { + reporter.reportOn(annotationTypeRef.source, FirErrors.NOT_A_CLASS, context) + } + } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 000abe92c1d..c9af9e0891b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -306,6 +306,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_VARARG_SPREAD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_INLINE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_OVERRIDE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_AN_ANNOTATION_CLASS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_FUNCTION_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE @@ -779,6 +780,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { OPT_IN_MARKER_ON_OVERRIDE_WARNING, "Opt-in requirement marker annotation on override makes no sense without the same marker on base declaration" ) + map.put(NOT_A_CLASS, "Not a class") // Exposed visibility group // # map.put( diff --git a/compiler/testData/diagnostics/tests/annotations/typeParameterAsAnnotation.fir.kt b/compiler/testData/diagnostics/tests/annotations/typeParameterAsAnnotation.fir.kt deleted file mode 100644 index 1290a11601f..00000000000 --- a/compiler/testData/diagnostics/tests/annotations/typeParameterAsAnnotation.fir.kt +++ /dev/null @@ -1,9 +0,0 @@ -class Foo { - @T - fun foo() = 0 -} - -class Bar { - @T - fun foo() = 0 -} diff --git a/compiler/testData/diagnostics/tests/annotations/typeParameterAsAnnotation.kt b/compiler/testData/diagnostics/tests/annotations/typeParameterAsAnnotation.kt index bbe861566ce..538ec69533d 100644 --- a/compiler/testData/diagnostics/tests/annotations/typeParameterAsAnnotation.kt +++ b/compiler/testData/diagnostics/tests/annotations/typeParameterAsAnnotation.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class Foo { @T fun foo() = 0