diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/classSimpleName.kt b/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/classSimpleName.kt index 6899989aaca..7079ca9ea11 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/classSimpleName.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/classLiterals/classSimpleName.kt @@ -1,14 +1,12 @@ +import kotlin.test.assertEquals + class Klass fun box(): String { - val x = Klass::class - if (x.simpleName != "Klass") return "Fail x: ${x.simpleName}" - - val y = java.util.Date::class - if (y.simpleName != "Date") return "Fail y: ${y.simpleName}" - - val z = kotlin.jvm.internal.KotlinSyntheticClass.Kind::class - if (z.simpleName != "Kind") return "Fail z: ${z.simpleName}" + assertEquals("Klass", Klass::class.simpleName) + assertEquals("Date", java.util.Date::class.simpleName) + assertEquals("Kind", kotlin.jvm.internal.KotlinSyntheticClass.Kind::class.simpleName) + assertEquals("Void", java.lang.Void::class.simpleName) return "OK" } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt index ce649f06289..35f22f88051 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt @@ -58,10 +58,9 @@ class LazyJavaAnnotationDescriptor( } private val type = c.storageManager.createLazyValue { - val fqName = fqName() - if (fqName == null) return@createLazyValue ErrorUtils.createErrorType("No fqName: $javaAnnotation") - val annotationClass = JavaToKotlinClassMap.INSTANCE.mapKotlinClass(fqName, TypeUsage.MEMBER_SIGNATURE_INVARIANT) - ?: javaAnnotation.resolve()?.let { javaClass -> c.moduleClassResolver.resolveClass(javaClass) } + val fqName = fqName() ?: return@createLazyValue ErrorUtils.createErrorType("No fqName: $javaAnnotation") + val annotationClass = JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(fqName) + ?: javaAnnotation.resolve()?.let { javaClass -> c.moduleClassResolver.resolveClass(javaClass) } annotationClass?.getDefaultType() ?: ErrorUtils.createErrorType(fqName.asString()) } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.kt index 0f934da7669..6445e7274f3 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.kt @@ -146,7 +146,7 @@ class LazyJavaTypeResolver( return c.reflectionTypes.kClass } - val javaToKotlinClassMap = JavaToKotlinClassMap.INSTANCE + val javaToKotlin = JavaToKotlinClassMap.INSTANCE val howThisTypeIsUsedEffectively = when { attr.flexibility == FLEXIBLE_LOWER_BOUND -> MEMBER_SIGNATURE_COVARIANT @@ -154,13 +154,19 @@ class LazyJavaTypeResolver( // This case has to be checked before isMarkedReadOnly/isMarkedMutable, because those two are slow // not mapped, we don't care about being marked mutable/read-only - javaToKotlinClassMap.mapPlatformClass(fqName).isEmpty() -> attr.howThisTypeIsUsed + javaToKotlin.mapPlatformClass(fqName).isEmpty() -> attr.howThisTypeIsUsed // Read (possibly external) annotations else -> attr.howThisTypeIsUsedAccordingToAnnotations } - return javaToKotlinClassMap.mapKotlinClass(fqName, howThisTypeIsUsedEffectively) + if (howThisTypeIsUsedEffectively == MEMBER_SIGNATURE_COVARIANT || howThisTypeIsUsedEffectively == SUPERTYPE) { + javaToKotlin.mapJavaToKotlinCovariant(fqName)?.let { mutableCollectionDescriptor -> + return mutableCollectionDescriptor + } + } + + return javaToKotlin.mapJavaToKotlin(fqName) } private fun isConstructorTypeParameter(): Boolean { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JavaToKotlinClassMap.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JavaToKotlinClassMap.java index c1d3f6fd300..2b954c5f797 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JavaToKotlinClassMap.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JavaToKotlinClassMap.java @@ -21,7 +21,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.PrimitiveType; import org.jetbrains.kotlin.descriptors.ClassDescriptor; -import org.jetbrains.kotlin.load.java.components.TypeUsage; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.resolve.DescriptorUtils; @@ -49,16 +48,15 @@ public class JavaToKotlinClassMap extends JavaToKotlinClassMapBuilder implements } @Nullable - public ClassDescriptor mapKotlinClass(@NotNull FqName fqName, @NotNull TypeUsage typeUsage) { - if (typeUsage == TypeUsage.MEMBER_SIGNATURE_COVARIANT || typeUsage == TypeUsage.SUPERTYPE) { - ClassDescriptor descriptor = classDescriptorMapForCovariantPositions.get(fqName); - if (descriptor != null) { - return descriptor; - } - } + public ClassDescriptor mapJavaToKotlin(@NotNull FqName fqName) { return classDescriptorMap.get(fqName); } + @Nullable + public ClassDescriptor mapJavaToKotlinCovariant(@NotNull FqName fqName) { + return classDescriptorMapForCovariantPositions.get(fqName); + } + @NotNull private static FqName fqNameByClass(@NotNull Class clazz) { return new FqName(clazz.getCanonicalName()); @@ -92,8 +90,8 @@ public class JavaToKotlinClassMap extends JavaToKotlinClassMapBuilder implements @NotNull public Collection mapPlatformClass(@NotNull FqName fqName) { - ClassDescriptor kotlinAnalog = classDescriptorMap.get(fqName); - ClassDescriptor kotlinCovariantAnalog = classDescriptorMapForCovariantPositions.get(fqName); + ClassDescriptor kotlinAnalog = mapJavaToKotlin(fqName); + ClassDescriptor kotlinCovariantAnalog = mapJavaToKotlinCovariant(fqName); List descriptors = new ArrayList(2); if (kotlinAnalog != null) { descriptors.add(kotlinAnalog); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/InverseIntrinsicObjectsMapping.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/InverseIntrinsicObjectsMapping.kt new file mode 100644 index 00000000000..6814efd5ba1 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/InverseIntrinsicObjectsMapping.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.reflect.jvm.internal + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.jvm.IntrinsicObjects +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.name.FqName + +object InverseIntrinsicObjectsMapping { + private val map = linkedMapOf() + + init { + for (descriptor in KotlinBuiltIns.getInstance().getBuiltInsPackageFragment().getMemberScope().getAllDescriptors()) { + val companion = (descriptor as? ClassDescriptor)?.getCompanionObjectDescriptor() ?: continue + IntrinsicObjects.mapType(companion)?.let { fqName -> + map[fqName] = companion + } + } + } + + /** + * Maps a FQ name of an internal JVM class representing a built-in companion object to the relevant Kotlin descriptor, + * e.g. [kotlin.jvm.internal.StringCompanionObject] -> class descriptor of [kotlin.String.Companion] + */ + fun mapJvmClassToKotlinDescriptor(javaFqName: FqName): ClassDescriptor? = map[javaFqName] +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt index 19fd4951f46..5741196da31 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt @@ -17,27 +17,26 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.jvm.IntrinsicObjects import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.load.java.structure.reflect.classId -import org.jetbrains.kotlin.load.java.structure.reflect.desc import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.JavaToKotlinClassMapBuilder +import org.jetbrains.kotlin.platform.JavaToKotlinClassMapBuilder.Direction.BOTH +import org.jetbrains.kotlin.platform.JavaToKotlinClassMapBuilder.Direction.KOTLIN_TO_JAVA import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils -import kotlin.reflect.KotlinReflectionInternalError object RuntimeTypeMapper : JavaToKotlinClassMapBuilder() { - private val kotlinArrayClassId = KotlinBuiltIns.getInstance().getArray().classId - private val kotlinFqNameToJvmDesc = linkedMapOf() - private val jvmDescToKotlinClassId = linkedMapOf() init { init() @@ -48,43 +47,26 @@ object RuntimeTypeMapper : JavaToKotlinClassMapBuilder() { val builtIns = KotlinBuiltIns.getInstance() for (type in JvmPrimitiveType.values()) { - val primitiveType = type.getPrimitiveType() - val primitiveClassDescriptor = builtIns.getPrimitiveClassDescriptor(primitiveType) - - recordKotlinToJvm(primitiveClassDescriptor, type.getDesc()) - recordKotlinToJvm(builtIns.getPrimitiveArrayClassDescriptor(primitiveType), "[" + type.getDesc()) - - recordJvmToKotlin(ClassId.topLevel(type.getWrapperFqName()).desc, primitiveClassDescriptor) + recordKotlinToJvm(builtIns.getPrimitiveClassDescriptor(type.getPrimitiveType()), type.getDesc()) } } private fun recordKotlinToJvm(kotlinDescriptor: ClassDescriptor, jvmDesc: String) { kotlinFqNameToJvmDesc[DescriptorUtils.getFqNameSafe(kotlinDescriptor)] = jvmDesc - recordJvmToKotlin(jvmDesc, kotlinDescriptor) - - val companionObject = kotlinDescriptor.getCompanionObjectDescriptor() - if (companionObject != null) { - val runtimeCompanionFqName = IntrinsicObjects.mapType(companionObject) - ?: throw KotlinReflectionInternalError("Failed to map intrinsic companion of $kotlinDescriptor") - recordKotlinToJvm(companionObject, ClassId.topLevel(runtimeCompanionFqName).desc) - } - } - - private fun recordJvmToKotlin(jvmDesc: String, kotlinDescriptor: ClassDescriptor) { - jvmDescToKotlinClassId[jvmDesc] = kotlinDescriptor.classId } override fun register(javaClass: Class<*>, kotlinDescriptor: ClassDescriptor, direction: JavaToKotlinClassMapBuilder.Direction) { - // TODO: use direction correctly - recordKotlinToJvm(kotlinDescriptor, javaClass.classId.desc) + if (direction == BOTH || direction == KOTLIN_TO_JAVA) { + recordKotlinToJvm(kotlinDescriptor, javaClass.classId.desc) + } } override fun register(javaClass: Class<*>, kotlinDescriptor: ClassDescriptor, kotlinMutableDescriptor: ClassDescriptor) { - // TODO: readonly collection mapping just rewrites the mutable one, improve readability here register(javaClass, kotlinMutableDescriptor, JavaToKotlinClassMapBuilder.Direction.BOTH) register(javaClass, kotlinDescriptor, JavaToKotlinClassMapBuilder.Direction.BOTH) } + // TODO: this logic must be shared with JetTypeMapper fun mapTypeToJvmDesc(type: JetType): String { val classifier = type.getConstructor().getDeclarationDescriptor() if (classifier is TypeParameterDescriptor) { @@ -106,21 +88,50 @@ object RuntimeTypeMapper : JavaToKotlinClassMapBuilder() { return if (TypeUtils.isNullableType(type)) ClassId.topLevel(jvmType.getWrapperFqName()).desc else jvmType.getDesc() } + KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(fqNameUnsafe)?.let { primitiveType -> + return "[" + JvmPrimitiveType.get(primitiveType).getDesc() + } + if (fqNameUnsafe.isSafe()) { kotlinFqNameToJvmDesc[fqNameUnsafe.toSafe()]?.let { return it } } + if (classDescriptor.isCompanionObject()) { + IntrinsicObjects.mapType(classDescriptor)?.let { fqName -> + return ClassId.topLevel(fqName).desc + } + } + return classDescriptor.classId.desc } fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId { - if (klass.isArray() && !klass.getComponentType().isPrimitive()) { - return kotlinArrayClassId + if (klass.isArray()) { + klass.getComponentType().primitiveType?.let { + return KotlinBuiltIns.getInstance().getPrimitiveArrayClassDescriptor(it).classId + } + return ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.array.toSafe()) } - return jvmDescToKotlinClassId[klass.desc] ?: klass.classId + klass.primitiveType?.let { + return KotlinBuiltIns.getInstance().getPrimitiveClassDescriptor(it).classId + } + + val classId = klass.classId + if (!classId.isLocal()) { + val fqName = classId.asSingleFqName() + val kotlinClass = JavaToKotlinClassMap.INSTANCE.mapJavaToKotlin(fqName) + kotlinClass?.let { return it.classId } + + InverseIntrinsicObjectsMapping.mapJvmClassToKotlinDescriptor(fqName)?.let { return it.classId } + } + + return classId } + private val Class<*>.primitiveType: PrimitiveType? + get() = if (isPrimitive()) JvmPrimitiveType.get(getSimpleName()).getPrimitiveType() else null + private val ClassId.desc: String get() = "L${JvmClassName.byClassId(this).getInternalName()};" }