FIR: report WRONG_ANNOTATION_TARGET on types

This commit is contained in:
Mikhail Glukhikh
2021-05-18 11:11:28 +03:00
parent 2a33a6927c
commit 9a13ec9b76
45 changed files with 89 additions and 300 deletions
@@ -5,7 +5,7 @@ interface I {
}
class A {
fun too(): @<!NOT_AN_ANNOTATION_CLASS!>Annotation<!> Unit {}
fun too(): <!WRONG_ANNOTATION_TARGET!>@<!NOT_AN_ANNOTATION_CLASS!>Annotation<!><!> Unit {}
fun foo(): <!REDUNDANT_RETURN_UNIT_TYPE!>Unit<!>
{
@@ -30,7 +30,7 @@ abstract class First {
}
@WithString("xyz")
class Second(val y: Char) : @WithInt(0) First() {
class Second(val y: Char) : <!WRONG_ANNOTATION_TARGET!>@WithInt(0)<!> First() {
override fun foo(arg: Double) {
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
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.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
@@ -40,12 +41,14 @@ private val defaultAnnotationTargets = KotlinTarget.DEFAULT_TARGET_SET
fun FirAnnotationCall.getAllowedAnnotationTargets(session: FirSession): Set<KotlinTarget> {
if (annotationTypeRef is FirErrorTypeRef) return KotlinTarget.values().toSet()
val annotationClass = (this.annotationTypeRef.coneType as? ConeClassLikeType)?.lookupTag?.toSymbol(session)?.fir as? FirRegularClass
val annotationClass = (this.annotationTypeRef.coneType as? ConeClassLikeType)
?.fullyExpandedType(session)?.lookupTag?.toSymbol(session)?.fir as? FirRegularClass
return annotationClass?.getAllowedAnnotationTargets() ?: defaultAnnotationTargets
}
fun FirRegularClass.getAllowedAnnotationTargets(): Set<KotlinTarget> {
val targetAnnotation = getTargetAnnotation() ?: return defaultAnnotationTargets
if (targetAnnotation.argumentList.arguments.isEmpty()) return emptySet()
val arguments = when (val targetArgument = targetAnnotation.findSingleArgumentByName(TARGET_PARAMETER_NAME)) {
is FirVarargArgumentsExpression -> targetArgument.arguments
is FirArrayOfCall -> targetArgument.arguments
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.type
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
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.analysis.diagnostics.withSuppressedDiagnostics
import org.jetbrains.kotlin.fir.types.FirTypeRef
object FirTypeAnnotationChecker : FirTypeRefChecker() {
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
for (annotation in typeRef.annotations) {
withSuppressedDiagnostics(annotation, context) {
val annotationTargets = annotation.getAllowedAnnotationTargets(context.session)
if (KotlinTarget.TYPE !in annotationTargets) {
val useSiteTarget = annotation.useSiteTarget
if (useSiteTarget == null || KotlinTarget.USE_SITE_MAPPING[useSiteTarget] !in annotationTargets) {
reporter.reportOn(annotation.source, FirErrors.WRONG_ANNOTATION_TARGET, "type usage", context)
}
}
}
}
}
}
@@ -171,6 +171,7 @@ abstract class AbstractDiagnosticCollectorVisitor(
if (resolvedTypeRef.type is ConeClassErrorType) {
super.visitResolvedTypeRef(resolvedTypeRef, data)
}
if (resolvedTypeRef.source?.kind is FirFakeSourceElementKind) return
resolvedTypeRef.delegatedTypeRef?.accept(this, data)
}
@@ -5,18 +5,14 @@
package org.jetbrains.kotlin.fir.checkers
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.cfa.FirCallsEffectAnalyzer
import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer
import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirSuspendModifierChecker
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirTypeAnnotationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirTypeRefChecker
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
object CommonTypeCheckers : TypeCheckers() {
override val typeRefCheckers: Set<FirTypeRefChecker> = setOf(
FirSuspendModifierChecker
FirTypeAnnotationChecker,
FirSuspendModifierChecker,
)
}
@@ -323,7 +323,8 @@ private fun FirTypeRef.hideLocalTypeIfNeeded(
}
val superType = firClass.superTypeRefs.single()
if (superType is FirResolvedTypeRef) {
return superType
val newKind = source?.kind
return if (newKind is FirFakeSourceElementKind) superType.copyWithNewSourceKind(newKind) else superType
}
}
return this