Drop Cloneable in JS, synthesize it at compile-time on JVM
Use the same approach that is used for creating function type classes
(Function{0,1,...}) + add Cloneable to supertypes of Array and primitive arrays
#KT-5537 Fixed
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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 org.jetbrains.kotlin.builtins
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import java.util.*
|
||||
|
||||
class CloneableClassScope(storageManager: StorageManager, private val classDescriptor: ClassDescriptor) : MemberScopeImpl() {
|
||||
private val allDescriptors by storageManager.createLazyValue {
|
||||
val cloneFunction =
|
||||
SimpleFunctionDescriptorImpl.create(classDescriptor, Annotations.EMPTY, CLONE_NAME, DECLARATION, SourceElement.NO_SOURCE)
|
||||
cloneFunction.initialize(null, classDescriptor.thisAsReceiverParameter, emptyList(), emptyList(), classDescriptor.builtIns.anyType,
|
||||
Modality.OPEN, Visibilities.PROTECTED)
|
||||
|
||||
listOf(cloneFunction) + createFakeOverrides()
|
||||
}
|
||||
|
||||
private val functionNames = setOf(CLONE_NAME) + classDescriptor.builtIns.anyType.memberScope.getFunctionNames()
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> =
|
||||
if (name in functionNames) allDescriptors.filter { it.name == name } else emptySet()
|
||||
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> = allDescriptors
|
||||
|
||||
override fun getFunctionNames(): Set<Name> = functionNames
|
||||
|
||||
private fun createFakeOverrides(): List<SimpleFunctionDescriptor> {
|
||||
val result = ArrayList<SimpleFunctionDescriptor>(3)
|
||||
val allSuperDescriptors = classDescriptor.typeConstructor.supertypes
|
||||
.flatMap { it.memberScope.getContributedDescriptors() }
|
||||
.filterIsInstance<SimpleFunctionDescriptor>()
|
||||
for ((name, descriptors) in allSuperDescriptors.groupBy { it.name }) {
|
||||
OverridingUtil.generateOverridesInFunctionGroup(
|
||||
name,
|
||||
/* membersFromSupertypes = */ descriptors,
|
||||
/* membersFromCurrent = */ emptyList(),
|
||||
classDescriptor,
|
||||
object : NonReportingOverrideStrategy() {
|
||||
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
|
||||
OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, null)
|
||||
result.add(fakeOverride as SimpleFunctionDescriptor)
|
||||
}
|
||||
|
||||
override fun conflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
|
||||
error("Conflict in scope of $classDescriptor: $fromSuper vs $fromCurrent")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println("kotlin.Cloneable member scope")
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal val CLONE_NAME = Name.identifier("clone")
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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 org.jetbrains.kotlin.builtins
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassDescriptorFactory
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
|
||||
class JvmBuiltInClassDescriptorFactory(
|
||||
storageManager: StorageManager,
|
||||
private val moduleDescriptor: ModuleDescriptor
|
||||
) : ClassDescriptorFactory {
|
||||
private val cloneable by storageManager.createLazyValue {
|
||||
ClassDescriptorImpl(
|
||||
moduleDescriptor.getPackage(KOTLIN_FQ_NAME).fragments.single(),
|
||||
CLONEABLE_NAME, Modality.ABSTRACT, ClassKind.INTERFACE, listOf(moduleDescriptor.builtIns.anyType),
|
||||
SourceElement.NO_SOURCE
|
||||
).apply {
|
||||
initialize(CloneableClassScope(storageManager, this), emptySet(), null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldCreateClass(packageFqName: FqName, name: Name): Boolean =
|
||||
name == CLONEABLE_NAME && packageFqName == KOTLIN_FQ_NAME
|
||||
|
||||
override fun createClass(classId: ClassId): ClassDescriptor? =
|
||||
when (classId) {
|
||||
CLONEABLE_CLASS_ID -> cloneable
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun getAllContributedClassesIfPossible(packageFqName: FqName): Collection<ClassDescriptor> =
|
||||
when (packageFqName) {
|
||||
KOTLIN_FQ_NAME -> setOf(cloneable)
|
||||
else -> emptySet()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KOTLIN_FQ_NAME = KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME
|
||||
private val CLONEABLE_NAME = KotlinBuiltIns.FQ_NAMES.cloneable.shortName()
|
||||
val CLONEABLE_CLASS_ID = ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.cloneable.toSafe())
|
||||
}
|
||||
}
|
||||
+73
-47
@@ -17,6 +17,8 @@
|
||||
package org.jetbrains.kotlin.load.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.builtins.BuiltInsInitializer
|
||||
import org.jetbrains.kotlin.builtins.CloneableClassScope
|
||||
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||
@@ -28,6 +30,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.components.JavaResolverCache
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution
|
||||
@@ -65,6 +68,9 @@ open class JvmBuiltInsSettings(
|
||||
private val isAdditionalBuiltInsFeatureSupported: Boolean by lazy(isAdditionalBuiltInsFeatureSupported)
|
||||
|
||||
private val mockSerializableType = storageManager.createMockJavaIoSerializableType()
|
||||
private val cloneableType by storageManager.createLazyValue {
|
||||
moduleDescriptor.builtIns.getBuiltInClassByName(JvmBuiltInClassDescriptorFactory.CLONEABLE_CLASS_ID.shortClassName).defaultType
|
||||
}
|
||||
|
||||
private val javaAnalogueClassesWithCustomSupertypeCache = storageManager.createCacheWithNotNullValues<FqName, ClassDescriptor>()
|
||||
|
||||
@@ -114,58 +120,66 @@ open class JvmBuiltInsSettings(
|
||||
}
|
||||
|
||||
override fun getSupertypes(classDescriptor: DeserializedClassDescriptor): Collection<KotlinType> {
|
||||
if (isSerializableInJava(classDescriptor.fqNameSafe)) {
|
||||
return listOf(mockSerializableType)
|
||||
val fqName = classDescriptor.fqNameUnsafe
|
||||
return when {
|
||||
isArrayOrPrimitiveArray(fqName) -> listOf(cloneableType, mockSerializableType)
|
||||
isSerializableInJava(fqName) -> listOf(mockSerializableType)
|
||||
else -> listOf()
|
||||
}
|
||||
else return listOf()
|
||||
}
|
||||
|
||||
override fun getFunctions(name: Name, classDescriptor: DeserializedClassDescriptor): Collection<SimpleFunctionDescriptor> =
|
||||
getAdditionalFunctions(classDescriptor) {
|
||||
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
|
||||
}
|
||||
.mapNotNull {
|
||||
additionalMember ->
|
||||
val substitutedWithKotlinTypeParameters =
|
||||
additionalMember.substitute(
|
||||
createMappedTypeParametersSubstitution(
|
||||
additionalMember.containingDeclaration as ClassDescriptor, classDescriptor).buildSubstitutor()
|
||||
) as SimpleFunctionDescriptor
|
||||
override fun getFunctions(name: Name, classDescriptor: DeserializedClassDescriptor): Collection<SimpleFunctionDescriptor> {
|
||||
if (name == CloneableClassScope.CLONE_NAME && KotlinBuiltIns.isArrayOrPrimitiveArray(classDescriptor)) {
|
||||
return listOf(createCloneForArray(
|
||||
classDescriptor, cloneableType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
|
||||
))
|
||||
}
|
||||
|
||||
substitutedWithKotlinTypeParameters.newCopyBuilder().apply {
|
||||
setOwner(classDescriptor)
|
||||
setDispatchReceiverParameter(classDescriptor.thisAsReceiverParameter)
|
||||
setPreserveSourceElement()
|
||||
setSubstitution(UnsafeVarianceTypeSubstitution(moduleDescriptor.builtIns))
|
||||
return getAdditionalFunctions(classDescriptor) {
|
||||
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
|
||||
}.mapNotNull {
|
||||
additionalMember ->
|
||||
val substitutedWithKotlinTypeParameters =
|
||||
additionalMember.substitute(
|
||||
createMappedTypeParametersSubstitution(
|
||||
additionalMember.containingDeclaration as ClassDescriptor, classDescriptor).buildSubstitutor()
|
||||
) as SimpleFunctionDescriptor
|
||||
|
||||
val memberStatus = additionalMember.getJdkMethodStatus()
|
||||
when (memberStatus) {
|
||||
JDKMemberStatus.BLACK_LIST -> {
|
||||
// Black list methods in final class can't be overridden or called with 'super'
|
||||
if (classDescriptor.isFinalClass) return@mapNotNull null
|
||||
setHiddenForResolutionEverywhereBesideSupercalls()
|
||||
substitutedWithKotlinTypeParameters.newCopyBuilder().apply {
|
||||
setOwner(classDescriptor)
|
||||
setDispatchReceiverParameter(classDescriptor.thisAsReceiverParameter)
|
||||
setPreserveSourceElement()
|
||||
setSubstitution(UnsafeVarianceTypeSubstitution(moduleDescriptor.builtIns))
|
||||
|
||||
val memberStatus = additionalMember.getJdkMethodStatus()
|
||||
when (memberStatus) {
|
||||
JDKMemberStatus.BLACK_LIST -> {
|
||||
// Black list methods in final class can't be overridden or called with 'super'
|
||||
if (classDescriptor.isFinalClass) return@mapNotNull null
|
||||
setHiddenForResolutionEverywhereBesideSupercalls()
|
||||
}
|
||||
|
||||
JDKMemberStatus.NOT_CONSIDERED -> {
|
||||
if (!isAdditionalBuiltInsFeatureSupported) {
|
||||
setAdditionalAnnotations(notSupportedDeprecation)
|
||||
}
|
||||
|
||||
JDKMemberStatus.NOT_CONSIDERED -> {
|
||||
if (!isAdditionalBuiltInsFeatureSupported) {
|
||||
setAdditionalAnnotations(notSupportedDeprecation)
|
||||
}
|
||||
else {
|
||||
setAdditionalAnnotations(notConsideredDeprecation)
|
||||
}
|
||||
}
|
||||
|
||||
JDKMemberStatus.DROP -> return@mapNotNull null
|
||||
|
||||
JDKMemberStatus.WHITE_LIST -> {
|
||||
if (!isAdditionalBuiltInsFeatureSupported) {
|
||||
setAdditionalAnnotations(notSupportedDeprecation)
|
||||
}
|
||||
else {
|
||||
setAdditionalAnnotations(notConsideredDeprecation)
|
||||
}
|
||||
}
|
||||
|
||||
}.build()!!
|
||||
}
|
||||
JDKMemberStatus.DROP -> return@mapNotNull null
|
||||
|
||||
JDKMemberStatus.WHITE_LIST -> {
|
||||
if (!isAdditionalBuiltInsFeatureSupported) {
|
||||
setAdditionalAnnotations(notSupportedDeprecation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}.build()!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFunctionsNames(classDescriptor: DeserializedClassDescriptor): Set<Name> =
|
||||
// NB: It's just an approximation that could be calculated relatively fast
|
||||
@@ -206,6 +220,15 @@ open class JvmBuiltInsSettings(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCloneForArray(
|
||||
arrayClassDescriptor: DeserializedClassDescriptor,
|
||||
cloneFromCloneable: SimpleFunctionDescriptor
|
||||
): SimpleFunctionDescriptor = cloneFromCloneable.newCopyBuilder().apply {
|
||||
setOwner(arrayClassDescriptor)
|
||||
setVisibility(Visibilities.PUBLIC)
|
||||
setReturnType(arrayClassDescriptor.defaultType)
|
||||
}.build()!!
|
||||
|
||||
private fun SimpleFunctionDescriptor.isMutabilityViolation(isMutable: Boolean): Boolean {
|
||||
val owner = containingDeclaration as ClassDescriptor
|
||||
val jvmDescriptor = computeJvmDescriptor()
|
||||
@@ -323,12 +346,11 @@ open class JvmBuiltInsSettings(
|
||||
valueParameters.single().type.constructor.declarationDescriptor?.fqNameUnsafe == classDescriptor.fqNameUnsafe
|
||||
|
||||
companion object {
|
||||
fun isSerializableInJava(classFqName: FqName): Boolean {
|
||||
val fqNameUnsafe = classFqName.toUnsafe()
|
||||
if (fqNameUnsafe == KotlinBuiltIns.FQ_NAMES.array || KotlinBuiltIns.isPrimitiveArray(fqNameUnsafe)) {
|
||||
fun isSerializableInJava(fqName: FqNameUnsafe): Boolean {
|
||||
if (isArrayOrPrimitiveArray(fqName)) {
|
||||
return true
|
||||
}
|
||||
val javaClassId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqNameUnsafe) ?: return false
|
||||
val javaClassId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName) ?: return false
|
||||
val classViaReflection = try {
|
||||
Class.forName(javaClassId.asSingleFqName().asString())
|
||||
}
|
||||
@@ -338,6 +360,10 @@ open class JvmBuiltInsSettings(
|
||||
return Serializable::class.java.isAssignableFrom(classViaReflection)
|
||||
}
|
||||
|
||||
private fun isArrayOrPrimitiveArray(fqName: FqNameUnsafe): Boolean {
|
||||
return fqName == KotlinBuiltIns.FQ_NAMES.array || KotlinBuiltIns.isPrimitiveArray(fqName)
|
||||
}
|
||||
|
||||
val DROP_LIST_METHOD_SIGNATURES: Set<String> =
|
||||
SignatureBuildingComponents.inJavaUtil(
|
||||
"Collection",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.platform
|
||||
|
||||
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmBuiltInsSettings
|
||||
@@ -49,4 +50,7 @@ class JvmBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManage
|
||||
}
|
||||
|
||||
override fun getAdditionalClassPartsProvider() = settings
|
||||
|
||||
override fun getClassDescriptorFactories() =
|
||||
super.getClassDescriptorFactories() + JvmBuiltInClassDescriptorFactory(storageManager, builtInsModule)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user