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 de38d9771ae..8f01f3816e0 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 @@ -1165,6 +1165,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION) { firDiagnostic -> + NonSourceAnnotationOnInlinedLambdaExpressionImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirJsErrors.WRONG_JS_QUALIFIER) { firDiagnostic -> WrongJsQualifierImpl( firDiagnostic as KtPsiDiagnostic, 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 d89bc3fb1f7..d181ebe6ff6 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 @@ -844,6 +844,10 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = VolatileOnDelegate::class } + interface NonSourceAnnotationOnInlinedLambdaExpression : KtFirDiagnostic { + override val diagnosticClass get() = NonSourceAnnotationOnInlinedLambdaExpression::class + } + interface WrongJsQualifier : KtFirDiagnostic { override val diagnosticClass get() = WrongJsQualifier::class } 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 c6b68fd7f2a..d64e1e16ca9 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 @@ -1011,6 +1011,11 @@ internal class VolatileOnDelegateImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.VolatileOnDelegate +internal class NonSourceAnnotationOnInlinedLambdaExpressionImpl( + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.NonSourceAnnotationOnInlinedLambdaExpression + internal class WrongJsQualifierImpl( firDiagnostic: KtPsiDiagnostic, token: KtLifetimeToken, 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 b8192555a51..a6678df5213 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 @@ -384,6 +384,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val VOLATILE_ON_VALUE by error() val VOLATILE_ON_DELEGATE by error() + + val NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION 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 4893f9c5678..9f7dd31e099 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 @@ -293,6 +293,7 @@ object FirErrors { val AMBIGUOUS_ANNOTATION_ARGUMENT by error1>>() val VOLATILE_ON_VALUE by error0() val VOLATILE_ON_DELEGATE by error0() + val NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION by error0() // OptIn val OPT_IN_USAGE by warning2(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt index 8c499c24c9b..3206b9c945e 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt @@ -155,6 +155,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set = setOf( "AMBIGUOUS_ANNOTATION_ARGUMENT", "VOLATILE_ON_VALUE", "VOLATILE_ON_DELEGATE", + "NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION", "WRONG_JS_QUALIFIER", "JS_MODULE_PROHIBITED_ON_VAR", "JS_MODULE_PROHIBITED_ON_NON_NATIVE", diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 17f0586d182..96cf1f31a53 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.* import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnonymousFunctionParametersChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFiniteBoundRestrictionChecker +import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirInlinedLambdaNonSourceAnnotationsChecker import org.jetbrains.kotlin.fir.analysis.checkers.syntax.* object CommonDeclarationCheckers : DeclarationCheckers() { @@ -173,6 +174,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { override val anonymousFunctionCheckers: Set get() = setOf( FirAnonymousFunctionParametersChecker, + FirInlinedLambdaNonSourceAnnotationsChecker, FirAnonymousFunctionSyntaxChecker, ) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirInlinedLambdaNonSourceAnnotationsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirInlinedLambdaNonSourceAnnotationsChecker.kt new file mode 100644 index 00000000000..4fbb92b197c --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirInlinedLambdaNonSourceAnnotationsChecker.kt @@ -0,0 +1,32 @@ +/* + * 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.expression + +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirAnonymousFunctionChecker +import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationRetention +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction +import org.jetbrains.kotlin.fir.declarations.InlineStatus +import org.jetbrains.kotlin.fir.declarations.toAnnotationClassLikeSymbol + +object FirInlinedLambdaNonSourceAnnotationsChecker : FirAnonymousFunctionChecker() { + override fun check(declaration: FirAnonymousFunction, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration.inlineStatus != InlineStatus.Inline && declaration.inlineStatus != InlineStatus.CrossInline) { + return + } + + for (it in declaration.annotations) { + val annotationSymbol = it.toAnnotationClassLikeSymbol(context.session) ?: continue + + if (annotationSymbol.getAnnotationRetention(context.session) != AnnotationRetention.SOURCE) { + reporter.reportOn(it.source, FirErrors.NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION, 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 ba59fc31f37..70a2fdd5a47 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 @@ -399,6 +399,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_MODIFIER_FORM import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_TAIL_RECURSIVE_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_VARARG_SPREAD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_INLINE @@ -984,6 +985,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(NON_INTERNAL_PUBLISHED_API, "'@PublishedApi' annotation is only applicable to internal declaration.") map.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties.") map.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties.") + map.put( + NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION, + "The lambda expression here is an inlined argument, so this annotation cannot be stored anywhere.", + ) // OptIn map.put(OPT_IN_USAGE, "{1}", TO_STRING, STRING) diff --git a/compiler/testData/diagnostics/tests/annotations/options/functions.fir.kt b/compiler/testData/diagnostics/tests/annotations/options/functions.fir.kt index 0b514effb7f..8e4bd8e6830 100644 --- a/compiler/testData/diagnostics/tests/annotations/options/functions.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/options/functions.fir.kt @@ -21,8 +21,8 @@ fun foo(arg: Int) { // Literal is annotatable bar @FunAnn { arg } // Annotatable in principle but useless, fast is inline - fast @FunAnn { arg } - fast2(1, @FunAnn { arg }) + fast @FunAnn { arg } + fast2(1, @FunAnn { arg }) // Source annotation, ok fast @SourceAnn { arg } fast2(1, @SourceAnn { arg })