FIR: add EXPERIMENTAL_API_USAGE reporting

This commit is contained in:
Mikhail Glukhikh
2021-07-08 15:50:53 +03:00
parent 3235b09a92
commit 82f268d611
81 changed files with 520 additions and 650 deletions
@@ -1,4 +1,5 @@
// FIR_IDENTICAL
// ALLOW_KOTLIN_PACKAGE
// !LANGUAGE: +UnrestrictedBuilderInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: annotation.kt
@@ -1,4 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// ALLOW_KOTLIN_PACKAGE
// !WITH_NEW_INFERENCE
// FILE: annotation.kt
@@ -1,4 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// ALLOW_KOTLIN_PACKAGE
// !WITH_NEW_INFERENCE
// FILE: annotation.kt
@@ -1,4 +1,5 @@
// FIR_IDENTICAL
// ALLOW_KOTLIN_PACKAGE
// !LANGUAGE: +UnrestrictedBuilderInference
// !DIAGNOSTICS: -UNUSED_PARAMETER
@@ -1,4 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// ALLOW_KOTLIN_PACKAGE
// FILE: annotation.kt
@@ -1,4 +1,5 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// ALLOW_KOTLIN_PACKAGE
// FILE: annotation.kt
@@ -1,138 +0,0 @@
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: api.kt
package api
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS,
AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.BINARY)
annotation class ExperimentalAPI
@ExperimentalAPI
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS,
AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.BINARY)
annotation class EAnno
// FILE: usage-propagate.kt
package usage1
import api.*
@ExperimentalAPI
@EAnno fun function() {}
@ExperimentalAPI
fun parameter(@EAnno p: String) {}
@ExperimentalAPI
fun parameterType(p: <!WRONG_ANNOTATION_TARGET!>@EAnno<!> String) {}
@ExperimentalAPI
fun returnType(): <!WRONG_ANNOTATION_TARGET!>@EAnno<!> Unit {}
@ExperimentalAPI
@EAnno val property = ""
@ExperimentalAPI
@EAnno typealias Typealias = Unit
@ExperimentalAPI
@EAnno class Klass
@ExperimentalAPI
annotation class AnnotationArgument(val p: EAnno)
@ExperimentalAPI
fun insideBody() {
@EAnno fun local() {}
}
@ExperimentalAPI
fun inDefaultArgument(f: () -> Unit = @EAnno fun() {}) {}
@ExperimentalAPI
val inProperty = @EAnno fun() {}
@ExperimentalAPI
val inPropertyAccessor: () -> Unit
get() = @EAnno fun() {}
// FILE: usage-use.kt
package usage2
import api.*
@OptIn(ExperimentalAPI::class)
@EAnno fun function() {}
@OptIn(ExperimentalAPI::class)
fun parameter(@EAnno p: String) {}
@OptIn(ExperimentalAPI::class)
fun parameterType(p: <!WRONG_ANNOTATION_TARGET!>@EAnno<!> String) {}
@OptIn(ExperimentalAPI::class)
fun returnType(): <!WRONG_ANNOTATION_TARGET!>@EAnno<!> Unit {}
@OptIn(ExperimentalAPI::class)
@EAnno val property = ""
@OptIn(ExperimentalAPI::class)
@EAnno typealias Typealias = Unit
@OptIn(ExperimentalAPI::class)
@EAnno class Klass
@OptIn(ExperimentalAPI::class)
annotation class AnnotationArgument(val p: EAnno)
fun insideBody() {
@OptIn(ExperimentalAPI::class) @EAnno fun local() {}
}
fun inDefaultArgument(@OptIn(ExperimentalAPI::class) f: () -> Unit = @EAnno fun() {}) {}
@OptIn(ExperimentalAPI::class)
val inProperty = @EAnno fun() {}
val inPropertyAccessor: () -> Unit
@OptIn(ExperimentalAPI::class)
get() = @EAnno fun() {}
// FILE: usage-none.kt
package usage3
import api.*
@EAnno fun function() {}
fun parameter(@EAnno p: String) {}
fun parameterType(p: <!WRONG_ANNOTATION_TARGET!>@EAnno<!> String) {}
fun returnType(): <!WRONG_ANNOTATION_TARGET!>@EAnno<!> Unit {}
@EAnno val property = ""
@EAnno typealias Typealias = Unit
@EAnno class Klass
annotation class AnnotationArgument(val p: EAnno)
fun insideBody() {
@EAnno fun local() {}
}
fun inDefaultArgument(f: () -> Unit = @EAnno fun() {}) {}
val inProperty = @EAnno fun() {}
val inPropertyAccessor: () -> Unit
get() = @EAnno fun() {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// !DIAGNOSTICS: -UNUSED_PARAMETER
// FILE: api.kt
@@ -1,84 +0,0 @@
// !DIAGNOSTICS: -NOTHING_TO_INLINE -UNUSED_PARAMETER
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
package api
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Retention(AnnotationRetention.BINARY)
annotation class API
@API
fun f() {}
// FILE: usage.kt
package usage
import api.*
fun use1() {
f()
}
val use2 = f()
// FILE: inline-usage.kt
package usage
import api.*
inline fun inlineUse1() {
f()
}
inline var inlineUse2: Unit
get() {
f()
}
set(value) {
f()
}
var inlineUse3: Unit
inline get() {
f()
}
@API
inline set(value) {
f()
}
@API
inline fun inlineUse4() {
f()
}
// FILE: private-inline-usage.kt
package usage
import api.*
private inline fun privateInline1() {
f()
}
internal inline fun privateInline2() {
f()
}
private inline var privateInline3: Unit
get() {
f()
}
set(value) {
f()
}
internal class InternalClass {
inline fun privateInline4() {
f()
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -NOTHING_TO_INLINE -UNUSED_PARAMETER
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
@@ -1,89 +0,0 @@
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
package api
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class ExperimentalAPI
@ExperimentalAPI
class C {
fun function(): String = ""
val property: String = ""
class Nested
inner class Inner
}
@ExperimentalAPI
fun C.extension() {}
// FILE: usage-propagate.kt
package usage1
import api.*
@ExperimentalAPI
fun useAll() {
val c: C = C()
c.function()
c.property
C.Nested()
c.Inner()
c.extension()
}
@ExperimentalAPI
class Use {
fun useAll(c: C) {
c.function()
c.property
C.Nested()
c.Inner()
c.extension()
}
}
// FILE: usage-use.kt
package usage2
import api.*
@OptIn(ExperimentalAPI::class)
fun useAll() {
val c: C = C()
c.function()
c.property
C.Nested()
c.Inner()
c.extension()
}
@OptIn(ExperimentalAPI::class)
class Use {
fun useAll(c: C) {
c.function()
c.property
C.Nested()
c.Inner()
c.extension()
}
}
// FILE: usage-none.kt
package usage3
import api.*
fun use() {
val c: C = C()
c.function()
c.property
C.Nested()
c.Inner()
c.extension()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
@@ -1,37 +0,0 @@
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
package api
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.BINARY)
annotation class ExperimentalAPI
@ExperimentalAPI
class C {
@ExperimentalAPI
fun function() {}
@ExperimentalAPI
val property: String = ""
@ExperimentalAPI
class Nested {
@ExperimentalAPI
fun nestedFunction() {}
}
}
// FILE: usage.kt
package usage
import api.*
fun use() {
val c: C = C()
c.function()
c.property
C.Nested().nestedFunction()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
@@ -40,5 +40,5 @@ package usage3
import api.*
@Anno(MEANING)
@Anno(<!EXPERIMENTAL_API_USAGE!>MEANING<!>)
fun usage() {}
@@ -52,7 +52,7 @@ package usage3
import api.*
fun use1() {
C.D.E.F()
C.D.<!EXPERIMENTAL_API_USAGE!>E<!>.<!EXPERIMENTAL_API_USAGE!>F<!>()
}
fun use2(f: C.D.E.F) = f.hashCode()
fun use2(f: <!EXPERIMENTAL_API_USAGE!>C.D.E.F<!>) = <!EXPERIMENTAL_API_USAGE!>f<!>.hashCode()
@@ -23,5 +23,5 @@ class Derived : Base() {
}
fun test(b: Base) {
b.foo()
b.<!EXPERIMENTAL_API_USAGE_ERROR!>foo<!>()
}
@@ -1,24 +0,0 @@
// FILE: api.kt
@<!EXPERIMENTAL_IS_NOT_ENABLED!>RequiresOptIn<!>
@Retention(AnnotationRetention.BINARY)
annotation class Marker
@Marker
fun f() {}
// FILE: usage.kt
fun use1() {
f()
}
@Marker
fun use2() {
f()
}
@<!EXPERIMENTAL_IS_NOT_ENABLED!>OptIn<!>(Marker::class)
fun use3() {
f()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: api.kt
@<!EXPERIMENTAL_IS_NOT_ENABLED!>RequiresOptIn<!>
@@ -0,0 +1,24 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
@RequiresOptIn
@Retention(AnnotationRetention.BINARY)
annotation class E
@set:E
var x: Int = 42
@E
var y: Int = 24
var z: Int = 44
@E set(arg) {
field = arg
}
fun user(): Int {
<!EXPERIMENTAL_API_USAGE_ERROR!>x<!> = 10
<!EXPERIMENTAL_API_USAGE_ERROR!>y<!> = 5
<!EXPERIMENTAL_API_USAGE_ERROR!>x<!> = 15
return x + <!EXPERIMENTAL_API_USAGE_ERROR!>y<!> + z
}
@@ -0,0 +1,13 @@
package
@set:E public var x: kotlin.Int
@E public var y: kotlin.Int
@set:E public var z: kotlin.Int
public fun user(): kotlin.Int
@kotlin.RequiresOptIn @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class E : kotlin.Annotation {
public constructor E()
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
}
@@ -9,15 +9,15 @@ annotation class Marker
interface Some
abstract class User {
abstract fun createSome(): Some
fun Some?.onSome() {}
fun withSome(some: Some? = null) {}
abstract fun createSome(): <!EXPERIMENTAL_API_USAGE_ERROR!>Some<!>
fun <!EXPERIMENTAL_API_USAGE_ERROR!>Some<!>?.onSome() {}
fun withSome(some: <!EXPERIMENTAL_API_USAGE_ERROR!>Some<!>? = null) {}
fun use() {
val something = createSome()
val somethingOther: Some = createSome()
null.onSome()
withSome()
val something = <!EXPERIMENTAL_API_USAGE_ERROR!>createSome<!>()
val somethingOther: <!EXPERIMENTAL_API_USAGE_ERROR!>Some<!> = <!EXPERIMENTAL_API_USAGE_ERROR!>createSome<!>()
null.<!EXPERIMENTAL_API_USAGE_ERROR!>onSome<!>()
<!EXPERIMENTAL_API_USAGE_ERROR!>withSome<!>()
}
}
@@ -25,15 +25,15 @@ data class DataClass(@property:Marker val x: Int)
fun useDataClass(d: DataClass) {
// Should have error in both
d.x
d.<!EXPERIMENTAL_API_USAGE_ERROR!>x<!>
val (x) = d
}
typealias My = Some
typealias My = <!EXPERIMENTAL_API_USAGE_ERROR!>Some<!>
fun my(my: My) {}
fun my(my: <!EXPERIMENTAL_API_USAGE_ERROR!>My<!>) {}
fun your(my: Some) {}
fun your(my: <!EXPERIMENTAL_API_USAGE_ERROR!>Some<!>) {}
@Marker
interface ExperimentalType {
@@ -48,7 +48,7 @@ interface NotExperimentalExtension : ExperimentalType {
fun use(arg: NotExperimentalExtension) {
arg.foo()
arg.bar()
arg.<!EXPERIMENTAL_API_USAGE_ERROR!>bar<!>()
}
@Marker
@@ -67,7 +67,7 @@ typealias MyList = ArrayList<I>
typealias YourList = ArrayList<String>
fun main() {
val x = listOf(A(), B())
val x = <!EXPERIMENTAL_API_USAGE_ERROR!>listOf<!>(A(), B())
val y = MyList()
val z = YourList()
YourList().add("")
@@ -83,7 +83,7 @@ object O {
operator fun provideDelegate(x: Any?, y: Any?): C = C()
}
val x: String by O
val x: String by <!EXPERIMENTAL_API_USAGE_ERROR!>O<!>
@Marker
class OperatorContainer : Comparable<OperatorContainer> {
@@ -116,8 +116,8 @@ operator fun String.minus(s: String) = OperatorContainer()
operator fun String.invoke() = OperatorContainer()
fun operatorContainerUsage(s: String, a: AnotherContainer) {
val res1 = s - s
val res2 = s()
val res3 = res1 > res2
for (c in a) {}
val res1 = s <!EXPERIMENTAL_API_USAGE_ERROR!>-<!> s
val res2 = <!EXPERIMENTAL_API_USAGE_ERROR!>s<!>()
val res3 = <!EXPERIMENTAL_API_USAGE_ERROR!>res1<!> <!EXPERIMENTAL_API_USAGE_ERROR!>><!> <!EXPERIMENTAL_API_USAGE_ERROR!>res2<!>
<!EXPERIMENTAL_API_USAGE_ERROR, EXPERIMENTAL_API_USAGE_ERROR, EXPERIMENTAL_API_USAGE_ERROR, EXPERIMENTAL_API_USAGE_ERROR!>for (c in a) {}<!>
}
@@ -1,79 +0,0 @@
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// !DIAGNOSTICS: -UNUSED_VARIABLE
// FILE: api.kt
package api
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.TYPEALIAS,
AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.BINARY)
annotation class ExperimentalAPI
@ExperimentalAPI
fun function(): String = ""
@ExperimentalAPI
val property: String = ""
@ExperimentalAPI
typealias Typealias = String
// FILE: usage-propagate.kt
package usage1
import api.*
@ExperimentalAPI
fun useAll() {
function()
property
val s: Typealias = ""
}
@ExperimentalAPI
class Use {
fun useAll() {
function()
property
val s: Typealias = ""
}
}
// FILE: usage-use.kt
package usage2
import api.*
fun useAll() {
@OptIn(ExperimentalAPI::class)
{
function()
property
val s: Typealias = ""
}()
}
@OptIn(ExperimentalAPI::class)
class Use {
fun useAll() {
function()
property
val s: Typealias = ""
}
}
// FILE: usage-none.kt
package usage3
import api.*
fun use() {
function()
property
val s: Typealias = ""
s.hashCode()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// !DIAGNOSTICS: -UNUSED_VARIABLE
// FILE: api.kt
@@ -1,14 +0,0 @@
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
package api
@RequiresOptIn
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class ExperimentalAPI
@ExperimentalAPI
class Foo
typealias Bar = Foo
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
@@ -21,11 +21,11 @@ annotation class M
// Usages as types should be errors
fun f1(e: RequiresOptIn) {}
fun f2(u: OptIn?) {}
fun f1(e: <!EXPERIMENTAL_CAN_ONLY_BE_USED_AS_ANNOTATION!>RequiresOptIn<!>) {}
fun f2(u: <!EXPERIMENTAL_CAN_ONLY_BE_USED_AS_ANNOTATION!>OptIn?<!>) {}
typealias Experimental0 = RequiresOptIn
typealias OptIn0 = OptIn
typealias Experimental0 = <!EXPERIMENTAL_CAN_ONLY_BE_USED_AS_ANNOTATION!>RequiresOptIn<!>
typealias OptIn0 = <!EXPERIMENTAL_CAN_ONLY_BE_USED_AS_ANNOTATION!>OptIn<!>
fun f3(e: Experimental0 /* TODO */) {}
fun f4(u: OptIn0 /* TODO */) {}
@@ -1,39 +0,0 @@
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
package api
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class ExperimentalAPI1
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class ExperimentalAPI2
@ExperimentalAPI1
fun compilation() {}
@ExperimentalAPI2
fun runtime() {}
// FILE: usage.kt
@file:OptIn(ExperimentalAPI1::class)
package usage
import api.*
fun use() {
compilation()
runtime()
}
class Use {
fun use() {
compilation()
runtime()
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
@@ -1,4 +1,5 @@
// FIR_IDENTICAL
// FIR_IDE_IGNORE
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn api.ExperimentalAPI
// MODULE: api
// FILE: api.kt
@@ -1,55 +0,0 @@
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
package api
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class E1
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class E2
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class E3
@E1
fun e1() {}
@E2
fun e2() {}
@E3
fun e3() {}
// FILE: usage.kt
package usage
import api.*
@OptIn(E1::class, E2::class, E3::class)
fun use1() {
e1()
e2()
e3()
}
@OptIn(E1::class, E3::class)
fun use2() {
e1()
@OptIn(E2::class) e2()
e3()
}
@OptIn(E1::class, E2::class)
fun use3() {
e1()
e2()
e3()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !USE_EXPERIMENTAL: kotlin.RequiresOptIn
// FILE: api.kt
@@ -2,9 +2,9 @@
fun main() {
val list = listOf(A())
list.forEach(A::foo)
list.forEach(A::<!EXPERIMENTAL_API_USAGE_ERROR!>foo<!>)
list.forEach {
it.foo()
it.<!EXPERIMENTAL_API_USAGE_ERROR!>foo<!>()
}
}