[tests] Add new (and refactor existing) tests for @SubclassOptInRequired

KT-54617
This commit is contained in:
Stanislav Ruban
2023-05-22 17:31:37 +03:00
committed by Space Team
parent 833edfb209
commit e6d5df18b8
21 changed files with 672 additions and 652 deletions
@@ -0,0 +1,32 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@SubclassOptInRequired(ApiMarker::class)
open class OpenKlass
@SubclassOptInRequired(ApiMarker::class)
abstract class AbstractKlass
@SubclassOptInRequired(ApiMarker::class)
interface Interface
class OuterKlass {
@SubclassOptInRequired(ApiMarker::class)
open class NestedOpenKlass
@SubclassOptInRequired(ApiMarker::class)
abstract class NestedAbstractKlass
@SubclassOptInRequired(ApiMarker::class)
interface NestedInterface
@SubclassOptInRequired(ApiMarker::class)
open inner class InnerOpenKlass
@SubclassOptInRequired(ApiMarker::class)
abstract inner class InnerAbstractKlass
}
@@ -0,0 +1,99 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
// final classes are not valid targets for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
class Klass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
data class DataKlass(val arg: Int)
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
@JvmInline value class ValueKlass(val arg: Int)
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
annotation class AnnotationKlass
// functional interface is not a valid target for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
fun interface FunctionalInterface { fun func() }
// enum classes and objects are not valid targets for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
enum class EnumKlass { ENTRY }
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
object Objekt
// sealed classifiers are not valid targets for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
sealed class SealedKlass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
sealed interface SealedInterface
// local classes are not valid targets for @SubclassOptInRequired
fun foo() {
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
open class LocalOpenKlass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
abstract class LocalAbstractKlass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
class LocalKlass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
data class LocalDataKlass(val arg: Int)
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
object {}
}
class OuterKlass {
// final classes are not valid targets for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
class NestedKlass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
inner class InnerKlass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
data class NestedDataKlass(val arg: Int)
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
@JvmInline value class NestedValueKlass(val arg: Int)
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
annotation class NestedAnnotationKlass
// functional interface is not a valid target for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
fun interface NestedFunctionalInterface { fun func() }
// enum classes and objects are not valid targets for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
enum class NestedEnumKlass { ENTRY }
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
object NestedObjekt
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
companion object
// sealed classifiers are not valid targets for @SubclassOptInRequired
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
sealed class NestedSealedKlass
<!SUBCLASS_OPT_IN_INAPPLICABLE!>@SubclassOptInRequired(ApiMarker::class)<!>
sealed interface NestedSealedInterface
}
@@ -0,0 +1,31 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@SubclassOptInRequired(ApiMarker::class)
interface Interface
fun foo() {
// error: inheriting Interface requires an explicit opt-in
open class LocalOpenKlassA: <!OPT_IN_USAGE_ERROR!>Interface<!>
abstract class LocalAbstractKlassA: <!OPT_IN_USAGE_ERROR!>Interface<!>
class LocalKlassA: <!OPT_IN_USAGE_ERROR!>Interface<!>
data class LocalDataKlassA(val arg: Int): <!OPT_IN_USAGE_ERROR!>Interface<!>
object: <!OPT_IN_USAGE_ERROR!>Interface<!> {}
// opt-in is present, no errors
@OptIn(ApiMarker::class) open class LocalOpenKlassB: Interface
@OptIn(ApiMarker::class) abstract class LocalAbstractKlassB: Interface
@OptIn(ApiMarker::class) class LocalKlassB: Interface
@OptIn(ApiMarker::class) data class LocalDataKlassB(val arg: Int): Interface
@OptIn(ApiMarker::class) object: Interface {}
// requiring to opt-in into local classifiers works as well
// (even though it doesn't make that much sense)
@ApiMarker open class LocalOpenKlassC: Interface
@ApiMarker abstract class LocalAbstractKlassC: Interface
@ApiMarker class LocalKlassC: Interface
@ApiMarker data class LocalDataKlassC(val arg: Int): Interface
@ApiMarker object: Interface {}
}
@@ -0,0 +1,18 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@ApiMarker
interface I1
@SubclassOptInRequired(ApiMarker::class)
interface I2
// SubclassOptInRequired can only fix the error from I2
@SubclassOptInRequired(ApiMarker::class)
interface Impl1: <!OPT_IN_USAGE_ERROR!>I1<!>, I2
// the order of I1 and I2 shouldn't matter
@SubclassOptInRequired(ApiMarker::class)
interface Impl2: I2, <!OPT_IN_USAGE_ERROR!>I1<!>
@@ -0,0 +1,6 @@
// FIR_IDENTICAL
annotation class DummyAnnotation
<!OPT_IN_ARGUMENT_IS_NOT_MARKER!>@SubclassOptInRequired(DummyAnnotation::class)<!>
open class IncorrectSubclassOptInArgumentMarker
@@ -0,0 +1,22 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@ApiMarker
class UnstableKlassApi
open class UnstableFunctionApi {
@ApiMarker
open fun overridableFunction() {}
}
@SubclassOptInRequired(ApiMarker::class)
open class NotFullyOptedIntoApiMarker: UnstableFunctionApi() {
init {
// usage is unstable, error is reported even despite SubclassOptInRequired
<!OPT_IN_USAGE_ERROR!>UnstableKlassApi<!>()
}
// usage is unstable, error is reported even despite SubclassOptInRequired
override fun <!OPT_IN_OVERRIDE_ERROR!>overridableFunction<!>() {}
}
@@ -0,0 +1,34 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@SubclassOptInRequired(ApiMarker::class)
abstract class AbstractKlassOptInApi
// no opt-in: diagnostic reported
abstract class AbstractKlassOptInApiInheritorA: <!OPT_IN_USAGE_ERROR!>AbstractKlassOptInApi<!>()
// opt-in present: no diagnostic, opt-in isn't propagated
@OptIn(ApiMarker::class)
abstract class AbstractKlassOptInApiInheritorB: AbstractKlassOptInApi()
// inheritance opt-in required: no diagnostic, opt-in is propagated
@SubclassOptInRequired(ApiMarker::class)
abstract class AbstractKlassOptInApiInheritorC: AbstractKlassOptInApi()
// full opt-in required: no diagnostic, stricter opt-in is propagated
@ApiMarker
abstract class AbstractKlassOptInApiInheritorD: AbstractKlassOptInApi()
abstract class AbstractKlassOptInApiInheritorE: AbstractKlassOptInApiInheritorB() // inheritance opt-in isn't propagated
abstract class AbstractKlassOptInApiInheritorF: <!OPT_IN_USAGE_ERROR!>AbstractKlassOptInApiInheritorC<!>() // inheritance opt-in is propagated
abstract class AbstractKlassOptInApiInheritorG: <!OPT_IN_USAGE_ERROR!>AbstractKlassOptInApiInheritorD<!>() // inheritance opt-in is propagated
fun useSiteTestAbstractClasses(
o: AbstractKlassOptInApi, // usage opt-in isn't required
b: AbstractKlassOptInApiInheritorB, // usage opt-in isn't required
c: AbstractKlassOptInApiInheritorC, // usage opt-in isn't required
d: <!OPT_IN_USAGE_ERROR!>AbstractKlassOptInApiInheritorD<!>, // usage opt-in is required
e: AbstractKlassOptInApiInheritorE // usage opt-in isn't required
) {}
@@ -0,0 +1,12 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@SubclassOptInRequired(ApiMarker::class)
interface ToBeInheritedByDelegation
open class InheritingByDelegationA(arg: ToBeInheritedByDelegation): <!OPT_IN_USAGE_ERROR!>ToBeInheritedByDelegation<!> by arg
@SubclassOptInRequired(ApiMarker::class)
open class InheritingByDelegationB(arg: ToBeInheritedByDelegation): ToBeInheritedByDelegation by arg
@@ -0,0 +1,34 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@SubclassOptInRequired(ApiMarker::class)
interface InterfaceOptInApi
// no opt-in: diagnostic reported
interface InterfaceOptInApiInheritorA: <!OPT_IN_USAGE_ERROR!>InterfaceOptInApi<!>
// opt-in present: no diagnostic, opt-in isn't propagated
@OptIn(ApiMarker::class)
interface InterfaceOptInApiInheritorB: InterfaceOptInApi
// inheritance opt-in required: no diagnostic, opt-in is propagated
@SubclassOptInRequired(ApiMarker::class)
interface InterfaceOptInApiInheritorC: InterfaceOptInApi
// full opt-in required: no diagnostic, stricter opt-in is propagated
@ApiMarker
interface InterfaceOptInApiInheritorD: InterfaceOptInApi
interface InterfaceOptInApiInheritorE: InterfaceOptInApiInheritorB // inheritance opt-in isn't propagated
interface InterfaceOptInApiInheritorF: <!OPT_IN_USAGE_ERROR!>InterfaceOptInApiInheritorC<!> // inheritance opt-in is propagated
interface InterfaceOptInApiInheritorG: <!OPT_IN_USAGE_ERROR!>InterfaceOptInApiInheritorD<!> // inheritance opt-in is propagated
fun useSiteTestInterfaces(
o: InterfaceOptInApi, // usage opt-in isn't required
b: InterfaceOptInApiInheritorB, // usage opt-in isn't required
c: InterfaceOptInApiInheritorC, // usage opt-in isn't required
d: <!OPT_IN_USAGE_ERROR!>InterfaceOptInApiInheritorD<!>, // usage opt-in is required
e: InterfaceOptInApiInheritorE // usage opt-in isn't required
) {}
@@ -0,0 +1,34 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class ApiMarker
@SubclassOptInRequired(ApiMarker::class)
open class OpenKlassOptInApi
// no opt-in: diagnostic reported
open class OpenKlassOptInApiInheritorA: <!OPT_IN_USAGE_ERROR!>OpenKlassOptInApi<!>()
// opt-in present: no diagnostic, opt-in isn't propagated
@OptIn(ApiMarker::class)
open class OpenKlassOptInApiInheritorB: OpenKlassOptInApi()
// inheritance opt-in required: no diagnostic, opt-in is propagated
@SubclassOptInRequired(ApiMarker::class)
open class OpenKlassOptInApiInheritorC: OpenKlassOptInApi()
// full opt-in required: no diagnostic, stricter opt-in is propagated
@ApiMarker
open class OpenKlassOptInApiInheritorD: OpenKlassOptInApi()
open class OpenKlassOptInApiInheritorE: OpenKlassOptInApiInheritorB() // inheritance opt-in isn't propagated
open class OpenKlassOptInApiInheritorF: <!OPT_IN_USAGE_ERROR!>OpenKlassOptInApiInheritorC<!>() // inheritance opt-in is propagated
open class OpenKlassOptInApiInheritorG: <!OPT_IN_USAGE_ERROR!>OpenKlassOptInApiInheritorD<!>() // inheritance opt-in is propagated
fun useSiteTestOpenClasses() {
OpenKlassOptInApi() // usage opt-in isn't required
OpenKlassOptInApiInheritorB() // usage opt-in isn't required
OpenKlassOptInApiInheritorC() // usage opt-in isn't required
<!OPT_IN_USAGE_ERROR!>OpenKlassOptInApiInheritorD<!>() // usage opt-in is required
OpenKlassOptInApiInheritorE() // usage opt-in isn't required
}