Retain optional expected annotations when compiling platform code
After this change, optional expected annotations will be compiled to
physical class files on JVM, and stored to metadata on other platforms,
to allow their usages from dependent platform modules. For example:
@OptionalExpectation
expect annotation class A
When compiling this code on JVM, A.class will be produced as if the
class A did neither have the 'expect' modifier, nor had it been
annotated with OptionalExpectation. Note that if there's no actual
annotation class for A, then usages (which can only be usages as
annotation entries) are simply skipped.
Class A will be public from Kotlin's point of view (since it should
be possible to use it in Kotlin sources), but _package-private_ in Java
to disallow its usages outside of the declaring module.
#KT-18882 Fixed
#KT-24617 Fixed
This commit is contained in:
@@ -1,49 +1,34 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalMultiplatform
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// WITH_RUNTIME
|
||||
// FILE: common.kt
|
||||
// MODULE: library
|
||||
// FILE: expected.kt
|
||||
|
||||
package a
|
||||
|
||||
@OptionalExpectation
|
||||
expect annotation class Anno(val s: String)
|
||||
expect annotation class A(val x: Int)
|
||||
|
||||
// FILE: jvm.kt
|
||||
@OptionalExpectation
|
||||
expect annotation class B(val s: String)
|
||||
|
||||
import java.lang.reflect.AnnotatedElement
|
||||
// FILE: actual.kt
|
||||
|
||||
@Anno("Foo")
|
||||
class Foo @Anno("<init>") constructor(@Anno("x") x: Int) {
|
||||
@Anno("bar")
|
||||
fun bar() {}
|
||||
package a
|
||||
|
||||
@Anno("getX")
|
||||
var x = x
|
||||
@Anno("setX")
|
||||
set
|
||||
actual annotation class A(actual val x: Int)
|
||||
|
||||
@Anno("Nested")
|
||||
interface Nested
|
||||
}
|
||||
// MODULE: main(library)
|
||||
// FILE: main.kt
|
||||
|
||||
private fun check(element: AnnotatedElement) {
|
||||
check(element.annotations)
|
||||
}
|
||||
package usage
|
||||
|
||||
private fun check(annotations: Array<Annotation>) {
|
||||
val filtered = annotations.filterNot { it.annotationClass.java.name == "kotlin.Metadata" }
|
||||
if (filtered.isNotEmpty()) {
|
||||
throw AssertionError("Annotations should be empty: $filtered")
|
||||
}
|
||||
}
|
||||
import a.A
|
||||
import a.B
|
||||
|
||||
@A(42)
|
||||
@B("OK")
|
||||
fun box(): String {
|
||||
val foo = Foo::class.java
|
||||
check(foo)
|
||||
check(Foo.Nested::class.java)
|
||||
check(foo.declaredMethods.single { it.name == "bar" })
|
||||
check(foo.declaredMethods.single { it.name == "getX" })
|
||||
check(foo.declaredMethods.single { it.name == "setX" })
|
||||
check(foo.constructors.single())
|
||||
check(foo.constructors.single().parameterAnnotations.single())
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalMultiplatform
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
// FILE: common.kt
|
||||
|
||||
@OptionalExpectation
|
||||
expect annotation class Anno(val s: String)
|
||||
|
||||
// FILE: jvm.kt
|
||||
|
||||
import java.lang.reflect.AnnotatedElement
|
||||
|
||||
@Anno("Foo")
|
||||
class Foo @Anno("<init>") constructor(@Anno("x") x: Int) {
|
||||
@Anno("bar")
|
||||
fun bar() {}
|
||||
|
||||
@Anno("getX")
|
||||
var x = x
|
||||
@Anno("setX")
|
||||
set
|
||||
|
||||
@Anno("Nested")
|
||||
interface Nested
|
||||
}
|
||||
|
||||
private fun check(element: AnnotatedElement) {
|
||||
check(element.annotations)
|
||||
}
|
||||
|
||||
private fun check(annotations: Array<Annotation>) {
|
||||
val filtered = annotations.filterNot { it.annotationClass.java.name == "kotlin.Metadata" }
|
||||
if (filtered.isNotEmpty()) {
|
||||
throw AssertionError("Annotations should be empty: $filtered")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val foo = Foo::class.java
|
||||
check(foo)
|
||||
check(Foo.Nested::class.java)
|
||||
check(foo.declaredMethods.single { it.name == "bar" })
|
||||
check(foo.declaredMethods.single { it.name == "getX" })
|
||||
check(foo.declaredMethods.single { it.name == "setX" })
|
||||
check(foo.constructors.single())
|
||||
check(foo.constructors.single().parameterAnnotations.single())
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user