2/2 [FIR] Report all KotlinActual annotation usages in Kotlin.
KT-67202
Implement FirKotlinActualAnnotationHasNoEffectInKotlinExpressionChecker and
FirKotlinActualAnnotationHasNoEffectInKotlinTypeChecker
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 15ab28c..1ebd9a6 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
@@ -17,6 +17,7 @@
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
get() = setOf(
+ FirKotlinActualAnnotationHasNoEffectInKotlinExpressionChecker,
FirUnderscoreChecker,
FirExpressionAnnotationChecker,
FirDeprecationChecker,
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt
index 97bd8c7..ea08467 100644
--- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt
@@ -24,6 +24,7 @@
FirIncompatibleClassTypeChecker,
FirContextReceiversTypeChecker,
FirContextReceiversDeprecatedTypeChecker,
+ FirKotlinActualAnnotationHasNoEffectInKotlinTypeChecker,
FirProjectionRelationChecker,
FirArrayOfNothingTypeChecker,
)
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirKotlinActualAnnotationHasNoEffectInKotlinExpressionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirKotlinActualAnnotationHasNoEffectInKotlinExpressionChecker.kt
new file mode 100644
index 0000000..d0091dc
--- /dev/null
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirKotlinActualAnnotationHasNoEffectInKotlinExpressionChecker.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2024 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.MppCheckerKind
+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
+import org.jetbrains.kotlin.fir.containingClassLookupTag
+import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
+import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
+import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
+import org.jetbrains.kotlin.fir.expressions.FirStatement
+import org.jetbrains.kotlin.fir.references.toResolvedConstructorSymbol
+import org.jetbrains.kotlin.fir.types.classId
+import org.jetbrains.kotlin.fir.types.resolvedType
+import org.jetbrains.kotlin.name.StandardClassIds
+
+object FirKotlinActualAnnotationHasNoEffectInKotlinExpressionChecker : FirBasicExpressionChecker(MppCheckerKind.Common) {
+ override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
+ val kotlinActual = StandardClassIds.Annotations.KotlinActual
+ when (expression) {
+ is FirResolvedQualifier if expression.resolvedType.classId == kotlinActual ->
+ reporter.reportOn(expression.source, FirErrors.KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN, context)
+ is FirCallableReferenceAccess if expression.calleeReference.toResolvedConstructorSymbol()?.containingClassLookupTag()?.classId == kotlinActual ->
+ reporter.reportOn(expression.source, FirErrors.KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN, context)
+ is FirFunctionCall if expression.calleeReference.toResolvedConstructorSymbol()?.containingClassLookupTag()?.classId == kotlinActual ->
+ reporter.reportOn(expression.source, FirErrors.KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN, context)
+ }
+ }
+}
diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirKotlinActualAnnotationHasNoEffectInKotlinTypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirKotlinActualAnnotationHasNoEffectInKotlinTypeChecker.kt
new file mode 100644
index 0000000..1cba2c3
--- /dev/null
+++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirKotlinActualAnnotationHasNoEffectInKotlinTypeChecker.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010-2024 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.KtFakeSourceElementKind
+import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
+import org.jetbrains.kotlin.diagnostics.reportOn
+import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
+import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
+import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
+import org.jetbrains.kotlin.fir.types.classId
+import org.jetbrains.kotlin.name.StandardClassIds
+
+object FirKotlinActualAnnotationHasNoEffectInKotlinTypeChecker : FirResolvedTypeRefChecker(MppCheckerKind.Common) {
+ override fun check(typeRef: FirResolvedTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
+ if (typeRef.source == null || typeRef.source?.kind is KtFakeSourceElementKind) return
+ if (typeRef.coneType.classId == StandardClassIds.Annotations.KotlinActual) {
+ reporter.reportOn(typeRef.source, FirErrors.KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN, context)
+ }
+ }
+}
\ No newline at end of file
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 0d1add4..a02aa84 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
@@ -382,6 +382,7 @@
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_MISSING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_ON_NULLABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
+import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LABEL_NAME_CLASH
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_FIELD_IN_VAL_PROPERTY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION
@@ -1116,6 +1117,10 @@
"'DeprecatedSinceKotlin' annotation cannot be used outside 'kotlin' subpackages."
)
map.put(
+ KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN,
+ "'KotlinActual' annotation has no effect in Kotlin."
+ )
+ map.put(
OVERRIDE_DEPRECATION,
"This declaration overrides a deprecated member but is not marked as deprecated itself. Please add the ''@Deprecated'' annotation or suppress the diagnostic.",
EMPTY,
diff --git a/compiler/testData/diagnostics/tests/KotlinActualAnnotationHasNoEffectInKotlin.fir.kt b/compiler/testData/diagnostics/tests/KotlinActualAnnotationHasNoEffectInKotlin.fir.kt
new file mode 100644
index 0000000..140ebc7
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/KotlinActualAnnotationHasNoEffectInKotlin.fir.kt
@@ -0,0 +1,20 @@
+// WITH_KOTLIN_JVM_ANNOTATIONS
+
+import kotlin.annotations.jvm.KotlinActual
+
+@<!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>
+fun foo() {
+ val a: <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!> = null!!
+ val b: (<!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>) -> Unit = { x -> }
+ val c: ((<!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>) -> Unit, (<!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>) -> Unit) -> ((<!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>) -> Unit) = { x, y -> { } }
+ val d: (() -> <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>, () -> <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>) -> (() -> <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>) = { x, y -> { null!! } }
+
+ val e = <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>::class
+ val f = <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>::<!CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR!>KotlinActual<!><!>
+ val g = <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual()<!>
+}
+
+typealias Duh = <!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>
+
+@[<!KOTLIN_ACTUAL_ANNOTATION_HAS_NO_EFFECT_IN_KOTLIN!>KotlinActual<!>]
+fun bar() {}
diff --git a/compiler/testData/diagnostics/tests/KotlinActualAnnotationHasNoEffectInKotlin.kt b/compiler/testData/diagnostics/tests/KotlinActualAnnotationHasNoEffectInKotlin.kt
index e44a514..b8dbbab 100644
--- a/compiler/testData/diagnostics/tests/KotlinActualAnnotationHasNoEffectInKotlin.kt
+++ b/compiler/testData/diagnostics/tests/KotlinActualAnnotationHasNoEffectInKotlin.kt
@@ -1,4 +1,3 @@
-// FIR_IDENTICAL
// WITH_KOTLIN_JVM_ANNOTATIONS
import kotlin.annotations.jvm.KotlinActual