Generate type annotations on class type parameters bounds
#KT-13228 #KT-46539 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
f574f89f78
commit
cd7841ceed
+43
@@ -0,0 +1,43 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// EMIT_JVM_TYPE_ANNOTATIONS
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_REFLECT
|
||||
// FULL_JDK
|
||||
package foo
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.functions
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TypeAnn(val name: String)
|
||||
|
||||
interface SimpleInterface
|
||||
open class SimpleClass
|
||||
|
||||
class InterfaceClassBound<T>() where T : @TypeAnn("Interface") SimpleInterface, T : @TypeAnn("Class") SimpleClass {
|
||||
|
||||
}
|
||||
|
||||
class ClassInterfaceBound<T>() where T : @TypeAnn("Class") SimpleClass, T : @TypeAnn("Interface") SimpleInterface {
|
||||
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
val interfaceBounds = InterfaceClassBound::class.typeParameters.single()
|
||||
if (interfaceBounds.upperBounds[0].annotations.joinToString() != "@foo.TypeAnn(name=Interface)") return "fail 1: ${interfaceBounds.upperBounds[0].annotations.joinToString()}"
|
||||
if ((interfaceBounds.upperBounds[0].classifier as KClass<*>).simpleName != "SimpleInterface") return "fail 1.1: ${interfaceBounds.upperBounds[0].classifier}"
|
||||
|
||||
if (interfaceBounds.upperBounds[1].annotations.joinToString() != "@foo.TypeAnn(name=Class)") return "fail 2: ${interfaceBounds.upperBounds[1].annotations.joinToString()}"
|
||||
if ((interfaceBounds.upperBounds[1].classifier as KClass<*>).simpleName != "SimpleClass") return "fail 2.1: ${interfaceBounds.upperBounds[1].classifier}"
|
||||
|
||||
val classBounds = ClassInterfaceBound::class.typeParameters.single()
|
||||
if (classBounds.upperBounds[0].annotations.joinToString() != "@foo.TypeAnn(name=Class)") return "fail 3: ${classBounds.upperBounds[0].annotations.joinToString()}"
|
||||
if ((classBounds.upperBounds[0].classifier as KClass<*>).simpleName != "SimpleClass") return "fail 3.1: ${classBounds.upperBounds[0].classifier}"
|
||||
|
||||
if (classBounds.upperBounds[1].annotations.joinToString() != "@foo.TypeAnn(name=Interface)") return "fail 4: ${classBounds.upperBounds[1].annotations.joinToString()}"
|
||||
if ((classBounds.upperBounds[1].classifier as KClass<*>).simpleName != "SimpleInterface") return "fail 4.1: ${classBounds.upperBounds[1].classifier}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
// IGNORE_BACKEND: JVM
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
// EMIT_JVM_TYPE_ANNOTATIONS
|
||||
// JVM_TARGET: 1.8
|
||||
// WITH_REFLECT
|
||||
// FULL_JDK
|
||||
package foo
|
||||
|
||||
import java.lang.reflect.AnnotatedType
|
||||
import java.lang.reflect.TypeVariable
|
||||
import java.lang.reflect.AnnotatedParameterizedType
|
||||
import kotlin.reflect.jvm.javaMethod
|
||||
import kotlin.test.fail
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TypeAnn(val name: String)
|
||||
|
||||
@Target(AnnotationTarget.TYPE_PARAMETER)
|
||||
annotation class TypeParameterAnn
|
||||
|
||||
@Target(AnnotationTarget.TYPE_PARAMETER)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class TypeParameterAnnBinary
|
||||
|
||||
interface Simple
|
||||
class SimpleClass
|
||||
interface Generic<G>
|
||||
class GenericClass<G>
|
||||
|
||||
@Suppress("UNSUPPORTED")
|
||||
class SimpleParameter<@TypeParameterAnn @TypeParameterAnnBinary T> {}
|
||||
|
||||
@Suppress("UNSUPPORTED")
|
||||
class InterfaceBound<@TypeParameterAnn T : @TypeAnn("Simple") Simple> {}
|
||||
|
||||
@Suppress("UNSUPPORTED")
|
||||
class ClassBound<@TypeParameterAnn T : @TypeAnn("Simple") SimpleClass>
|
||||
|
||||
class InterfaceBoundGeneric<T : @TypeAnn("Generic") Generic<@TypeAnn("Simple") Simple>> {}
|
||||
|
||||
class ClassBoundGeneric<T : @TypeAnn("GenericClass") GenericClass<@TypeAnn("SimpleClass") SimpleClass>>
|
||||
|
||||
@Suppress("UNSUPPORTED")
|
||||
class TypeParameterAsBound<Y, @TypeParameterAnn T : @TypeAnn("Y as Bound") Y>
|
||||
|
||||
|
||||
fun box(): String {
|
||||
|
||||
//foo
|
||||
// checkTypeParameterAnnotation(
|
||||
// SimpleParameter::class.java.typeParameters.single(),
|
||||
// "T",
|
||||
// "@foo.TypeParameterAnn()",
|
||||
// "foo"
|
||||
// )
|
||||
|
||||
//interfaceBound
|
||||
val interfaceBound = InterfaceBound::class.java
|
||||
// checkTypeParameterAnnotation(
|
||||
// InterfaceBound.typeParameters.single(),
|
||||
// "T",
|
||||
// "@foo.TypeParameterAnn()",
|
||||
// "interfaceBound type parameter"
|
||||
// )
|
||||
|
||||
checkTypeAnnotation(
|
||||
interfaceBound.typeParameters.single().annotatedBounds.single(),
|
||||
"interface foo.Simple",
|
||||
"@foo.TypeAnn(name=Simple)",
|
||||
"interfaceBound bound"
|
||||
)
|
||||
|
||||
//classBound
|
||||
val classBound = ClassBound::class.java
|
||||
// checkTypeParameterAnnotation(
|
||||
// classBound.typeParameters.single(),
|
||||
// "T",
|
||||
// "@foo.TypeParameterAnn()",
|
||||
// "classBound type parameter"
|
||||
// )
|
||||
|
||||
checkTypeAnnotation(
|
||||
classBound.typeParameters.single().annotatedBounds.single(),
|
||||
"class foo.SimpleClass",
|
||||
"@foo.TypeAnn(name=Simple)",
|
||||
"classBound bound"
|
||||
)
|
||||
|
||||
|
||||
//interfaceBoundGeneric
|
||||
val interfaceBoundGeneric = InterfaceBoundGeneric::class.java
|
||||
// checkTypeAnnotation(
|
||||
// interfaceBoundGeneric.typeParameters.single().annotatedBounds.single(),
|
||||
// "foo.Generic<foo.Simple>",
|
||||
// "@foo.TypeAnn(name=Generic)",
|
||||
// "interfaceBoundGeneric bound"
|
||||
// )
|
||||
|
||||
checkTypeAnnotation(
|
||||
(interfaceBoundGeneric.typeParameters.single().annotatedBounds.single() as AnnotatedParameterizedType).getAnnotatedActualTypeArguments().single(),
|
||||
"interface foo.Simple",
|
||||
"@foo.TypeAnn(name=Simple)",
|
||||
"interfaceBoundGeneric bound parameter"
|
||||
)
|
||||
|
||||
//classBoundGeneric
|
||||
val classBoundGeneric = ClassBoundGeneric::class.java
|
||||
// Works on JDK 15
|
||||
// checkTypeAnnotation(
|
||||
// classBoundGeneric.typeParameters.single().annotatedBounds.single(),
|
||||
// "foo.GenericClass<foo.SimpleClass>",
|
||||
// "@foo.TypeAnn(name=GenericClass)",
|
||||
// "classBoundGeneric bound"
|
||||
// )
|
||||
|
||||
checkTypeAnnotation(
|
||||
(classBoundGeneric.typeParameters.single().annotatedBounds.single() as AnnotatedParameterizedType).getAnnotatedActualTypeArguments().single(),
|
||||
"class foo.SimpleClass",
|
||||
"@foo.TypeAnn(name=SimpleClass)",
|
||||
"classBoundGeneric bound parameter"
|
||||
)
|
||||
|
||||
//typeParameterTypeParameterBound
|
||||
val typeParameterTypeParameterBound = TypeParameterAsBound::class.java
|
||||
// checkTypeParameterAnnotation(
|
||||
// typeParameterTypeParameterBound.typeParameters[1]!!,
|
||||
// "T",
|
||||
// "@foo.TypeParameterAnn()",
|
||||
// "typeParameterTypeParameterBound type parameter"
|
||||
// )
|
||||
// Works on JDK 15
|
||||
// checkTypeAnnotation(
|
||||
// typeParameterTypeParameterBound.typeParameters[1]!!.annotatedBounds.single(),
|
||||
// "Y",
|
||||
// "@foo.TypeAnn(name=Y as Bound)",
|
||||
// "typeParameterTypeParameterBound bound"
|
||||
// )
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
fun checkTypeParameterAnnotation(
|
||||
typeParameter: TypeVariable<*>,
|
||||
type: String,
|
||||
annotations: String,
|
||||
message: String
|
||||
) {
|
||||
if (typeParameter.annotation() != annotations) fail("check $message (1): ${typeParameter.annotation()} != $annotations")
|
||||
|
||||
if (typeParameter.toString() != type) fail("check $message (2): ${typeParameter.toString()} != $type")
|
||||
}
|
||||
|
||||
|
||||
fun checkTypeAnnotation(
|
||||
annotatedType: AnnotatedType,
|
||||
type: String,
|
||||
annotations: String,
|
||||
message: String
|
||||
) {
|
||||
if (annotatedType.annotation() != annotations &&
|
||||
//JDK11+
|
||||
annotatedType . annotation () != annotations.replace("=", "=\"").replace(")", "\")")
|
||||
) fail("check $message (1): ${annotatedType.annotation()} != $annotations")
|
||||
|
||||
if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type")
|
||||
}
|
||||
|
||||
|
||||
fun AnnotatedType.annotation() = annotations.joinToString()
|
||||
|
||||
fun TypeVariable<*>.annotation() = annotations.joinToString()
|
||||
Reference in New Issue
Block a user