Support KClass<*> annotation arguments in serialization/deserialization
#KT-11586 Fixed
This commit is contained in:
+1
-1
@@ -741,7 +741,7 @@ private class ConstantExpressionEvaluatorVisitor(
|
|||||||
override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, expectedType: KotlinType?): CompileTimeConstant<*>? {
|
override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, expectedType: KotlinType?): CompileTimeConstant<*>? {
|
||||||
val type = trace.getType(expression)!!
|
val type = trace.getType(expression)!!
|
||||||
if (type.isError) return null
|
if (type.isError) return null
|
||||||
return KClassValue(type).wrap()
|
return factory.createKClassValue(type).wrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveArguments(valueArguments: List<ValueArgument>, expectedType: KotlinType): List<CompileTimeConstant<*>?> {
|
private fun resolveArguments(valueArguments: List<ValueArgument>, expectedType: KotlinType): List<CompileTimeConstant<*>?> {
|
||||||
|
|||||||
+6
-3
@@ -97,9 +97,12 @@ class AnnotationSerializer(private val stringTable: StringTable) {
|
|||||||
intValue = value.value.toLong()
|
intValue = value.value.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitKClassValue(value: KClassValue?, data: Unit?) {
|
override fun visitKClassValue(value: KClassValue, data: Unit) {
|
||||||
// TODO: support class literals
|
val descriptor = value.value.constructor.declarationDescriptor as? ClassDescriptor
|
||||||
throw UnsupportedOperationException("Class literal annotation arguments are not yet supported: $value")
|
?: throw UnsupportedOperationException("Class literal annotation argument should be a class: $value")
|
||||||
|
|
||||||
|
type = Type.CLASS
|
||||||
|
classId = stringTable.getFqNameIndex(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLongValue(value: LongValue, data: Unit) {
|
override fun visitLongValue(value: LongValue, data: Unit) {
|
||||||
|
|||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
// ALLOW_AST_ACCESS
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.TYPE)
|
||||||
|
annotation class Ann(val klass: KClass<*>)
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun simple(s: @Ann(Simple::class) String) {}
|
||||||
|
fun generic(s: @Ann(Generic::class) String) {}
|
||||||
|
fun innerGeneric(s: @Ann(InnerGeneric.Inner::class) String) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Simple
|
||||||
|
class Generic<T>
|
||||||
|
class InnerGeneric<A, B> {
|
||||||
|
inner class Inner<in C, D : A>
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
public final class A {
|
||||||
|
/*primary*/ public constructor A()
|
||||||
|
public final fun generic(/*0*/ s: @test.Ann(klass = test.Generic<*>::class) kotlin.String): kotlin.Unit
|
||||||
|
public final fun innerGeneric(/*0*/ s: @test.Ann(klass = test.InnerGeneric<*, *>.Inner<*, *>::class) kotlin.String): kotlin.Unit
|
||||||
|
public final fun simple(/*0*/ s: @test.Ann(klass = test.Simple::class) kotlin.String): kotlin.Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) public final annotation class Ann : kotlin.Annotation {
|
||||||
|
/*primary*/ public constructor Ann(/*0*/ klass: kotlin.reflect.KClass<*>)
|
||||||
|
public final val klass: kotlin.reflect.KClass<*>
|
||||||
|
public final fun <get-klass>(): kotlin.reflect.KClass<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Generic</*0*/ T> {
|
||||||
|
/*primary*/ public constructor Generic</*0*/ T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class InnerGeneric</*0*/ A, /*1*/ B> {
|
||||||
|
/*primary*/ public constructor InnerGeneric</*0*/ A, /*1*/ B>()
|
||||||
|
|
||||||
|
public final inner class Inner</*0*/ in C, /*1*/ D : A> /*captured type parameters: /*2*/ A, /*3*/ B*/ {
|
||||||
|
/*primary*/ public constructor Inner</*0*/ in C, /*1*/ D : A>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Simple {
|
||||||
|
/*primary*/ public constructor Simple()
|
||||||
|
}
|
||||||
@@ -2250,6 +2250,12 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassLiteralArgument.kt")
|
||||||
|
public void testClassLiteralArgument() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.kt");
|
||||||
|
doTestCompiledKotlin(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ReceiverParameter.kt")
|
@TestMetadata("ReceiverParameter.kt")
|
||||||
public void testReceiverParameter() throws Exception {
|
public void testReceiverParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
||||||
|
|||||||
+6
@@ -457,6 +457,12 @@ public class LoadKotlinWithTypeTableTestGenerated extends AbstractLoadKotlinWith
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassLiteralArgument.kt")
|
||||||
|
public void testClassLiteralArgument() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ReceiverParameter.kt")
|
@TestMetadata("ReceiverParameter.kt")
|
||||||
public void testReceiverParameter() throws Exception {
|
public void testReceiverParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
||||||
|
|||||||
+6
@@ -2250,6 +2250,12 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassLiteralArgument.kt")
|
||||||
|
public void testClassLiteralArgument() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.kt");
|
||||||
|
doTestCompiledKotlin(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ReceiverParameter.kt")
|
@TestMetadata("ReceiverParameter.kt")
|
||||||
public void testReceiverParameter() throws Exception {
|
public void testReceiverParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
||||||
|
|||||||
+6
@@ -459,6 +459,12 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassLiteralArgument.kt")
|
||||||
|
public void testClassLiteralArgument() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ReceiverParameter.kt")
|
@TestMetadata("ReceiverParameter.kt")
|
||||||
public void testReceiverParameter() throws Exception {
|
public void testReceiverParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
||||||
|
|||||||
+13
-6
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -31,11 +32,9 @@ import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation
|
|||||||
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument.Value
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument.Value
|
||||||
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument.Value.Type
|
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument.Value.Type
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.SimpleType
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||||
|
|
||||||
class AnnotationDeserializer(private val module: ModuleDescriptor, private val notFoundClasses: NotFoundClasses) {
|
class AnnotationDeserializer(private val module: ModuleDescriptor, private val notFoundClasses: NotFoundClasses) {
|
||||||
private val builtIns: KotlinBuiltIns
|
private val builtIns: KotlinBuiltIns
|
||||||
@@ -85,8 +84,7 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n
|
|||||||
factory.createStringValue(nameResolver.getString(value.stringValue))
|
factory.createStringValue(nameResolver.getString(value.stringValue))
|
||||||
}
|
}
|
||||||
Type.CLASS -> {
|
Type.CLASS -> {
|
||||||
// TODO: support class literals
|
resolveClassLiteralValue(nameResolver.getClassId(value.classId))
|
||||||
error("Class literal annotation arguments are not supported yet (${nameResolver.getClassId(value.classId)})")
|
|
||||||
}
|
}
|
||||||
Type.ENUM -> {
|
Type.ENUM -> {
|
||||||
resolveEnumValue(nameResolver.getClassId(value.classId), nameResolver.getName(value.enumValueId))
|
resolveEnumValue(nameResolver.getClassId(value.classId), nameResolver.getName(value.enumValueId))
|
||||||
@@ -132,6 +130,15 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun resolveClassLiteralValue(classId: ClassId): ConstantValue<*> {
|
||||||
|
// If value refers to a class named test.Foo.Bar where both Foo and Bar have generic type parameters,
|
||||||
|
// we're constructing a type `KClass<test.Foo<*>.Bar<*>>` below
|
||||||
|
val starProjectedType = resolveClass(classId).defaultType.replaceArgumentsWithStarProjections()
|
||||||
|
val kClass = resolveClass(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.kClass.toSafe()))
|
||||||
|
val type = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, kClass, listOf(TypeProjectionImpl(starProjectedType)))
|
||||||
|
return factory.createKClassValue(type)
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: see analogous code in BinaryClassAnnotationAndConstantLoaderImpl
|
// NOTE: see analogous code in BinaryClassAnnotationAndConstantLoaderImpl
|
||||||
private fun resolveEnumValue(enumClassId: ClassId, enumEntryName: Name): ConstantValue<*> {
|
private fun resolveEnumValue(enumClassId: ClassId, enumEntryName: Name): ConstantValue<*> {
|
||||||
val enumClass = resolveClass(enumClassId)
|
val enumClass = resolveClass(enumClassId)
|
||||||
|
|||||||
+6
@@ -457,6 +457,12 @@ public class LoadJavaClsStubTestGenerated extends AbstractLoadJavaClsStubTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassLiteralArgument.kt")
|
||||||
|
public void testClassLiteralArgument() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.kt");
|
||||||
|
doTestCompiledKotlin(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ReceiverParameter.kt")
|
@TestMetadata("ReceiverParameter.kt")
|
||||||
public void testReceiverParameter() throws Exception {
|
public void testReceiverParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
||||||
|
|||||||
@@ -457,6 +457,12 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlin/annotations/types"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassLiteralArgument.kt")
|
||||||
|
public void testClassLiteralArgument() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ReceiverParameter.kt")
|
@TestMetadata("ReceiverParameter.kt")
|
||||||
public void testReceiverParameter() throws Exception {
|
public void testReceiverParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/types/ReceiverParameter.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user