Introduce use-site annotation target checks for FIR
This commit is contained in:
+13
@@ -180,6 +180,19 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<String>("actualTarget")
|
||||
parameter<String>("useSiteTarget")
|
||||
}
|
||||
val INAPPLICABLE_TARGET_ON_PROPERTY by error<PsiElement> {
|
||||
parameter<String>("useSiteDescription")
|
||||
}
|
||||
val INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE by error<PsiElement> {
|
||||
parameter<String>("useSiteDescription")
|
||||
}
|
||||
val INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE by error<PsiElement>()
|
||||
val INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD by error<PsiElement>()
|
||||
val INAPPLICABLE_PARAM_TARGET by error<PsiElement>()
|
||||
val REDUNDANT_ANNOTATION_TARGET by warning<PsiElement> {
|
||||
parameter<String>("useSiteDescription")
|
||||
}
|
||||
val INAPPLICABLE_FILE_TARGET by error<PsiElement>()
|
||||
}
|
||||
|
||||
val EXPOSED_VISIBILITY by object : DiagnosticGroup("Exposed visibility") {
|
||||
|
||||
@@ -181,6 +181,13 @@ object FirErrors {
|
||||
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by error0<PsiElement>()
|
||||
val WRONG_ANNOTATION_TARGET by error1<KtAnnotationEntry, String>()
|
||||
val WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET by error2<KtAnnotationEntry, String, String>()
|
||||
val INAPPLICABLE_TARGET_ON_PROPERTY by error1<PsiElement, String>()
|
||||
val INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE by error1<PsiElement, String>()
|
||||
val INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE by error0<PsiElement>()
|
||||
val INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD by error0<PsiElement>()
|
||||
val INAPPLICABLE_PARAM_TARGET by error0<PsiElement>()
|
||||
val REDUNDANT_ANNOTATION_TARGET by warning1<PsiElement, String>()
|
||||
val INAPPLICABLE_FILE_TARGET by error0<PsiElement>()
|
||||
|
||||
// Exposed visibility
|
||||
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<KtNamedDeclaration, EffectiveVisibility, FirMemberDeclaration, EffectiveVisibility>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
|
||||
+63
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
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.context.CheckerContext
|
||||
@@ -77,6 +78,10 @@ object FirAnnotationChecker : FirAnnotatedDeclarationChecker() {
|
||||
return actualTargets.onlyWithUseSiteTarget.any { it in applicableTargets && it == useSiteMapping }
|
||||
}
|
||||
|
||||
if (useSiteTarget != null) {
|
||||
checkAnnotationUseSiteTarget(declaration, annotation, useSiteTarget, context, reporter)
|
||||
}
|
||||
|
||||
if (check(actualTargets.defaultTargets) || check(actualTargets.canBeSubstituted) || checkWithUseSiteTargets()) {
|
||||
return
|
||||
}
|
||||
@@ -100,6 +105,64 @@ object FirAnnotationChecker : FirAnnotatedDeclarationChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAnnotationUseSiteTarget(
|
||||
annotated: FirAnnotatedDeclaration,
|
||||
annotation: FirAnnotationCall,
|
||||
target: AnnotationUseSiteTarget,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
when (target) {
|
||||
AnnotationUseSiteTarget.PROPERTY,
|
||||
AnnotationUseSiteTarget.PROPERTY_GETTER -> {
|
||||
}
|
||||
AnnotationUseSiteTarget.FIELD -> {
|
||||
if (annotated is FirProperty && annotated.delegateFieldSymbol != null && !annotated.hasBackingField) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD, context)
|
||||
}
|
||||
}
|
||||
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> {
|
||||
if (annotated is FirProperty && annotated.delegateFieldSymbol == null) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, context)
|
||||
}
|
||||
}
|
||||
AnnotationUseSiteTarget.PROPERTY_SETTER,
|
||||
AnnotationUseSiteTarget.SETTER_PARAMETER -> {
|
||||
if (annotated !is FirProperty || annotated.isLocal) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_ON_PROPERTY, target.renderName, context)
|
||||
} else if (!annotated.isVar) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, target.renderName, context)
|
||||
}
|
||||
}
|
||||
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> when {
|
||||
annotated is FirValueParameter -> {
|
||||
val container = context.containingDeclarations.lastOrNull()
|
||||
if (container is FirConstructor && container.isPrimary) {
|
||||
reporter.reportOn(annotation.source, FirErrors.REDUNDANT_ANNOTATION_TARGET, target.renderName, context)
|
||||
} else {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_PARAM_TARGET, context)
|
||||
}
|
||||
}
|
||||
annotated is FirProperty && annotated.source?.kind == FirFakeSourceElementKind.PropertyFromParameter -> {
|
||||
}
|
||||
else -> reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_PARAM_TARGET, context)
|
||||
}
|
||||
AnnotationUseSiteTarget.FILE -> {
|
||||
// NB: report once?
|
||||
if (annotated !is FirFile) {
|
||||
reporter.reportOn(annotation.source, FirErrors.INAPPLICABLE_FILE_TARGET, context)
|
||||
}
|
||||
}
|
||||
AnnotationUseSiteTarget.RECEIVER -> {
|
||||
// NB: report once?
|
||||
// annotation with use-site target `receiver` can be only on type reference, but not on declaration
|
||||
reporter.reportOn(
|
||||
annotation.source, FirErrors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET, "declaration", target.renderName, context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDeprecatedCalls(
|
||||
deprecatedSinceKotlinCall: FirAnnotationCall,
|
||||
deprecatedCall: FirAnnotationCall?,
|
||||
|
||||
+20
-3
@@ -141,8 +141,14 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXP
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_FILE_TARGET
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFIX_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_LATEINIT_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_PARAM_TARGET
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_ON_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_ENUM_COMPARISON_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_MODIFIERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_TYPES
|
||||
@@ -238,6 +244,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_IMPL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_SUPERTYPES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_ANNOTATION_TARGET
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_CALL_OF_CONVERSION_METHOD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_EXPLICIT_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
|
||||
@@ -449,7 +456,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(NULLABLE_TYPE_OF_ANNOTATION_MEMBER, "An annotation parameter cannot be nullable")
|
||||
map.put(INVALID_TYPE_OF_ANNOTATION_MEMBER, "Invalid type of annotation member")
|
||||
map.put(VAR_ANNOTATION_PARAMETER, "An annotation parameter cannot be 'var'")
|
||||
map.put(ANNOTATION_CLASS_CONSTRUCTOR_CALL, "Annotation class cannot be instantiated");
|
||||
map.put(ANNOTATION_CLASS_CONSTRUCTOR_CALL, "Annotation class cannot be instantiated")
|
||||
map.put(NOT_AN_ANNOTATION_CLASS, "Illegal annotation class: {0}", NULLABLE_STRING)
|
||||
map.put(SUPERTYPES_FOR_ANNOTATION_CLASS, "Annotation class cannot have supertypes")
|
||||
map.put(
|
||||
@@ -478,13 +485,23 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
"DeprecatedSinceKotlin annotation cannot be used outside 'kotlin' subpackages"
|
||||
)
|
||||
map.put(ANNOTATION_ON_SUPERCLASS, "Annotations on superclass are meaningless")
|
||||
map.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
|
||||
map.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING)
|
||||
map.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}:'' annotations could be applied only to property declarations", TO_STRING)
|
||||
map.put(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, "''@{0}:'' annotations could be applied only to mutable properties", TO_STRING)
|
||||
map.put(INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, "'@delegate:' annotations could be applied only to delegated properties")
|
||||
map.put(
|
||||
INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD,
|
||||
"'@field:' annotations could be applied only to properties with backing fields"
|
||||
)
|
||||
map.put(INAPPLICABLE_PARAM_TARGET, "'@param:' annotations could be applied only to primary constructor parameters")
|
||||
map.put(REDUNDANT_ANNOTATION_TARGET, "Redundant annotation target ''{0}''", TO_STRING)
|
||||
map.put(INAPPLICABLE_FILE_TARGET, "'@file:' annotations can only be applied before package declaration")
|
||||
map.put(
|
||||
WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET,
|
||||
"This annotation is not applicable to target ''{0}'' and use site target ''@{1}''",
|
||||
TO_STRING,
|
||||
TO_STRING
|
||||
);
|
||||
)
|
||||
|
||||
// Exposed visibility group // #
|
||||
map.put(
|
||||
|
||||
Reference in New Issue
Block a user