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