[K2] Disappeared OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN (2)
Added checking usages of markers as qualifiers. KT-59998
This commit is contained in:
committed by
Space Team
parent
445ed7abc9
commit
97f09acc92
+39
-12
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.type
|
||||
|
||||
import org.jetbrains.kotlin.KtRealSourceElementKind
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
@@ -18,18 +19,17 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_CAN
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.getContainingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
object FirOptInUsageTypeRefChecker : FirTypeRefChecker() {
|
||||
@OptIn(SymbolInternals::class)
|
||||
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val source = typeRef.source
|
||||
if (source?.kind !is KtRealSourceElementKind) return
|
||||
@@ -38,23 +38,34 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() {
|
||||
|
||||
val typeAliasExpandedSymbol = (symbol as? FirTypeAliasSymbol)?.resolvedExpandedTypeRef?.findSymbol(context.session)
|
||||
val processedSymbol = typeAliasExpandedSymbol ?: symbol
|
||||
val resolvedTypeRef = typeRef as? FirResolvedTypeRef
|
||||
val qualifier = (resolvedTypeRef?.delegatedTypeRef as? FirUserTypeRef)?.qualifier
|
||||
|
||||
val classId = processedSymbol.classId
|
||||
val lastAnnotationCall = context.callsOrAssignments.lastOrNull() as? FirAnnotation
|
||||
if (lastAnnotationCall == null || lastAnnotationCall.annotationTypeRef !== typeRef) {
|
||||
if (classId == OptInNames.REQUIRES_OPT_IN_CLASS_ID || classId == OptInNames.OPT_IN_CLASS_ID) {
|
||||
reporter.reportOn(source, OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION, context)
|
||||
} else if (processedSymbol is FirRegularClassSymbol &&
|
||||
processedSymbol.fir.getAnnotationByClassId(OptInNames.REQUIRES_OPT_IN_CLASS_ID, context.session) != null
|
||||
) {
|
||||
reporter.reportOn(source, OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN, context)
|
||||
when {
|
||||
classId == OptInNames.REQUIRES_OPT_IN_CLASS_ID || classId == OptInNames.OPT_IN_CLASS_ID ->
|
||||
reporter.reportOn(source, OPT_IN_CAN_ONLY_BE_USED_AS_ANNOTATION, context)
|
||||
processedSymbol.isExperimentalMarker(context.session) ->
|
||||
reporter.reportOn(source, OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN, context)
|
||||
!qualifier.isNullOrEmpty() -> {
|
||||
processedSymbol.checkContainingClasses(source, qualifier, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isSupertypeRef = typeRef in (context.containingDeclarations.lastOrNull() as? FirClass)?.superTypeRefs.orEmpty()
|
||||
with(FirOptInUsageBaseChecker) {
|
||||
val experimentalities = mutableSetOf<FirOptInUsageBaseChecker.Experimentality>()
|
||||
experimentalities.addAll(symbol.loadClassifierExperimentalities(context, isSupertypeRef))
|
||||
if (typeAliasExpandedSymbol != null) experimentalities.addAll(typeAliasExpandedSymbol.loadClassifierExperimentalities(context, isSupertypeRef))
|
||||
if (typeAliasExpandedSymbol != null) {
|
||||
experimentalities.addAll(
|
||||
typeAliasExpandedSymbol.loadClassifierExperimentalities(
|
||||
context,
|
||||
isSupertypeRef
|
||||
)
|
||||
)
|
||||
}
|
||||
experimentalities.addAll(loadExperimentalitiesFromConeArguments(context, coneType.typeArguments.toList()))
|
||||
reportNotAcceptedExperimentalities(experimentalities, typeRef, context, reporter)
|
||||
}
|
||||
@@ -72,4 +83,20 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() {
|
||||
val coneType = coneTypeSafe<ConeClassLikeType>() ?: return null
|
||||
return coneType.lookupTag.toSymbol(session)
|
||||
}
|
||||
|
||||
private fun FirClassLikeSymbol<*>.isExperimentalMarker(session: FirSession) =
|
||||
this is FirRegularClassSymbol && fir.getAnnotationByClassId(OptInNames.REQUIRES_OPT_IN_CLASS_ID, session) != null
|
||||
|
||||
private tailrec fun FirClassLikeSymbol<*>.checkContainingClasses(
|
||||
source: KtSourceElement,
|
||||
qualifier: List<FirQualifierPart>,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
) {
|
||||
val containingClassSymbol = this.getContainingClassLookupTag()?.toSymbol(context.session) ?: return
|
||||
if (qualifier.any { it.name == containingClassSymbol.name } && containingClassSymbol.isExperimentalMarker(context.session)) {
|
||||
reporter.reportOn(source, OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN, context)
|
||||
}
|
||||
containingClassSymbol.checkContainingClasses(source, qualifier, context, reporter)
|
||||
}
|
||||
}
|
||||
|
||||
+25
-14
@@ -45,34 +45,45 @@ fun f5() {}
|
||||
|
||||
// Usages of markers as types should be errors
|
||||
|
||||
@RequiresOptIn
|
||||
annotation class Marker {
|
||||
class NestedClass
|
||||
object A {
|
||||
@RequiresOptIn
|
||||
annotation class Marker {
|
||||
class NestedClass() {
|
||||
class NestedClass2
|
||||
|
||||
companion object {
|
||||
const val value = 42
|
||||
fun f12(m: NestedClass2){}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val value = 42
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun f6(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>) {}
|
||||
fun f7(): List<<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>>? = null
|
||||
fun f8(): <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>test.Marker?<!> = null
|
||||
fun f6(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker<!>) {}
|
||||
fun f7(): List<<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker<!>>? = null
|
||||
fun f8(): <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>test.A.Marker?<!> = null
|
||||
|
||||
typealias Marker0 = <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>
|
||||
typealias Marker0 = <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker<!>
|
||||
|
||||
fun f9(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker0<!>) {}
|
||||
|
||||
|
||||
// Usages of markers as qualifiers are errors as well (we can lift this restriction for select cases)
|
||||
|
||||
fun f10(m: Marker.NestedClass) {
|
||||
Marker.value
|
||||
fun f10(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.NestedClass<!>) {
|
||||
A.Marker.value
|
||||
}
|
||||
|
||||
fun f11(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>A.Marker.NestedClass.NestedClass2<!>) {}
|
||||
|
||||
|
||||
// FILE: usage-from-other-file.kt
|
||||
|
||||
// Usages of markers in import statements should be OK, but not as qualifiers to import their nested classes
|
||||
|
||||
import test.Marker
|
||||
import test.Marker.NestedClass
|
||||
import test.Marker.Companion
|
||||
import test.A.Marker
|
||||
import test.A.Marker.NestedClass
|
||||
import test.A.Marker.Companion
|
||||
|
||||
fun f12(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>test.A.Marker.NestedClass.NestedClass2<!>) {}
|
||||
|
||||
+25
-14
@@ -45,34 +45,45 @@ fun f5() {}
|
||||
|
||||
// Usages of markers as types should be errors
|
||||
|
||||
@RequiresOptIn
|
||||
annotation class Marker {
|
||||
class NestedClass
|
||||
object A {
|
||||
@RequiresOptIn
|
||||
annotation class Marker {
|
||||
class NestedClass() {
|
||||
class NestedClass2
|
||||
|
||||
companion object {
|
||||
const val value = 42
|
||||
fun f12(m: NestedClass2){}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val value = 42
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun f6(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>) {}
|
||||
fun f7(): List<<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>>? = null
|
||||
fun f8(): test.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>? = null
|
||||
fun f6(m: A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>) {}
|
||||
fun f7(): List<A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>>? = null
|
||||
fun f8(): test.A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>? = null
|
||||
|
||||
typealias Marker0 = <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>
|
||||
typealias Marker0 = A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>
|
||||
|
||||
fun f9(m: <!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker0<!>) {}
|
||||
|
||||
|
||||
// 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!>Marker<!>.NestedClass) {
|
||||
<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.value
|
||||
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
|
||||
}
|
||||
|
||||
fun f11(m: A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass.NestedClass2) {}
|
||||
|
||||
|
||||
// FILE: usage-from-other-file.kt
|
||||
|
||||
// Usages of markers in import statements should be OK, but not as qualifiers to import their nested classes
|
||||
|
||||
import test.Marker
|
||||
import test.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass
|
||||
import test.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.Companion
|
||||
import test.A.Marker
|
||||
import test.A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass
|
||||
import test.A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.Companion
|
||||
|
||||
fun f12(m: test.A.<!OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN!>Marker<!>.NestedClass.NestedClass2) {}
|
||||
|
||||
+47
-28
@@ -1,16 +1,56 @@
|
||||
package
|
||||
|
||||
public fun f12(/*0*/ m: test.A.Marker.NestedClass.NestedClass2): kotlin.Unit
|
||||
|
||||
package test {
|
||||
public fun f1(/*0*/ e: kotlin.RequiresOptIn): kotlin.Unit
|
||||
public fun f10(/*0*/ m: test.Marker.NestedClass): kotlin.Unit
|
||||
public fun f10(/*0*/ m: test.A.Marker.NestedClass): kotlin.Unit
|
||||
public fun f11(/*0*/ m: test.A.Marker.NestedClass.NestedClass2): kotlin.Unit
|
||||
public fun f2(/*0*/ u: kotlin.OptIn?): kotlin.Unit
|
||||
public fun f3(/*0*/ e: test.Experimental0 /* = kotlin.RequiresOptIn */): kotlin.Unit
|
||||
public fun f4(/*0*/ u: test.OptIn0 /* = kotlin.OptIn */): kotlin.Unit
|
||||
@test.VarargKClasses(k = {kotlin.RequiresOptIn::class, kotlin.OptIn::class, kotlin.RequiresOptIn::class, kotlin.OptIn::class}) public fun f5(): kotlin.Unit
|
||||
public fun f6(/*0*/ m: test.Marker): kotlin.Unit
|
||||
public fun f7(): kotlin.collections.List<test.Marker>?
|
||||
public fun f8(): test.Marker?
|
||||
public fun f9(/*0*/ m: test.Marker0 /* = test.Marker */): kotlin.Unit
|
||||
public fun f6(/*0*/ m: test.A.Marker): kotlin.Unit
|
||||
public fun f7(): kotlin.collections.List<test.A.Marker>?
|
||||
public fun f8(): test.A.Marker?
|
||||
public fun f9(/*0*/ m: test.Marker0 /* = test.A.Marker */): kotlin.Unit
|
||||
|
||||
public object A {
|
||||
private constructor A()
|
||||
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 toString(): kotlin.String
|
||||
|
||||
@kotlin.RequiresOptIn public final annotation class Marker : kotlin.Annotation {
|
||||
public constructor Marker()
|
||||
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 toString(): kotlin.String
|
||||
|
||||
public companion object Companion {
|
||||
private constructor Companion()
|
||||
public const final val value: kotlin.Int = 42
|
||||
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 toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class NestedClass {
|
||||
public constructor NestedClass()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final fun f12(/*0*/ m: test.A.Marker.NestedClass.NestedClass2): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public final class NestedClass2 {
|
||||
public constructor NestedClass2()
|
||||
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 toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@kotlin.RequiresOptIn(level = Level.ERROR) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class M : kotlin.Annotation {
|
||||
public constructor M()
|
||||
@@ -19,28 +59,6 @@ package test {
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.RequiresOptIn public final annotation class Marker : kotlin.Annotation {
|
||||
public constructor Marker()
|
||||
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 toString(): kotlin.String
|
||||
|
||||
public companion object Companion {
|
||||
private constructor Companion()
|
||||
public const final val value: kotlin.Int = 42
|
||||
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 toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class NestedClass {
|
||||
public constructor NestedClass()
|
||||
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 toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
|
||||
public final annotation class VarargKClasses : kotlin.Annotation {
|
||||
public constructor VarargKClasses(/*0*/ vararg k: kotlin.reflect.KClass<*> /*kotlin.Array<out kotlin.reflect.KClass<*>>*/)
|
||||
public final val k: kotlin.Array<out kotlin.reflect.KClass<*>>
|
||||
@@ -49,6 +67,7 @@ package test {
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
public typealias Experimental0 = kotlin.RequiresOptIn
|
||||
public typealias Marker0 = test.Marker
|
||||
public typealias Marker0 = test.A.Marker
|
||||
public typealias OptIn0 = kotlin.OptIn
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user