diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java index d77fa2180d4..c0abbf672e6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AnnotationCodegen.java @@ -439,7 +439,7 @@ public abstract class AnnotationCodegen { @Override public Void visitKClassValue(KClassValue value, Void data) { - annotationVisitor.visit(name, typeMapper.mapType(value.getValue())); + annotationVisitor.visit(name, typeMapper.mapType(value.getArgumentType(module))); return null; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index edf66c91138..204c941ee16 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -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.ConstantValue; 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.jvm.AsmTypes; import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo; @@ -1111,7 +1112,7 @@ public class FunctionCodegen { } @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")); if (annotation == null) { annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws")); @@ -1130,9 +1131,10 @@ public class FunctionCodegen { arrayValue.getValue(), (ConstantValue constant) -> { if (constant instanceof KClassValue) { - KClassValue classValue = (KClassValue) constant; - ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue()); - return mapper.mapClass(classDescriptor).getInternalName(); + ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType( + ((KClassValue) constant).getArgumentType(DescriptorUtilsKt.getModule(function)) + ); + return typeMapper.mapClass(classDescriptor).getInternalName(); } return null; } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java index 386158d60f3..5e8a015760c 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java @@ -287,6 +287,10 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { String elementDesc = nestedness == 0 ? typeDesc : type.getElementType().getDescriptor(); JvmPrimitiveType primType = JvmPrimitiveType.getByDesc(elementDesc); if (primType != null) { + if (nestedness > 0) { + // "int[][]" should be loaded as "Array", not as "Array>" + return new ClassLiteralValue(ClassId.topLevel(primType.getPrimitiveType().getArrayTypeFqName()), nestedness - 1); + } return new ClassLiteralValue(ClassId.topLevel(primType.getPrimitiveType().getTypeFqName()), nestedness); } ClassId javaClassId = resolveNameByDesc(elementDesc, innerClasses); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt index 177955193df..8b8dd8ff951 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalMarkerDeclarationAnnotationChecker.kt @@ -53,7 +53,8 @@ class ExperimentalMarkerDeclarationAnnotationChecker(private val module: ModuleD for (annotationClass in annotationClasses) { 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) { classDescriptor.loadExperimentalityForMarkerAnnotation() } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt index e1f1ffed8ac..fa984f7bda5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ExperimentalUsageChecker.kt @@ -189,7 +189,9 @@ class ExperimentalUsageChecker(project: Project) : CallChecker { if (descriptor?.fqName == USE_EXPERIMENTAL_FQ_NAME) { val annotationClasses = descriptor.allValueArguments[USE_EXPERIMENTAL_ANNOTATION_CLASS] 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 } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt index 1f18656f0d7..f2ae5944822 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/constants/evaluate/ConstantExpressionEvaluator.kt @@ -888,7 +888,9 @@ private class ConstantExpressionEvaluatorVisitor( override fun visitClassLiteralExpression(expression: KtClassLiteralExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { val type = trace.getType(expression)!! 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, expectedType: KotlinType): List?> { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt index de9c5960539..f090a4c142c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/sinceKotlinUtil.kt @@ -8,12 +8,12 @@ package org.jetbrains.kotlin.resolve import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.KClassValue +import org.jetbrains.kotlin.resolve.descriptorUtil.module sealed class SinceKotlinAccessibility { object Accessible : SinceKotlinAccessibility() @@ -102,13 +102,13 @@ private fun DeclarationDescriptor.getOwnSinceKotlinVersion(): SinceKotlinValue? return result } -private fun Annotated.loadWasExperimentalMarkerClasses(): List { +private fun DeclarationDescriptor.loadWasExperimentalMarkerClasses(): List { val wasExperimental = annotations.findAnnotation(ExperimentalUsageChecker.WAS_EXPERIMENTAL_FQ_NAME) if (wasExperimental != null) { val annotationClasses = wasExperimental.allValueArguments[ExperimentalUsageChecker.WAS_EXPERIMENTAL_ANNOTATION_CLASS] if (annotationClasses is ArrayValue) { return annotationClasses.value.mapNotNull { annotationClass -> - (annotationClass as? KClassValue)?.value?.constructor?.declarationDescriptor as? ClassDescriptor + (annotationClass as? KClassValue)?.getArgumentType(module)?.constructor?.declarationDescriptor as? ClassDescriptor } } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt index db9d98623e4..67623fab628 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt @@ -85,7 +85,7 @@ class ConstantValueGenerator( is AnnotationValue -> generateAnnotationConstructorCall(constantValue.value) is KClassValue -> { - val classifierKtType = constantValue.value + val classifierKtType = constantValue.getArgumentType(moduleDescriptor) val classifierDescriptor = classifierKtType.constructor.declarationDescriptor ?: throw AssertionError("Unexpected KClassValue: $classifierKtType") diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt index 96bf53a0fa7..04288bdcc07 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/AnnotationSerializer.kt @@ -16,8 +16,6 @@ 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.AnnotationDescriptor import org.jetbrains.kotlin.metadata.ProtoBuf @@ -100,22 +98,11 @@ class AnnotationSerializer(private val stringTable: DescriptorAwareStringTable) } 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 - classId = stringTable.getFqNameIndex(descriptor) + classId = stringTable.getQualifiedClassNameIndex(value.classId) - if (arrayDimensions > 0) { - arrayDimensionCount = arrayDimensions + if (value.arrayDimensions > 0) { + arrayDimensionCount = value.arrayDimensions } } diff --git a/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt b/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt index fd50a2847b0..c4dd01eb9df 100644 --- a/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt +++ b/compiler/testData/codegen/box/reflection/annotations/onTypes/differentArgumentTypes.kt @@ -27,6 +27,7 @@ annotation class Anno( val za: BooleanArray, val str: String, val k: KClass<*>, + val k2: KClass<*>, val e: AnnotationTarget, val a: Nested, val stra: Array, @@ -54,10 +55,11 @@ fun f(): @Anno( [false, true], "lol", Number::class, + IntArray::class, AnnotationTarget.EXPRESSION, Nested("1"), ["lmao"], - // [Double::class, Unit::class], + // [Double::class, Unit::class, LongArray::class], [AnnotationTarget.TYPEALIAS, AnnotationTarget.FIELD], [Nested("2"), Nested("3")] ) Unit {} @@ -66,7 +68,7 @@ fun box(): String { assertEquals( "[@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], " + - "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)])]", ::f.returnType.annotations.toString() ) diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.txt b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.txt index 3f3152bab3b..3a85db34e44 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.txt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotationWithKClass.txt @@ -2,8 +2,8 @@ package @Foo(a = {}) public fun test1(): 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 = {Gen::class}) public fun test4(): kotlin.Unit +@Foo(a = {kotlin.Array::class}) public fun test3(): kotlin.Unit +@Foo(a = {Gen::class}) public fun test4(): kotlin.Unit @Foo(a = {""}) public fun test5(): kotlin.Unit @Foo(a = {kotlin.Int::class, 1}) public fun test6(): kotlin.Unit @Bar public fun test7(): kotlin.Unit diff --git a/compiler/testData/loadJava/compiledJava/annotations/ClassObjectArrayInParam.txt b/compiler/testData/loadJava/compiledJava/annotations/ClassObjectArrayInParam.txt index ff98a0c36bb..003aaa84796 100644 --- a/compiler/testData/loadJava/compiledJava/annotations/ClassObjectArrayInParam.txt +++ b/compiler/testData/loadJava/compiledJava/annotations/ClassObjectArrayInParam.txt @@ -8,7 +8,7 @@ public open class ClassObjectArrayInParam { public final val value: kotlin.Array> } - @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>::class, kotlin.Array::class}) public open class Nested { public constructor Nested() } } diff --git a/compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.txt b/compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.txt index 77a9e5d2341..4cdd40dada1 100644 --- a/compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.txt +++ b/compiler/testData/loadJava/compiledKotlin/annotations/types/ClassLiteralArgument.txt @@ -3,8 +3,8 @@ package test public final class A { /*primary*/ public constructor A() public final fun arrays(/*0*/ s: @test.Ann(klass = kotlin.Array::class) kotlin.Array, /*1*/ t: @test.Ann(klass = kotlin.Array::class) kotlin.Array, /*2*/ u: @test.Ann(klass = kotlin.Array>::class) kotlin.Array>, /*3*/ v: @test.Ann(klass = kotlin.Array>>::class) kotlin.Array>>): 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 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 } diff --git a/compiler/tests/org/jetbrains/kotlin/resolve/annotation/AnnotationDescriptorResolveTest.java b/compiler/tests/org/jetbrains/kotlin/resolve/annotation/AnnotationDescriptorResolveTest.java index 291690f6ae4..6baabb4151c 100644 --- a/compiler/tests/org/jetbrains/kotlin/resolve/annotation/AnnotationDescriptorResolveTest.java +++ b/compiler/tests/org/jetbrains/kotlin/resolve/annotation/AnnotationDescriptorResolveTest.java @@ -87,7 +87,7 @@ public class AnnotationDescriptorResolveTest extends AbstractAnnotationDescripto public void testJavaClassAnnotation() throws Exception { String content = getContent("AnnClass(MyClass::class)"); - String expectedAnnotation = "@AnnClass(a = MyClass::class)"; + String expectedAnnotation = "@AnnClass(a = test.MyClass::class)"; doTest(content, expectedAnnotation); } } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt index 2e9b0871463..8a6bf04848e 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt @@ -18,9 +18,7 @@ package org.jetbrains.kotlin.load.java.lazy.descriptors import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.descriptors.annotations.Annotations 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.components.DescriptorResolverUtils 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.resolve.constants.* import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass -import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass 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( private val c: LazyJavaResolverContext, @@ -101,21 +100,8 @@ class LazyJavaAnnotationDescriptor( return EnumValue(enumClassId, entryName) } - private fun resolveFromJavaClassObjectType(javaType: JavaType): ConstantValue<*>? { - // Class type is never nullable in 'Foo.class' in Java - 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) - } + private fun resolveFromJavaClassObjectType(javaType: JavaType): ConstantValue<*>? = + KClassValue.create(c.typeResolver.transformJavaType(javaType, TypeUsage.COMMON.toAttributes())) override fun toString(): String { return DescriptorRenderer.FQ_NAMES_IN_TYPES.renderAnnotation(this) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt index 9287e616341..95af7978d94 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt @@ -16,11 +16,9 @@ package org.jetbrains.kotlin.load.kotlin -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor 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.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor 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.serialization.deserialization.AnnotationDeserializer 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 java.util.* @@ -94,8 +89,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl( } override fun visitClassLiteral(name: Name, value: ClassLiteralValue) { - arguments[name] = value.toClassValue() ?: - ErrorValue.create("Error value of annotation argument: $name: class ${value.classId.asSingleFqName()} not found") + arguments[name] = KClassValue(value) } override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) { @@ -115,11 +109,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl( } override fun visitClassLiteral(value: ClassLiteralValue) { - elements.add( - value.toClassValue() ?: ErrorValue.create( - "Error array element value of annotation argument: $name: class ${value.classId.asSingleFqName()} not found" - ) - ) + elements.add(KClassValue(value)) } 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 { return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 4942b18e03f..408cbe3393c 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -607,6 +607,11 @@ public abstract class KotlinBuiltIns { return getBuiltInClassByName("Annotation"); } + @NotNull + public ClassDescriptor getKClass() { + return getBuiltInClassByFqName(FQ_NAMES.kClass.toSafe()); + } + @NotNull private ClassDescriptor getCollectionClassByName(@NotNull String simpleName) { return getBuiltInClassByName(simpleName, packageFragments.invoke().collectionsPackageFragment); diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index bf43d92c87f..1356eb01f2a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -458,7 +458,11 @@ internal class DescriptorRendererImpl( return when (value) { is ArrayValue -> value.value.joinToString(", ", "{", "}") { renderConstant(it) } 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() } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt index 8e7637f0de7..2fd7728fb57 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt @@ -17,15 +17,18 @@ package org.jetbrains.kotlin.resolve.constants import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.types.ErrorUtils -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.resolve.descriptorUtil.classId +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections abstract class ConstantValue(open val value: T) { abstract fun getType(module: ModuleDescriptor): KotlinType @@ -154,13 +157,47 @@ class IntValue(value: Int) : IntegerValueConstant(value) { override fun accept(visitor: AnnotationArgumentVisitor, data: D) = visitor.visitIntValue(this, data) } -class KClassValue(private val type: KotlinType) : ConstantValue(type) { - override fun getType(module: ModuleDescriptor): KotlinType = type +class KClassValue(value: ClassLiteralValue) : ConstantValue(value) { + val classId: ClassId get() = value.classId + val arrayDimensions: Int get() = value.arrayNestedness - override val value: KotlinType - get() = type.arguments.single().type + constructor(classId: ClassId, arrayDimensions: Int) : this(ClassLiteralValue(classId, arrayDimensions)) + + 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 accept(visitor: AnnotationArgumentVisitor, 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(value) { diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt index ffd4738a0c5..7e09f58da6d 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/AnnotationDeserializer.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor 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.Argument 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.resolve.DescriptorUtils 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.replaceArgumentsWithStarProjections class AnnotationDeserializer(private val module: ModuleDescriptor, private val notFoundClasses: NotFoundClasses) { private val builtIns: KotlinBuiltIns @@ -79,7 +80,7 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n StringValue(nameResolver.getString(value.stringValue)) } Type.CLASS -> { - resolveClassLiteralValue(nameResolver.getClassId(value.classId), value.arrayDimensionCount) + KClassValue(nameResolver.getClassId(value.classId), value.arrayDimensionCount) } Type.ENUM -> { 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.letIf(predicate: Boolean, f: (T) -> R, g: (T) -> R): R = 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.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 = with(builtIns) { when (value.type) { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt index 3a7fdbd831b..64492628ffa 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -28,9 +28,9 @@ import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.protobuf.MessageLite -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.classId @@ -63,16 +63,19 @@ internal fun ClassDescriptor.toJavaClass(): Class<*>? { 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 // that's created for java.io.Serializable in JvmBuiltInsSettings - val classId = JavaToKotlinClassMap.mapKotlinToJava(DescriptorUtils.getFqName(this)) ?: classId ?: return null - val packageName = classId.packageFqName.asString() - 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) + val classId = classId ?: return null + loadClass(javaClass.safeClassLoader, classId, 0) } } } -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") { // See mapBuiltInType() in typeSignatureMapping.kt 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? = @@ -128,12 +136,15 @@ private fun ConstantValue<*>.toRuntimeValue(classLoader: ClassLoader): Any? = wh is ArrayValue -> value.map { it.toRuntimeValue(classLoader) }.toTypedArray() is EnumValue -> { val (enumClassId, entryName) = value - loadClass(classLoader, enumClassId.packageFqName.asString(), enumClassId.relativeClassName.asString())?.let { enumClass -> + loadClass(classLoader, enumClassId)?.let { enumClass -> @Suppress("UNCHECKED_CAST") Util.getEnumConstantByName(enumClass as Class>, 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 else -> value // Primitives and strings } diff --git a/idea/testData/checker/ResolveTypeInAnnotationArgumentRuntime.kt b/idea/testData/checker/ResolveTypeInAnnotationArgumentRuntime.kt index 53547204104..58e8d2344f6 100644 --- a/idea/testData/checker/ResolveTypeInAnnotationArgumentRuntime.kt +++ b/idea/testData/checker/ResolveTypeInAnnotationArgumentRuntime.kt @@ -2,4 +2,4 @@ import kotlin.reflect.KClass annotation class Ann(val value: KClass<*>) -@Ann(Array<String123>::class) class A +@Ann(Array<String123>::class) class A diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt index 58a279f644a..d9ecdbe0f7a 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/stubs/ClassFileToSourceStubConverter.kt @@ -27,18 +27,19 @@ import kotlinx.kapt.KaptIgnored import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.kapt3.* -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.KaptContextForStubGeneration import org.jetbrains.kotlin.kapt3.base.javac.kaptError import org.jetbrains.kotlin.kapt3.base.javac.reportKaptError import org.jetbrains.kotlin.kapt3.base.mapJList import org.jetbrains.kotlin.kapt3.base.mapJListIndexed 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.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.load.java.sources.JavaSourceElement import org.jetbrains.kotlin.name.FqName @@ -1049,7 +1050,7 @@ class ClassFileToSourceStubConverter( && asm.size == desc.value.size && 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 -> { val annotationDescriptor = (desc as? AnnotationValue)?.value ?: return false if (typeMapper.mapType(annotationDescriptor.type).descriptor != asm.desc) return false