[K2] Disappeared OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN (4)

Added checking usages of markers as qualifiers in properties and function calls.

^KT-59998
This commit is contained in:
Anastasia.Nekrasova
2023-11-06 18:27:54 +02:00
committed by Space Team
parent 72d69e16c4
commit 93ebd83ecd
4 changed files with 54 additions and 4 deletions
@@ -5,16 +5,49 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirOptInUsageBaseChecker.isExperimentalMarker
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
import org.jetbrains.kotlin.fir.getContainingClassLookupTag
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
object FirOptInUsageQualifierChecker : FirResolvedQualifierChecker() { object FirOptInUsageQualifierChecker : FirResolvedQualifierChecker() {
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
checkNotAcceptedExperimentalities(expression, context, reporter)
checkMarkerUsedAsQualifier(expression, context, reporter)
}
private fun checkNotAcceptedExperimentalities(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
val symbol = expression.symbol ?: return val symbol = expression.symbol ?: return
with(FirOptInUsageBaseChecker) { with(FirOptInUsageBaseChecker) {
val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null) val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null)
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter) reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter)
} }
} }
private fun checkMarkerUsedAsQualifier(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
val containingElements = context.containingElements
val parentExpression = containingElements.lastOrNull { it is FirQualifiedAccessExpression && it.dispatchReceiver == expression }
val source = parentExpression?.source ?: return
expression.symbol?.checkContainingClasses(source, context, reporter)
}
private tailrec fun FirClassLikeSymbol<*>.checkContainingClasses(
source: KtSourceElement,
context: CheckerContext,
reporter: DiagnosticReporter,
) {
if (isExperimentalMarker(context.session) && context.containingDeclarations.none { it.symbol == this }) {
reporter.reportOn(source, FirErrors.OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN, context)
}
val containingClassSymbol = this.getContainingClassLookupTag()?.toSymbol(context.session) ?: return
containingClassSymbol.checkContainingClasses(source, context, reporter)
}
} }
@@ -51,11 +51,16 @@ object A {
class NestedClass() { class NestedClass() {
class NestedClass2 class NestedClass2
fun f12(m: NestedClass2){} fun f12(m: NestedClass2){
val x = value
bar()
}
} }
companion object { companion object {
const val value = 42 const val value = 42
fun bar(){}
} }
} }
} }
@@ -74,7 +79,10 @@ fun f9(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>
// Usages of markers as qualifiers are errors as well (we can lift this restriction for select cases) // Usages of markers as qualifiers are errors as well (we can lift this restriction for select cases)
fun f10(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.NestedClass<!>) { fun f10(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.NestedClass<!>) {
A.Marker.value val a = <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.value<!>
<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.Companion.value<!>
<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.bar()<!>
<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.Companion.bar()<!>
} }
fun f11(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.NestedClass.NestedClass2<!>) {} fun f11(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.NestedClass.NestedClass2<!>) {}
@@ -51,11 +51,16 @@ object A {
class NestedClass() { class NestedClass() {
class NestedClass2 class NestedClass2
fun f12(m: NestedClass2){} fun f12(m: NestedClass2){
val x = value
bar()
}
} }
companion object { companion object {
const val value = 42 const val value = 42
fun bar(){}
} }
} }
} }
@@ -74,7 +79,10 @@ fun f9(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>
// Usages of markers as qualifiers are errors as well (we can lift this restriction for select cases) // Usages of markers as qualifiers are errors as well (we can lift this restriction for select cases)
fun f10(m: A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass) { fun f10(m: A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass) {
A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.value val a = A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.value
A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.Companion.value
A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.bar()
A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.Companion.bar()
} }
fun f11(m: A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass.NestedClass2) {} fun f11(m: A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass.NestedClass2) {}
@@ -30,6 +30,7 @@ package test {
public companion object Companion { public companion object Companion {
private constructor Companion() private constructor Companion()
public const final val value: kotlin.Int = 42 public const final val value: kotlin.Int = 42
public final fun bar(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String