FIR: support WRONG_ANNOTATION_TARGET on expressions
This commit is contained in:
+3
-3
@@ -1,17 +1,17 @@
|
|||||||
FILE: annotationUsedAsAnnotationArgument.kt
|
FILE: annotationUsedAsAnnotationArgument.kt
|
||||||
public final annotation class Ann : R|kotlin/Annotation| {
|
@R|kotlin/annotation/Target|(vararg(Q|kotlin/annotation/AnnotationTarget|.R|kotlin/annotation/AnnotationTarget.EXPRESSION|)) @R|kotlin/annotation/Retention|(Q|kotlin/annotation/AnnotationRetention|.R|kotlin/annotation/AnnotationRetention.SOURCE|) public final annotation class Ann : R|kotlin/Annotation| {
|
||||||
public constructor(): R|Ann| {
|
public constructor(): R|Ann| {
|
||||||
super<R|kotlin/Any|>()
|
super<R|kotlin/Any|>()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public final annotation class Ann2 : R|kotlin/Annotation| {
|
@R|kotlin/annotation/Target|(vararg(Q|kotlin/annotation/AnnotationTarget|.R|kotlin/annotation/AnnotationTarget.EXPRESSION|)) @R|kotlin/annotation/Retention|(Q|kotlin/annotation/AnnotationRetention|.R|kotlin/annotation/AnnotationRetention.SOURCE|) public final annotation class Ann2 : R|kotlin/Annotation| {
|
||||||
public constructor(): R|Ann2| {
|
public constructor(): R|Ann2| {
|
||||||
super<R|kotlin/Any|>()
|
super<R|kotlin/Any|>()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public final annotation class Ann3 : R|kotlin/Annotation| {
|
@R|kotlin/annotation/Target|(vararg(Q|kotlin/annotation/AnnotationTarget|.R|kotlin/annotation/AnnotationTarget.EXPRESSION|)) @R|kotlin/annotation/Retention|(Q|kotlin/annotation/AnnotationRetention|.R|kotlin/annotation/AnnotationRetention.SOURCE|) public final annotation class Ann3 : R|kotlin/Annotation| {
|
||||||
public constructor(arg: R|kotlin/Int|, s: R|kotlin/String|): R|Ann3| {
|
public constructor(arg: R|kotlin/Int|, s: R|kotlin/String|): R|Ann3| {
|
||||||
super<R|kotlin/Any|>()
|
super<R|kotlin/Any|>()
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -1,7 +1,15 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.EXPRESSION)
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
annotation class Ann
|
annotation class Ann
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.EXPRESSION)
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
annotation class Ann2
|
annotation class Ann2
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.EXPRESSION)
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
annotation class Ann3(val arg: Int, val s: String)
|
annotation class Ann3(val arg: Int, val s: String)
|
||||||
|
|
||||||
@Ann3(
|
@Ann3(
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
FILE: annotations.kt
|
FILE: annotations.kt
|
||||||
public final annotation class MyAnn : R|kotlin/Annotation| {
|
@R|kotlin/annotation/Retention|(Q|kotlin/annotation/AnnotationRetention|.R|kotlin/annotation/AnnotationRetention.SOURCE|) @R|kotlin/annotation/Target|(vararg(Q|kotlin/annotation/AnnotationTarget|.R|kotlin/annotation/AnnotationTarget.EXPRESSION|)) public final annotation class MyAnn : R|kotlin/Annotation| {
|
||||||
public constructor(): R|MyAnn| {
|
public constructor(): R|MyAnn| {
|
||||||
super<R|kotlin/Any|>()
|
super<R|kotlin/Any|>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
|
@Target(AnnotationTarget.EXPRESSION)
|
||||||
annotation class MyAnn
|
annotation class MyAnn
|
||||||
|
|
||||||
fun bar(x: Int) {}
|
fun bar(x: Int) {}
|
||||||
|
|||||||
+3
@@ -173,6 +173,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
|||||||
|
|
||||||
val ANNOTATION_ON_SUPERCLASS by error<KtAnnotationEntry>()
|
val ANNOTATION_ON_SUPERCLASS by error<KtAnnotationEntry>()
|
||||||
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by error<PsiElement>()
|
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by error<PsiElement>()
|
||||||
|
val WRONG_ANNOTATION_TARGET by error<KtAnnotationEntry> {
|
||||||
|
parameter<String>("actualTarget")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val EXPOSED_VISIBILITY by object : DiagnosticGroup("Exposed visibility") {
|
val EXPOSED_VISIBILITY by object : DiagnosticGroup("Exposed visibility") {
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ object FirErrors {
|
|||||||
val DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
val DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
val ANNOTATION_ON_SUPERCLASS by error0<KtAnnotationEntry>()
|
val ANNOTATION_ON_SUPERCLASS by error0<KtAnnotationEntry>()
|
||||||
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by error0<PsiElement>()
|
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by error0<PsiElement>()
|
||||||
|
val WRONG_ANNOTATION_TARGET by error1<KtAnnotationEntry, String>()
|
||||||
|
|
||||||
// Exposed visibility
|
// Exposed visibility
|
||||||
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<KtNamedDeclaration, EffectiveVisibility, FirMemberDeclaration, EffectiveVisibility>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<KtNamedDeclaration, EffectiveVisibility, FirMemberDeclaration, EffectiveVisibility>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
|
|||||||
+20
-15
@@ -9,13 +9,11 @@ import org.jetbrains.kotlin.builtins.StandardNames
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirVarargArgumentsExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.argumentMapping
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
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.fir.types.coneType
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -30,12 +28,8 @@ fun FirAnnotationCall.getRetention(session: FirSession): AnnotationRetention {
|
|||||||
|
|
||||||
fun FirRegularClass.getRetention(): AnnotationRetention {
|
fun FirRegularClass.getRetention(): AnnotationRetention {
|
||||||
val retentionAnnotation = getRetentionAnnotation() ?: return AnnotationRetention.RUNTIME
|
val retentionAnnotation = getRetentionAnnotation() ?: return AnnotationRetention.RUNTIME
|
||||||
val argumentMapping = retentionAnnotation.argumentMapping ?: return AnnotationRetention.RUNTIME
|
val retentionArgument = retentionAnnotation.findSingleArgumentByName(RETENTION_PARAMETER_NAME) as? FirQualifiedAccessExpression
|
||||||
val retentionArgument = argumentMapping.keys.firstOrNull() as? FirQualifiedAccessExpression
|
|
||||||
?: return AnnotationRetention.RUNTIME
|
?: return AnnotationRetention.RUNTIME
|
||||||
if (argumentMapping[retentionArgument]?.name != RETENTION_PARAMETER_NAME) {
|
|
||||||
return AnnotationRetention.RUNTIME
|
|
||||||
}
|
|
||||||
val retentionName = (retentionArgument.calleeReference as? FirResolvedNamedReference)?.name?.asString()
|
val retentionName = (retentionArgument.calleeReference as? FirResolvedNamedReference)?.name?.asString()
|
||||||
?: return AnnotationRetention.RUNTIME
|
?: return AnnotationRetention.RUNTIME
|
||||||
return AnnotationRetention.values().firstOrNull { it.name == retentionName } ?: AnnotationRetention.RUNTIME
|
return AnnotationRetention.values().firstOrNull { it.name == retentionName } ?: AnnotationRetention.RUNTIME
|
||||||
@@ -54,19 +48,20 @@ private val defaultAnnotationTargets = listOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun FirAnnotationCall.getAllowedAnnotationTargets(session: FirSession): List<AnnotationTarget> {
|
fun FirAnnotationCall.getAllowedAnnotationTargets(session: FirSession): List<AnnotationTarget> {
|
||||||
|
if (annotationTypeRef is FirErrorTypeRef) return AnnotationTarget.values().toList()
|
||||||
val annotationClass = (this.annotationTypeRef.coneType as? ConeClassLikeType)?.lookupTag?.toSymbol(session)?.fir as? FirRegularClass
|
val annotationClass = (this.annotationTypeRef.coneType as? ConeClassLikeType)?.lookupTag?.toSymbol(session)?.fir as? FirRegularClass
|
||||||
return annotationClass?.getAllowedAnnotationTargets() ?: defaultAnnotationTargets
|
return annotationClass?.getAllowedAnnotationTargets() ?: defaultAnnotationTargets
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirRegularClass.getAllowedAnnotationTargets(): List<AnnotationTarget> {
|
fun FirRegularClass.getAllowedAnnotationTargets(): List<AnnotationTarget> {
|
||||||
val targetAnnotation = getTargetAnnotation() ?: return defaultAnnotationTargets
|
val targetAnnotation = getTargetAnnotation() ?: return defaultAnnotationTargets
|
||||||
val argumentMapping = targetAnnotation.argumentMapping ?: return defaultAnnotationTargets
|
val arguments = when (val targetArgument = targetAnnotation.findSingleArgumentByName(TARGET_PARAMETER_NAME)) {
|
||||||
val targetArgument = argumentMapping.keys.firstOrNull() as? FirVarargArgumentsExpression
|
is FirVarargArgumentsExpression -> targetArgument.arguments
|
||||||
?: return defaultAnnotationTargets
|
is FirArrayOfCall -> targetArgument.arguments
|
||||||
if (argumentMapping[targetArgument]?.name != TARGET_PARAMETER_NAME) {
|
else -> return defaultAnnotationTargets
|
||||||
return defaultAnnotationTargets
|
|
||||||
}
|
}
|
||||||
return targetArgument.arguments.mapNotNull { argument ->
|
|
||||||
|
return arguments.mapNotNull { argument ->
|
||||||
val targetExpression = argument as? FirQualifiedAccessExpression
|
val targetExpression = argument as? FirQualifiedAccessExpression
|
||||||
val targetName = (targetExpression?.calleeReference as? FirResolvedNamedReference)?.name?.asString() ?: return@mapNotNull null
|
val targetName = (targetExpression?.calleeReference as? FirResolvedNamedReference)?.name?.asString() ?: return@mapNotNull null
|
||||||
AnnotationTarget.values().firstOrNull { target -> target.name == targetName }
|
AnnotationTarget.values().firstOrNull { target -> target.name == targetName }
|
||||||
@@ -87,3 +82,13 @@ fun FirAnnotatedDeclaration.getAnnotationByFqName(fqName: FqName): FirAnnotation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirAnnotationCall.findSingleArgumentByName(name: Name): FirExpression? {
|
||||||
|
val argumentMapping = argumentMapping
|
||||||
|
if (argumentMapping != null) {
|
||||||
|
return argumentMapping.keys.firstOrNull()?.takeIf { argumentMapping[it]?.name == name }
|
||||||
|
}
|
||||||
|
// NB: we have to consider both cases, because deserializer does not create argument mapping
|
||||||
|
val firstArgument = argumentList.arguments.firstOrNull() as? FirNamedArgumentExpression ?: return null
|
||||||
|
return firstArgument.takeIf { it.name == name }?.expression
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-1
@@ -5,19 +5,31 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
|
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getRetention
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
||||||
|
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.expressions.FirStatement
|
||||||
|
|
||||||
object FirExpressionAnnotationChecker : FirBasicExpressionChecker() {
|
object FirExpressionAnnotationChecker : FirBasicExpressionChecker() {
|
||||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
// Declarations are checked separately
|
||||||
|
// See KT-33658 about annotations on non-expression statements
|
||||||
|
if (expression is FirDeclaration ||
|
||||||
|
expression !is FirExpression ||
|
||||||
|
expression is FirBlock && expression.source?.kind == FirFakeSourceElementKind.DesugaredForLoop
|
||||||
|
) return
|
||||||
for (annotation in expression.annotations) {
|
for (annotation in expression.annotations) {
|
||||||
withSuppressedDiagnostics(annotation, context) {
|
withSuppressedDiagnostics(annotation, context) {
|
||||||
|
if (AnnotationTarget.EXPRESSION !in annotation.getAllowedAnnotationTargets(context.session)) {
|
||||||
|
reporter.reportOn(annotation.source, FirErrors.WRONG_ANNOTATION_TARGET, "expression", context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -328,6 +328,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VARIANCE_ON_TYPE_
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_ANNOTATION_PARAMETER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_ANNOTATION_PARAMETER
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_OVERRIDDEN_BY_VAL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_OVERRIDDEN_BY_VAL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH_ON_OVERRIDE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_GETTER_RETURN_TYPE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_GETTER_RETURN_TYPE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_INVOCATION_KIND
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_INVOCATION_KIND
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_MODIFIER_TARGET
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_MODIFIER_TARGET
|
||||||
@@ -476,6 +477,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
"DeprecatedSinceKotlin annotation cannot be used outside 'kotlin' subpackages"
|
"DeprecatedSinceKotlin annotation cannot be used outside 'kotlin' subpackages"
|
||||||
)
|
)
|
||||||
map.put(ANNOTATION_ON_SUPERCLASS, "Annotations on superclass are meaningless")
|
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);
|
||||||
|
|
||||||
// Exposed visibility group // #
|
// Exposed visibility group // #
|
||||||
map.put(
|
map.put(
|
||||||
|
|||||||
+1
-1
@@ -18,6 +18,6 @@ fun test() : Unit {
|
|||||||
val s = "" as Any
|
val s = "" as Any
|
||||||
("" as String?)?.length
|
("" as String?)?.length
|
||||||
(data@("" as String?))?.length
|
(data@("" as String?))?.length
|
||||||
(@MustBeDocumented()( "" as String?))?.length
|
(<!WRONG_ANNOTATION_TARGET!>@MustBeDocumented()<!>( "" as String?))?.length
|
||||||
Unit
|
Unit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ fun foo(arg: Int) {
|
|||||||
// Function expression too
|
// Function expression too
|
||||||
val f = @FunAnn fun(): Int { return 42 }
|
val f = @FunAnn fun(): Int { return 42 }
|
||||||
// But here, f and gav should be annotated instead
|
// But here, f and gav should be annotated instead
|
||||||
bar(@FunAnn f)
|
bar(<!WRONG_ANNOTATION_TARGET!>@FunAnn<!> f)
|
||||||
bar(@FunAnn ::gav)
|
bar(<!WRONG_ANNOTATION_TARGET!>@FunAnn<!> ::gav)
|
||||||
// Function expression, ok
|
// Function expression, ok
|
||||||
fast(f)
|
fast(f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
@Target(AnnotationTarget.FUNCTION)
|
|
||||||
annotation class FunAnn
|
|
||||||
|
|
||||||
@Target(AnnotationTarget.EXPRESSION)
|
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
|
||||||
annotation class ExprAnn
|
|
||||||
|
|
||||||
fun foo(): Int {
|
|
||||||
var x = 5
|
|
||||||
@FunAnn ++x
|
|
||||||
@ExprAnn ++x
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
@Target(AnnotationTarget.FUNCTION)
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
annotation class FunAnn
|
annotation class FunAnn
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -18,4 +18,4 @@
|
|||||||
return local
|
return local
|
||||||
}
|
}
|
||||||
|
|
||||||
@empty val z = @empty 0
|
@empty val z = <!WRONG_ANNOTATION_TARGET!>@empty<!> 0
|
||||||
|
|||||||
+3
-3
@@ -4,10 +4,10 @@ annotation class base
|
|||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
annotation class special
|
annotation class special
|
||||||
|
|
||||||
fun transform(i: Int, tr: (Int) -> Int): Int = @base @special tr(@special i)
|
fun transform(i: Int, tr: (Int) -> Int): Int = <!WRONG_ANNOTATION_TARGET!>@base<!> @special tr(@special i)
|
||||||
|
|
||||||
@base @special fun foo(i: Int): Int {
|
@base @special fun foo(i: Int): Int {
|
||||||
val j = @base @special i + 1
|
val j = <!WRONG_ANNOTATION_TARGET!>@base<!> @special i + 1
|
||||||
if (j == 1) return foo(@special @base 42)
|
if (j == 1) return foo(@special <!WRONG_ANNOTATION_TARGET!>@base<!> 42)
|
||||||
return transform(@special j, @base @special { @special it * 2 })
|
return transform(@special j, @base @special { @special it * 2 })
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -10,5 +10,5 @@ fun transform(i: Int, tr: (@special Int) -> Int): Int = @special tr(@special i)
|
|||||||
fun foo(i: Int): Int {
|
fun foo(i: Int): Int {
|
||||||
val j = @special i + 1
|
val j = @special i + 1
|
||||||
if (j == 1) return foo(@special 42)
|
if (j == 1) return foo(@special 42)
|
||||||
return transform(@special j, @special { i: @base Int -> @base i * 2 })
|
return transform(@special j, @special { i: @base Int -> <!WRONG_ANNOTATION_TARGET!>@base<!> i * 2 })
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -18,4 +18,4 @@
|
|||||||
return local
|
return local
|
||||||
}
|
}
|
||||||
|
|
||||||
@incorrect val z = @incorrect 0
|
@incorrect val z = <!WRONG_ANNOTATION_TARGET!>@incorrect<!> 0
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ import test.AnnotationTargets.*
|
|||||||
): @fieldann @parameter Int {
|
): @fieldann @parameter Int {
|
||||||
|
|
||||||
@local @base @multiple @fieldann val j = i + 1
|
@local @base @multiple @fieldann val j = i + 1
|
||||||
@base @multiple return j
|
<!WRONG_ANNOTATION_TARGET!>@base<!> <!WRONG_ANNOTATION_TARGET!>@multiple<!> return j
|
||||||
}
|
}
|
||||||
|
|
||||||
@base @method @konstructor constructor(): this(0)
|
@base @method @konstructor constructor(): this(0)
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE)
|
||||||
|
*
|
||||||
|
* SPEC VERSION: 0.1-313
|
||||||
|
* PRIMARY LINKS: expressions, when-expression -> paragraph 9 -> sentence 2
|
||||||
|
* expressions, when-expression -> paragraph 5 -> sentence 1
|
||||||
|
* expressions, when-expression -> paragraph 6 -> sentence 5
|
||||||
|
* annotations, annotation-targets -> paragraph 1 -> sentence 1
|
||||||
|
*/
|
||||||
|
fun foo(a: Int) {
|
||||||
|
<!WRONG_ANNOTATION_TARGET!>@ann<!>
|
||||||
|
when (a) {
|
||||||
|
1 -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
annotation class ann
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// FIR_IDENTICAL
|
|
||||||
/*
|
/*
|
||||||
* KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE)
|
* KOTLIN DIAGNOSTICS SPEC TEST (POSITIVE)
|
||||||
*
|
*
|
||||||
|
|||||||
+7
@@ -613,6 +613,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.WRONG_ANNOTATION_TARGET) { firDiagnostic ->
|
||||||
|
WrongAnnotationTargetImpl(
|
||||||
|
firDiagnostic.a,
|
||||||
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE) { firDiagnostic ->
|
add(FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE) { firDiagnostic ->
|
||||||
ExposedTypealiasExpandedTypeImpl(
|
ExposedTypealiasExpandedTypeImpl(
|
||||||
firDiagnostic.a,
|
firDiagnostic.a,
|
||||||
|
|||||||
+5
@@ -438,6 +438,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = RestrictedRetentionForExpressionAnnotation::class
|
override val diagnosticClass get() = RestrictedRetentionForExpressionAnnotation::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class WrongAnnotationTarget : KtFirDiagnostic<KtAnnotationEntry>() {
|
||||||
|
override val diagnosticClass get() = WrongAnnotationTarget::class
|
||||||
|
abstract val actualTarget: String
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ExposedTypealiasExpandedType : KtFirDiagnostic<KtNamedDeclaration>() {
|
abstract class ExposedTypealiasExpandedType : KtFirDiagnostic<KtNamedDeclaration>() {
|
||||||
override val diagnosticClass get() = ExposedTypealiasExpandedType::class
|
override val diagnosticClass get() = ExposedTypealiasExpandedType::class
|
||||||
abstract val elementVisibility: EffectiveVisibility
|
abstract val elementVisibility: EffectiveVisibility
|
||||||
|
|||||||
+8
@@ -712,6 +712,14 @@ internal class RestrictedRetentionForExpressionAnnotationImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class WrongAnnotationTargetImpl(
|
||||||
|
override val actualTarget: String,
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.WrongAnnotationTarget(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class ExposedTypealiasExpandedTypeImpl(
|
internal class ExposedTypealiasExpandedTypeImpl(
|
||||||
override val elementVisibility: EffectiveVisibility,
|
override val elementVisibility: EffectiveVisibility,
|
||||||
override val restrictingDeclaration: KtSymbol,
|
override val restrictingDeclaration: KtSymbol,
|
||||||
|
|||||||
Reference in New Issue
Block a user