Refactor KClassValue to store ClassLiteralValue internally

Only invariant array projections and non-null element types will be
supported soon (see KT-26568), so it makes no sense to store the
complete type in KClassValue. What we need is only the ClassId of the
class, and the number of times it's wrapped into kotlin/Array, which is
exactly what ClassLiteralValue represents.

This change helps in decoupling annotation values from
descriptors/types. The only constant value that depends on descriptors
is now AnnotationValue.

 #KT-26582 Fixed
This commit is contained in:
Alexander Udalov
2018-09-05 13:22:28 +03:00
parent bad30a4b99
commit c1ab08c8ce
23 changed files with 131 additions and 124 deletions
@@ -439,7 +439,7 @@ public abstract class AnnotationCodegen {
@Override @Override
public Void visitKClassValue(KClassValue value, Void data) { public Void visitKClassValue(KClassValue value, Void data) {
annotationVisitor.visit(name, typeMapper.mapType(value.getValue())); annotationVisitor.visit(name, typeMapper.mapType(value.getArgumentType(module)));
return null; return null;
} }
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
import org.jetbrains.kotlin.resolve.constants.ArrayValue; import org.jetbrains.kotlin.resolve.constants.ArrayValue;
import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.constants.KClassValue; import org.jetbrains.kotlin.resolve.constants.KClassValue;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.inline.InlineUtil; import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo; import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
@@ -1111,7 +1112,7 @@ public class FunctionCodegen {
} }
@NotNull @NotNull
public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull KotlinTypeMapper mapper) { public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull KotlinTypeMapper typeMapper) {
AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws")); AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws"));
if (annotation == null) { if (annotation == null) {
annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws")); annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws"));
@@ -1130,9 +1131,10 @@ public class FunctionCodegen {
arrayValue.getValue(), arrayValue.getValue(),
(ConstantValue<?> constant) -> { (ConstantValue<?> constant) -> {
if (constant instanceof KClassValue) { if (constant instanceof KClassValue) {
KClassValue classValue = (KClassValue) constant; ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(
ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue()); ((KClassValue) constant).getArgumentType(DescriptorUtilsKt.getModule(function))
return mapper.mapClass(classDescriptor).getInternalName(); );
return typeMapper.mapClass(classDescriptor).getInternalName();
} }
return null; return null;
} }
@@ -287,6 +287,10 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
String elementDesc = nestedness == 0 ? typeDesc : type.getElementType().getDescriptor(); String elementDesc = nestedness == 0 ? typeDesc : type.getElementType().getDescriptor();
JvmPrimitiveType primType = JvmPrimitiveType.getByDesc(elementDesc); JvmPrimitiveType primType = JvmPrimitiveType.getByDesc(elementDesc);
if (primType != null) { if (primType != null) {
if (nestedness > 0) {
// "int[][]" should be loaded as "Array<IntArray>", not as "Array<Array<Int>>"
return new ClassLiteralValue(ClassId.topLevel(primType.getPrimitiveType().getArrayTypeFqName()), nestedness - 1);
}
return new ClassLiteralValue(ClassId.topLevel(primType.getPrimitiveType().getTypeFqName()), nestedness); return new ClassLiteralValue(ClassId.topLevel(primType.getPrimitiveType().getTypeFqName()), nestedness);
} }
ClassId javaClassId = resolveNameByDesc(elementDesc, innerClasses); ClassId javaClassId = resolveNameByDesc(elementDesc, innerClasses);
@@ -53,7 +53,8 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD
for (annotationClass in annotationClasses) { for (annotationClass in annotationClasses) {
val classDescriptor = val classDescriptor =
(annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor as? ClassDescriptor ?: continue (annotationClass as? KClassValue)?.getArgumentType(module)?.constructor?.declarationDescriptor as? ClassDescriptor
?: continue
val experimentality = with(ExperimentalUsageChecker) { val experimentality = with(ExperimentalUsageChecker) {
classDescriptor.loadExperimentalityForMarkerAnnotation() classDescriptor.loadExperimentalityForMarkerAnnotation()
} }
@@ -189,7 +189,9 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
if (descriptor?.fqName == USE_EXPERIMENTAL_FQ_NAME) { if (descriptor?.fqName == USE_EXPERIMENTAL_FQ_NAME) {
val annotationClasses = descriptor.allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS] val annotationClasses = descriptor.allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS]
annotationClasses is ArrayValue && annotationClasses.value.any { annotationClass -> annotationClasses is ArrayValue && annotationClasses.value.any { annotationClass ->
(annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor?.fqNameSafe == annotationFqName annotationClass is KClassValue && annotationClass.value.let { (classId, arrayDimensions) ->
classId.asSingleFqName() == annotationFqName && arrayDimensions == 0
}
} }
} else false } else false
} }
@@ -888,7 +888,9 @@ 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() val descriptor = type.constructor.declarationDescriptor
if (descriptor !is ClassDescriptor || !KotlinBuiltIns.isKClass(descriptor)) return null
return KClassValue.create(type.arguments.first().type)?.wrap()
} }
private fun resolveArguments(valueArguments: List<ValueArgument>, expectedType: KotlinType): List<CompileTimeConstant<*>?> { private fun resolveArguments(valueArguments: List<ValueArgument>, expectedType: KotlinType): List<CompileTimeConstant<*>?> {
@@ -8,12 +8,12 @@ package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.KClassValue import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.resolve.descriptorUtil.module
sealed class SinceKotlinAccessibility { sealed class SinceKotlinAccessibility {
object Accessible : SinceKotlinAccessibility() object Accessible : SinceKotlinAccessibility()
@@ -102,13 +102,13 @@ private fun DeclarationDescriptor.getOwnSinceKotlinVersion(): SinceKotlinValue?
return result return result
} }
private fun Annotated.loadWasExperimentalMarkerClasses(): List<ClassDescriptor> { private fun DeclarationDescriptor.loadWasExperimentalMarkerClasses(): List<ClassDescriptor> {
val wasExperimental = annotations.findAnnotation(ExperimentalUsageChecker.WAS_EXPERIMENTAL_FQ_NAME) val wasExperimental = annotations.findAnnotation(ExperimentalUsageChecker.WAS_EXPERIMENTAL_FQ_NAME)
if (wasExperimental != null) { if (wasExperimental != null) {
val annotationClasses = wasExperimental.allValueArguments[ExperimentalUsageChecker.WAS_EXPERIMENTAL_ANNOTATION_CLASS] val annotationClasses = wasExperimental.allValueArguments[ExperimentalUsageChecker.WAS_EXPERIMENTAL_ANNOTATION_CLASS]
if (annotationClasses is ArrayValue) { if (annotationClasses is ArrayValue) {
return annotationClasses.value.mapNotNull { annotationClass -> return annotationClasses.value.mapNotNull { annotationClass ->
(annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor as? ClassDescriptor (annotationClass as? KClassValue)?.getArgumentType(module)?.constructor?.declarationDescriptor as? ClassDescriptor
} }
} }
} }
@@ -85,7 +85,7 @@ class ConstantValueGenerator(
is AnnotationValue -> generateAnnotationConstructorCall(constantValue.value) is AnnotationValue -> generateAnnotationConstructorCall(constantValue.value)
is KClassValue -> { is KClassValue -> {
val classifierKtType = constantValue.value val classifierKtType = constantValue.getArgumentType(moduleDescriptor)
val classifierDescriptor = classifierKtType.constructor.declarationDescriptor val classifierDescriptor = classifierKtType.constructor.declarationDescriptor
?: throw AssertionError("Unexpected KClassValue: $classifierKtType") ?: throw AssertionError("Unexpected KClassValue: $classifierKtType")
@@ -16,8 +16,6 @@
package org.jetbrains.kotlin.serialization package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
@@ -100,22 +98,11 @@ class AnnotationSerializer(private val stringTable: DescriptorAwareStringTable)
} }
override fun visitKClassValue(value: KClassValue, data: Unit) { override fun visitKClassValue(value: KClassValue, data: Unit) {
var kotlinType = value.value
var arrayDimensions = 0
while (KotlinBuiltIns.isArray(kotlinType)) {
// We only support invariant projections and non-null array element types, see KT-26568
kotlinType = kotlinType.arguments.single().type
arrayDimensions++
}
val descriptor = kotlinType.constructor.declarationDescriptor as? ClassDescriptor
?: throw UnsupportedOperationException("Class literal annotation argument should be a class: $value")
type = Type.CLASS type = Type.CLASS
classId = stringTable.getFqNameIndex(descriptor) classId = stringTable.getQualifiedClassNameIndex(value.classId)
if (arrayDimensions > 0) { if (value.arrayDimensions > 0) {
arrayDimensionCount = arrayDimensions arrayDimensionCount = value.arrayDimensions
} }
} }
@@ -27,6 +27,7 @@ annotation class Anno(
val za: BooleanArray, val za: BooleanArray,
val str: String, val str: String,
val k: KClass<*>, val k: KClass<*>,
val k2: KClass<*>,
val e: AnnotationTarget, val e: AnnotationTarget,
val a: Nested, val a: Nested,
val stra: Array<String>, val stra: Array<String>,
@@ -54,10 +55,11 @@ fun f(): @Anno(
[false, true], [false, true],
"lol", "lol",
Number::class, Number::class,
IntArray::class,
AnnotationTarget.EXPRESSION, AnnotationTarget.EXPRESSION,
Nested("1"), Nested("1"),
["lmao"], ["lmao"],
// [Double::class, Unit::class], // [Double::class, Unit::class, LongArray::class],
[AnnotationTarget.TYPEALIAS, AnnotationTarget.FIELD], [AnnotationTarget.TYPEALIAS, AnnotationTarget.FIELD],
[Nested("2"), Nested("3")] [Nested("2"), Nested("3")]
) Unit {} ) Unit {}
@@ -66,7 +68,7 @@ fun box(): String {
assertEquals( assertEquals(
"[@Anno(b=1, c=x, d=3.14, f=-2.72, i=42424242, j=239239239239239, s=42, z=true, " + "[@Anno(b=1, c=x, d=3.14, f=-2.72, i=42424242, j=239239239239239, s=42, z=true, " +
"ba=[-1], ca=[y], da=[-3.14159], fa=[2.7218], ia=[424242], ja=[239239239239], sa=[-43], za=[false, true], " + "ba=[-1], ca=[y], da=[-3.14159], fa=[2.7218], ia=[424242], ja=[239239239239], sa=[-43], za=[false, true], " +
"str=lol, k=class java.lang.Number, e=EXPRESSION, a=@Nested(value=1), " + "str=lol, k=class java.lang.Number, k2=class [I, e=EXPRESSION, a=@Nested(value=1), " +
"stra=[lmao], ea=[TYPEALIAS, FIELD], aa=[@Nested(value=2), @Nested(value=3)])]", "stra=[lmao], ea=[TYPEALIAS, FIELD], aa=[@Nested(value=2), @Nested(value=3)])]",
::f.returnType.annotations.toString() ::f.returnType.annotations.toString()
) )
@@ -2,8 +2,8 @@ package
@Foo(a = {}) public fun test1(): kotlin.Unit @Foo(a = {}) public fun test1(): kotlin.Unit
@Foo(a = {kotlin.Int::class, kotlin.String::class}) public fun test2(): kotlin.Unit @Foo(a = {kotlin.Int::class, kotlin.String::class}) public fun test2(): kotlin.Unit
@Foo(a = {kotlin.Array<*>::class}) public fun test3(): kotlin.Unit @Foo(a = {kotlin.Array<kotlin.Any>::class}) public fun test3(): kotlin.Unit
@Foo(a = {Gen<kotlin.Int>::class}) public fun test4(): kotlin.Unit @Foo(a = {Gen::class}) public fun test4(): kotlin.Unit
@Foo(a = {""}) public fun test5(): kotlin.Unit @Foo(a = {""}) public fun test5(): kotlin.Unit
@Foo(a = {kotlin.Int::class, 1}) public fun test6(): kotlin.Unit @Foo(a = {kotlin.Int::class, 1}) public fun test6(): kotlin.Unit
@Bar public fun test7(): kotlin.Unit @Bar public fun test7(): kotlin.Unit
@@ -8,7 +8,7 @@ public open class ClassObjectArrayInParam {
public final val value: kotlin.Array<kotlin.reflect.KClass<*>> public final val value: kotlin.Array<kotlin.reflect.KClass<*>>
} }
@test.ClassObjectArrayInParam.Anno(value = {test.ClassObjectArrayInParam::class, test.ClassObjectArrayInParam.Nested::class, kotlin.String::class, kotlin.collections.(Mutable)List<(raw) kotlin.Any?>::class, kotlin.Array<(out) kotlin.Array<(out) kotlin.String!>!>::class, kotlin.Array<(out) kotlin.IntArray!>::class}) public open class Nested { @test.ClassObjectArrayInParam.Anno(value = {test.ClassObjectArrayInParam::class, test.ClassObjectArrayInParam.Nested::class, kotlin.String::class, kotlin.collections.MutableList::class, kotlin.Array<kotlin.Array<kotlin.String>>::class, kotlin.Array<kotlin.IntArray>::class}) public open class Nested {
public constructor Nested() public constructor Nested()
} }
} }
@@ -3,8 +3,8 @@ package test
public final class A { public final class A {
/*primary*/ public constructor A() /*primary*/ public constructor A()
public final fun arrays(/*0*/ s: @test.Ann(klass = kotlin.Array<kotlin.Int>::class) kotlin.Array<kotlin.Int>, /*1*/ t: @test.Ann(klass = kotlin.Array<kotlin.IntArray>::class) kotlin.Array<kotlin.IntArray>, /*2*/ u: @test.Ann(klass = kotlin.Array<kotlin.Array<kotlin.Int>>::class) kotlin.Array<kotlin.Array<kotlin.Int>>, /*3*/ v: @test.Ann(klass = kotlin.Array<kotlin.Array<kotlin.Array<kotlin.String>>>::class) kotlin.Array<kotlin.Array<kotlin.Array<kotlin.String>>>): kotlin.Unit public final fun arrays(/*0*/ s: @test.Ann(klass = kotlin.Array<kotlin.Int>::class) kotlin.Array<kotlin.Int>, /*1*/ t: @test.Ann(klass = kotlin.Array<kotlin.IntArray>::class) kotlin.Array<kotlin.IntArray>, /*2*/ u: @test.Ann(klass = kotlin.Array<kotlin.Array<kotlin.Int>>::class) kotlin.Array<kotlin.Array<kotlin.Int>>, /*3*/ v: @test.Ann(klass = kotlin.Array<kotlin.Array<kotlin.Array<kotlin.String>>>::class) kotlin.Array<kotlin.Array<kotlin.Array<kotlin.String>>>): kotlin.Unit
public final fun generic(/*0*/ s: @test.Ann(klass = test.Generic<*>::class) kotlin.String): kotlin.Unit 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 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 public final fun simple(/*0*/ s: @test.Ann(klass = test.Simple::class) kotlin.String): kotlin.Unit
} }
@@ -87,7 +87,7 @@ public class AnnotationDescriptorResolveTest extends AbstractAnnotationDescripto
public void testJavaClassAnnotation() throws Exception { public void testJavaClassAnnotation() throws Exception {
String content = getContent("AnnClass(MyClass::class)"); String content = getContent("AnnClass(MyClass::class)");
String expectedAnnotation = "@AnnClass(a = MyClass::class)"; String expectedAnnotation = "@AnnClass(a = test.MyClass::class)";
doTest(content, expectedAnnotation); doTest(content, expectedAnnotation);
} }
} }
@@ -18,9 +18,7 @@ package org.jetbrains.kotlin.load.java.lazy.descriptors
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.findNonGenericClassAcrossDependencies import org.jetbrains.kotlin.descriptors.findNonGenericClassAcrossDependencies
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.java.components.TypeUsage import org.jetbrains.kotlin.load.java.components.TypeUsage
@@ -33,9 +31,10 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.isError
class LazyJavaAnnotationDescriptor( class LazyJavaAnnotationDescriptor(
private val c: LazyJavaResolverContext, private val c: LazyJavaResolverContext,
@@ -101,21 +100,8 @@ class LazyJavaAnnotationDescriptor(
return EnumValue(enumClassId, entryName) return EnumValue(enumClassId, entryName)
} }
private fun resolveFromJavaClassObjectType(javaType: JavaType): ConstantValue<*>? { private fun resolveFromJavaClassObjectType(javaType: JavaType): ConstantValue<*>? =
// Class type is never nullable in 'Foo.class' in Java KClassValue.create(c.typeResolver.transformJavaType(javaType, TypeUsage.COMMON.toAttributes()))
val type = TypeUtils.makeNotNullable(c.typeResolver.transformJavaType(
javaType,
TypeUsage.COMMON.toAttributes())
)
val jlClass = c.module.resolveTopLevelClass(FqName("java.lang.Class"), NoLookupLocation.FOR_NON_TRACKED_SCOPE) ?: return null
val arguments = listOf(TypeProjectionImpl(type))
val javaClassObjectType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, jlClass, arguments)
return KClassValue(javaClassObjectType)
}
override fun toString(): String { override fun toString(): String {
return DescriptorRenderer.FQ_NAMES_IN_TYPES.renderAnnotation(this) return DescriptorRenderer.FQ_NAMES_IN_TYPES.renderAnnotation(this)
@@ -16,11 +16,9 @@
package org.jetbrains.kotlin.load.kotlin package org.jetbrains.kotlin.load.kotlin
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.load.java.components.DescriptorResolverUtils import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
@@ -30,9 +28,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.serialization.deserialization.AnnotationDeserializer import org.jetbrains.kotlin.serialization.deserialization.AnnotationDeserializer
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.compact import org.jetbrains.kotlin.utils.compact
import java.util.* import java.util.*
@@ -94,8 +89,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
} }
override fun visitClassLiteral(name: Name, value: ClassLiteralValue) { override fun visitClassLiteral(name: Name, value: ClassLiteralValue) {
arguments[name] = value.toClassValue() ?: arguments[name] = KClassValue(value)
ErrorValue.create("Error value of annotation argument: $name: class ${value.classId.asSingleFqName()} not found")
} }
override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) { override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) {
@@ -115,11 +109,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
} }
override fun visitClassLiteral(value: ClassLiteralValue) { override fun visitClassLiteral(value: ClassLiteralValue) {
elements.add( elements.add(KClassValue(value))
value.toClassValue() ?: ErrorValue.create(
"Error array element value of annotation argument: $name: class ${value.classId.asSingleFqName()} not found"
)
)
} }
override fun visitEnd() { override fun visitEnd() {
@@ -153,21 +143,6 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
} }
} }
private fun ClassLiteralValue.toClassValue(): KClassValue? =
module.findClassAcrossModuleDependencies(classId)?.let { classDescriptor ->
var currentType = classDescriptor.defaultType
for (i in 0 until arrayNestedness) {
val nextWrappedType =
(if (i == 0) module.builtIns.getPrimitiveArrayKotlinTypeByPrimitiveKotlinType(currentType) else null)
?: module.builtIns.getArrayType(Variance.INVARIANT, currentType)
currentType = nextWrappedType
}
val kClass = resolveClass(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.kClass.toSafe()))
val arguments = listOf(TypeProjectionImpl(currentType))
val type = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, kClass, arguments)
KClassValue(type)
}
private fun resolveClass(classId: ClassId): ClassDescriptor { private fun resolveClass(classId: ClassId): ClassDescriptor {
return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses) return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses)
} }
@@ -607,6 +607,11 @@ public abstract class KotlinBuiltIns {
return getBuiltInClassByName("Annotation"); return getBuiltInClassByName("Annotation");
} }
@NotNull
public ClassDescriptor getKClass() {
return getBuiltInClassByFqName(FQ_NAMES.kClass.toSafe());
}
@NotNull @NotNull
private ClassDescriptor getCollectionClassByName(@NotNull String simpleName) { private ClassDescriptor getCollectionClassByName(@NotNull String simpleName) {
return getBuiltInClassByName(simpleName, packageFragments.invoke().collectionsPackageFragment); return getBuiltInClassByName(simpleName, packageFragments.invoke().collectionsPackageFragment);
@@ -458,7 +458,11 @@ internal class DescriptorRendererImpl(
return when (value) { return when (value) {
is ArrayValue -> value.value.joinToString(", ", "{", "}") { renderConstant(it) } is ArrayValue -> value.value.joinToString(", ", "{", "}") { renderConstant(it) }
is AnnotationValue -> renderAnnotation(value.value).removePrefix("@") is AnnotationValue -> renderAnnotation(value.value).removePrefix("@")
is KClassValue -> renderType(value.value) + "::class" is KClassValue -> {
var type = value.classId.asSingleFqName().asString()
repeat(value.arrayDimensions) { type = "kotlin.Array<$type>" }
"$type::class"
}
else -> value.toString() else -> value.toString()
} }
} }
@@ -17,15 +17,18 @@
package org.jetbrains.kotlin.resolve.constants package org.jetbrains.kotlin.resolve.constants
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
abstract class ConstantValue<out T>(open val value: T) { abstract class ConstantValue<out T>(open val value: T) {
abstract fun getType(module: ModuleDescriptor): KotlinType abstract fun getType(module: ModuleDescriptor): KotlinType
@@ -154,13 +157,47 @@ class IntValue(value: Int) : IntegerValueConstant<Int>(value) {
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitIntValue(this, data) override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitIntValue(this, data)
} }
class KClassValue(private val type: KotlinType) : ConstantValue<KotlinType>(type) { class KClassValue(value: ClassLiteralValue) : ConstantValue<ClassLiteralValue>(value) {
override fun getType(module: ModuleDescriptor): KotlinType = type val classId: ClassId get() = value.classId
val arrayDimensions: Int get() = value.arrayNestedness
override val value: KotlinType constructor(classId: ClassId, arrayDimensions: Int) : this(ClassLiteralValue(classId, arrayDimensions))
get() = type.arguments.single().type
override fun getType(module: ModuleDescriptor): KotlinType =
KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, module.builtIns.kClass, listOf(TypeProjectionImpl(getArgumentType(module))))
fun getArgumentType(module: ModuleDescriptor): KotlinType {
val descriptor = module.findClassAcrossModuleDependencies(classId)
?: return ErrorUtils.createErrorType("Unresolved type: $classId (arrayDimensions=$arrayDimensions)")
// If this value refers to a class named test.Foo.Bar where both Foo and Bar have generic type parameters,
// we're constructing a type `test.Foo<*>.Bar<*>` below
var type = descriptor.defaultType.replaceArgumentsWithStarProjections()
repeat(arrayDimensions) {
type = module.builtIns.getArrayType(Variance.INVARIANT, type)
}
return type
}
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitKClassValue(this, data) override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitKClassValue(this, data)
companion object {
fun create(argumentType: KotlinType): ConstantValue<*>? {
if (argumentType.isError) return null
var type = argumentType
var arrayDimensions = 0
while (KotlinBuiltIns.isArray(type)) {
type = type.arguments.single().type
arrayDimensions++
}
val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
val classId = descriptor.classId ?: return null
return KClassValue(classId, arrayDimensions)
}
}
} }
class LongValue(value: Long) : IntegerValueConstant<Long>(value) { class LongValue(value: Long) : IntegerValueConstant<Long>(value) {
@@ -20,7 +20,6 @@ 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.metadata.ProtoBuf.Annotation import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation
import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument
import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value
@@ -31,9 +30,11 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.ErrorUtils
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
@@ -79,7 +80,7 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n
StringValue(nameResolver.getString(value.stringValue)) StringValue(nameResolver.getString(value.stringValue))
} }
Type.CLASS -> { Type.CLASS -> {
resolveClassLiteralValue(nameResolver.getClassId(value.classId), value.arrayDimensionCount) KClassValue(nameResolver.getClassId(value.classId), value.arrayDimensionCount)
} }
Type.ENUM -> { Type.ENUM -> {
EnumValue(nameResolver.getClassId(value.classId), nameResolver.getName(value.enumValueId)) EnumValue(nameResolver.getClassId(value.classId), nameResolver.getName(value.enumValueId))
@@ -128,19 +129,6 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n
private inline fun <T, R> T.letIf(predicate: Boolean, f: (T) -> R, g: (T) -> R): R = private inline fun <T, R> T.letIf(predicate: Boolean, f: (T) -> R, g: (T) -> R): R =
if (predicate) f(this) else g(this) if (predicate) f(this) else g(this)
private fun resolveClassLiteralValue(classId: ClassId, arrayDimensions: Int): 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
var type = resolveClass(classId).defaultType.replaceArgumentsWithStarProjections()
repeat(arrayDimensions) {
// We only support invariant projections and non-null array element types, see KT-26568
type = builtIns.getArrayType(Variance.INVARIANT, type)
}
val kClass = resolveClass(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.kClass.toSafe()))
return KClassValue(KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, kClass, listOf(TypeProjectionImpl(type))))
}
private fun resolveArrayElementType(value: Value, nameResolver: NameResolver): SimpleType = private fun resolveArrayElementType(value: Value, nameResolver: NameResolver): SimpleType =
with(builtIns) { with(builtIns) {
when (value.type) { when (value.type) {
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classId
@@ -63,16 +63,19 @@ internal fun ClassDescriptor.toJavaClass(): Class<*>? {
else -> { else -> {
// If this is neither a Kotlin class nor a Java class, it's likely either a built-in or some fake class descriptor like the one // If this is neither a Kotlin class nor a Java class, it's likely either a built-in or some fake class descriptor like the one
// that's created for java.io.Serializable in JvmBuiltInsSettings // that's created for java.io.Serializable in JvmBuiltInsSettings
val classId = JavaToKotlinClassMap.mapKotlinToJava(DescriptorUtils.getFqName(this)) ?: classId ?: return null val classId = classId ?: return null
val packageName = classId.packageFqName.asString() loadClass(javaClass.safeClassLoader, classId, 0)
val className = classId.relativeClassName.asString()
// All pseudo-classes like kotlin.String.Companion must be accessible from the current class loader
loadClass(javaClass.safeClassLoader, packageName, className)
} }
} }
} }
internal fun loadClass(classLoader: ClassLoader, packageName: String, className: String): Class<*>? { private fun loadClass(classLoader: ClassLoader, kotlinClassId: ClassId, arrayDimensions: Int = 0): Class<*>? {
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(kotlinClassId.asSingleFqName().toUnsafe()) ?: kotlinClassId
// All pseudo-classes like kotlin.String.Companion must be accessible from the current class loader
return loadClass(classLoader, javaClassId.packageFqName.asString(), javaClassId.relativeClassName.asString(), arrayDimensions)
}
private fun loadClass(classLoader: ClassLoader, packageName: String, className: String, arrayDimensions: Int): Class<*>? {
if (packageName == "kotlin") { if (packageName == "kotlin") {
// See mapBuiltInType() in typeSignatureMapping.kt // See mapBuiltInType() in typeSignatureMapping.kt
when (className) { when (className) {
@@ -88,7 +91,12 @@ internal fun loadClass(classLoader: ClassLoader, packageName: String, className:
} }
} }
return classLoader.tryLoadClass("$packageName.${className.replace('.', '$')}") var fqName = "$packageName.${className.replace('.', '$')}"
repeat(arrayDimensions) {
fqName = "[$fqName"
}
return classLoader.tryLoadClass(fqName)
} }
internal fun Visibility.toKVisibility(): KVisibility? = internal fun Visibility.toKVisibility(): KVisibility? =
@@ -128,12 +136,15 @@ private fun ConstantValue<*>.toRuntimeValue(classLoader: ClassLoader): Any? = wh
is ArrayValue -> value.map { it.toRuntimeValue(classLoader) }.toTypedArray() is ArrayValue -> value.map { it.toRuntimeValue(classLoader) }.toTypedArray()
is EnumValue -> { is EnumValue -> {
val (enumClassId, entryName) = value val (enumClassId, entryName) = value
loadClass(classLoader, enumClassId.packageFqName.asString(), enumClassId.relativeClassName.asString())?.let { enumClass -> loadClass(classLoader, enumClassId)?.let { enumClass ->
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
Util.getEnumConstantByName(enumClass as Class<out Enum<*>>, entryName.asString()) Util.getEnumConstantByName(enumClass as Class<out Enum<*>>, entryName.asString())
} }
} }
is KClassValue -> (value.constructor.declarationDescriptor as? ClassDescriptor)?.toJavaClass() is KClassValue -> {
val (classId, arrayDimensions) = value
loadClass(classLoader, classId, arrayDimensions)
}
is ErrorValue, is NullValue -> null is ErrorValue, is NullValue -> null
else -> value // Primitives and strings else -> value // Primitives and strings
} }
@@ -2,4 +2,4 @@ import kotlin.reflect.KClass
annotation class Ann(val value: KClass<*>) annotation class Ann(val value: KClass<*>)
@Ann(Array<<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: String123">String123</error>>::class) class A @Ann(<error descr="[ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL] An annotation argument must be a class literal (T::class)">Array<<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: String123">String123</error>>::class</error>) class A
@@ -27,18 +27,19 @@ import kotlinx.kapt.KaptIgnored
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.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.kapt3.* import org.jetbrains.kotlin.kapt3.KaptContextForStubGeneration
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.kapt3.base.plus
import org.jetbrains.kotlin.kapt3.base.javac.kaptError import org.jetbrains.kotlin.kapt3.base.javac.kaptError
import org.jetbrains.kotlin.kapt3.base.javac.reportKaptError import org.jetbrains.kotlin.kapt3.base.javac.reportKaptError
import org.jetbrains.kotlin.kapt3.base.mapJList import org.jetbrains.kotlin.kapt3.base.mapJList
import org.jetbrains.kotlin.kapt3.base.mapJListIndexed import org.jetbrains.kotlin.kapt3.base.mapJListIndexed
import org.jetbrains.kotlin.kapt3.base.pairedListToMap import org.jetbrains.kotlin.kapt3.base.pairedListToMap
import org.jetbrains.kotlin.kapt3.base.util.TopLevelJava9Aware import org.jetbrains.kotlin.kapt3.base.plus
import org.jetbrains.kotlin.kapt3.base.stubs.KaptStubLineInformation import org.jetbrains.kotlin.kapt3.base.stubs.KaptStubLineInformation
import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.* import org.jetbrains.kotlin.kapt3.base.util.TopLevelJava9Aware
import org.jetbrains.kotlin.kapt3.javac.KaptJavaFileObject
import org.jetbrains.kotlin.kapt3.javac.KaptTreeMaker
import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.METHOD_PARAMETER_TYPE
import org.jetbrains.kotlin.kapt3.stubs.ErrorTypeCorrector.TypeKind.RETURN_TYPE
import org.jetbrains.kotlin.kapt3.util.* import org.jetbrains.kotlin.kapt3.util.*
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -1049,7 +1050,7 @@ class ClassFileToSourceStubConverter(
&& asm.size == desc.value.size && asm.size == desc.value.size
&& asm.zip(desc.value).all { (eAsm, eDesc) -> checkIfAnnotationValueMatches(eAsm, eDesc) } && asm.zip(desc.value).all { (eAsm, eDesc) -> checkIfAnnotationValueMatches(eAsm, eDesc) }
} }
is Type -> desc is KClassValue && typeMapper.mapType(desc.value) == asm is Type -> desc is KClassValue && typeMapper.mapType(desc.getArgumentType(kaptContext.generationState.module)) == asm
is AnnotationNode -> { is AnnotationNode -> {
val annotationDescriptor = (desc as? AnnotationValue)?.value ?: return false val annotationDescriptor = (desc as? AnnotationValue)?.value ?: return false
if (typeMapper.mapType(annotationDescriptor.type).descriptor != asm.desc) return false if (typeMapper.mapType(annotationDescriptor.type).descriptor != asm.desc) return false