Separate additional built-in members from JDK into three groups
- White list: can be used as common built-in declaration - Black list: can be used only for overrides and super-calls- - Not considered members: ones that is not in black or white list. Such members can be used in any context, but they usages marked as deprecated Third kind is needed to make possible use declarations added in future JDK versions. Deprecation is necessary because they may get into black list in next Kotlin compiler version
This commit is contained in:
+121
-26
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.load.kotlin
|
||||
import org.jetbrains.kotlin.builtins.BuiltInsInitializer
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.createDeprecatedAnnotation
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
@@ -40,6 +42,7 @@ import org.jetbrains.kotlin.serialization.deserialization.PlatformDependentDecla
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.types.DelegatingType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
@@ -61,6 +64,13 @@ open class JvmBuiltInsSettings(
|
||||
|
||||
private val javaAnalogueClassesWithCustomSupertypeCache = storageManager.createCacheWithNotNullValues<FqName, ClassDescriptor>()
|
||||
|
||||
// Most this properties are lazy because they depends on KotlinBuiltIns initialization that depends on JvmBuiltInsSettings object
|
||||
private val notConsideredDeprecation by storageManager.createLazyValue {
|
||||
moduleDescriptor.builtIns.createDeprecatedAnnotation(
|
||||
"This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version"
|
||||
).let { AnnotationsImpl(listOf(it)) }
|
||||
}
|
||||
|
||||
private fun createMockJavaIoSerializableType(): KotlinType {
|
||||
val mockJavaIoPackageFragment = object : PackageFragmentDescriptorImpl(moduleDescriptor, FqName("java.io")) {
|
||||
override fun getMemberScope() = MemberScope.Empty
|
||||
@@ -92,7 +102,7 @@ open class JvmBuiltInsSettings(
|
||||
getAdditionalFunctions(classDescriptor) {
|
||||
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
|
||||
}
|
||||
.map {
|
||||
.mapNotNull {
|
||||
additionalMember ->
|
||||
additionalMember.newCopyBuilder().apply {
|
||||
setOwner(classDescriptor)
|
||||
@@ -100,6 +110,25 @@ open class JvmBuiltInsSettings(
|
||||
setPreserveSourceElement()
|
||||
setSubstitution(createMappedTypeParametersSubstitution(
|
||||
additionalMember.containingDeclaration as ClassDescriptor, classDescriptor))
|
||||
|
||||
|
||||
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 -> {
|
||||
setAdditionalAnnotations(notConsideredDeprecation)
|
||||
}
|
||||
|
||||
JDKMemberStatus.DROP -> return@mapNotNull null
|
||||
|
||||
JDKMemberStatus.WHITE_LIST -> {} // Do nothing
|
||||
}
|
||||
|
||||
}.build()!!
|
||||
}
|
||||
|
||||
@@ -138,27 +167,13 @@ open class JvmBuiltInsSettings(
|
||||
it.containingDeclaration.fqNameSafe in kotlinVersions
|
||||
}) return@filter false
|
||||
|
||||
!analogueMember.isInBlackOrMutabilityViolation(isMutable)
|
||||
!analogueMember.isMutabilityViolation(isMutable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleFunctionDescriptor.isInBlackOrMutabilityViolation(isMutable: Boolean): Boolean {
|
||||
val jvmDescriptor = computeJvmDescriptor()
|
||||
private fun SimpleFunctionDescriptor.isMutabilityViolation(isMutable: Boolean): Boolean {
|
||||
val owner = containingDeclaration as ClassDescriptor
|
||||
if (DFS.ifAny(
|
||||
listOf(owner),
|
||||
{
|
||||
// Search through mapped supertypes to determine that Set.toArray is in blacklist, while we have only
|
||||
// Collection.toArray there explicitly
|
||||
// Note, that we can't find j.u.Collection.toArray within overriddenDescriptors of j.u.Set.toArray
|
||||
it.typeConstructor.supertypes.mapNotNull {
|
||||
(it.constructor.declarationDescriptor?.original as? ClassDescriptor)?.getJavaAnalogue()
|
||||
}
|
||||
}
|
||||
) {
|
||||
javaClassDescriptor ->
|
||||
SignatureBuildingComponents.signature(javaClassDescriptor, jvmDescriptor) in BLACK_LIST_METHOD_SIGNATURES
|
||||
}) return true
|
||||
val jvmDescriptor = computeJvmDescriptor()
|
||||
|
||||
if ((SignatureBuildingComponents.signature(owner, jvmDescriptor) in MUTABLE_METHOD_SIGNATURES) xor isMutable) return true
|
||||
|
||||
@@ -172,6 +187,40 @@ open class JvmBuiltInsSettings(
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getJdkMethodStatus(): JDKMemberStatus {
|
||||
val owner = containingDeclaration as ClassDescriptor
|
||||
val jvmDescriptor = computeJvmDescriptor()
|
||||
var result: JDKMemberStatus? = null
|
||||
return DFS.dfs<ClassDescriptor, JDKMemberStatus>(
|
||||
listOf(owner),
|
||||
{
|
||||
// Search through mapped supertypes to determine that Set.toArray is in blacklist, while we have only
|
||||
// Collection.toArray there explicitly
|
||||
// Note, that we can't find j.u.Collection.toArray within overriddenDescriptors of j.u.Set.toArray
|
||||
it.typeConstructor.supertypes.mapNotNull {
|
||||
(it.constructor.declarationDescriptor?.original as? ClassDescriptor)?.getJavaAnalogue()
|
||||
}
|
||||
},
|
||||
object : DFS.AbstractNodeHandler<ClassDescriptor, JDKMemberStatus>() {
|
||||
override fun beforeChildren(javaClassDescriptor: ClassDescriptor): Boolean {
|
||||
val signature = SignatureBuildingComponents.signature(javaClassDescriptor, jvmDescriptor)
|
||||
when (signature) {
|
||||
in BLACK_LIST_METHOD_SIGNATURES -> { result = JDKMemberStatus.BLACK_LIST }
|
||||
in WHITE_LIST_METHOD_SIGNATURES -> { result = JDKMemberStatus.WHITE_LIST }
|
||||
in DROP_LIST_METHOD_SIGNATURES -> { result = JDKMemberStatus.DROP }
|
||||
}
|
||||
|
||||
return result == null
|
||||
}
|
||||
|
||||
override fun result() = result ?: JDKMemberStatus.NOT_CONSIDERED
|
||||
})
|
||||
}
|
||||
|
||||
private enum class JDKMemberStatus {
|
||||
BLACK_LIST, WHITE_LIST, NOT_CONSIDERED, DROP
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.getJavaAnalogue(): LazyJavaClassDescriptor? {
|
||||
// Prevents recursive dependency: memberScope(Any) -> memberScope(Object) -> memberScope(Any)
|
||||
// No additional members should be added to Any
|
||||
@@ -211,6 +260,11 @@ open class JvmBuiltInsSettings(
|
||||
setReturnType(classDescriptor.defaultType)
|
||||
setPreserveSourceElement()
|
||||
setSubstitution(substitutor.substitution)
|
||||
|
||||
if (SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in WHITE_LIST_CONSTRUCTOR_SIGNATURES) {
|
||||
setAdditionalAnnotations(notConsideredDeprecation)
|
||||
}
|
||||
|
||||
}.build() as ConstructorDescriptor
|
||||
}
|
||||
}
|
||||
@@ -246,16 +300,17 @@ open class JvmBuiltInsSettings(
|
||||
return Serializable::class.java.isAssignableFrom(classViaReflection)
|
||||
}
|
||||
|
||||
val DROP_LIST_METHOD_SIGNATURES: Set<String> =
|
||||
SignatureBuildingComponents.inJavaUtil(
|
||||
"Collection",
|
||||
"toArray()[Ljava/lang/Object;", "toArray([Ljava/lang/Object;)[Ljava/lang/Object;") +
|
||||
|
||||
"java/lang/annotation/Annotation.annotationType()Ljava/lang/Class;"
|
||||
|
||||
val BLACK_LIST_METHOD_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
buildPrimitiveValueMethodsSet() +
|
||||
|
||||
"java/lang/annotation/Annotation.annotationType()Ljava/lang/Class;" +
|
||||
|
||||
inJavaUtil(
|
||||
"Collection", "toArray()[Ljava/lang/Object;", "toArray([Ljava/lang/Object;)[Ljava/lang/Object;"
|
||||
) +
|
||||
|
||||
inJavaUtil("List", "sort(Ljava/util/Comparator;)V") +
|
||||
|
||||
inJavaLang("String",
|
||||
@@ -280,8 +335,6 @@ open class JvmBuiltInsSettings(
|
||||
inJavaLang("Double", "isInfinite()Z", "isNaN()Z") +
|
||||
inJavaLang("Float", "isInfinite()Z", "isNaN()Z") +
|
||||
|
||||
inJavaUtil("Collection", "toArray([Ljava/lang/Object;)[Ljava/lang/Object;", "toArray()[Ljava/lang/Object;") +
|
||||
|
||||
inJavaLang("Enum", "getDeclaringClass()Ljava/lang/Class;", "finalize()V")
|
||||
}
|
||||
|
||||
@@ -292,6 +345,43 @@ open class JvmBuiltInsSettings(
|
||||
}
|
||||
}
|
||||
|
||||
val WHITE_LIST_METHOD_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
inJavaLang("CharSequence",
|
||||
"codePoints()Ljava/util/stream/IntStream;", "chars()Ljava/util/stream/IntStream;") +
|
||||
|
||||
inJavaUtil("Iterator",
|
||||
"forEachRemaining(Ljava/util/function/Consumer;)V") +
|
||||
|
||||
inJavaLang("Iterable",
|
||||
"forEach(Ljava/util/function/Consumer;)V", "spliterator()Ljava/util/Spliterator;") +
|
||||
|
||||
inJavaLang("Throwable",
|
||||
"setStackTrace([Ljava/lang/StackTraceElement;)V", "fillInStackTrace()Ljava/lang/Throwable;",
|
||||
"getLocalizedMessage()Ljava/lang/String;", "printStackTrace()V", "printStackTrace(Ljava/io/PrintStream;)V",
|
||||
"printStackTrace(Ljava/io/PrintWriter;)V", "getStackTrace()[Ljava/lang/StackTraceElement;",
|
||||
"initCause(Ljava/lang/Throwable;)Ljava/lang/Throwable;", "getSuppressed()[Ljava/lang/Throwable;",
|
||||
"addSuppressed(Ljava/lang/Throwable;)V") +
|
||||
|
||||
inJavaUtil("Collection",
|
||||
"spliterator()Ljava/util/Spliterator;", "parallelStream()Ljava/util/stream/Stream;",
|
||||
"stream()Ljava/util/stream/Stream;", "removeIf(Ljava/util/function/Predicate;)Z") +
|
||||
|
||||
inJavaUtil("List",
|
||||
"replaceAll(Ljava/util/function/UnaryOperator;)V") +
|
||||
|
||||
inJavaUtil("Map",
|
||||
"getOrDefault(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"forEach(Ljava/util/function/BiConsumer;)V", "replaceAll(Ljava/util/function/BiFunction;)V",
|
||||
"merge(Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;",
|
||||
"computeIfPresent(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;",
|
||||
"putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"replace(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z",
|
||||
"replace(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"computeIfAbsent(Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;",
|
||||
"compute(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;")
|
||||
}
|
||||
|
||||
val MUTABLE_METHOD_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
inJavaUtil("Collection", "removeIf(Ljava/util/function/Predicate;)Z") +
|
||||
@@ -324,6 +414,11 @@ open class JvmBuiltInsSettings(
|
||||
))
|
||||
}
|
||||
|
||||
val WHITE_LIST_CONSTRUCTOR_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
inJavaLang("Throwable", *constructors("Ljava/lang/String;Ljava/lang/Throwable;ZZ"))
|
||||
}
|
||||
|
||||
private fun buildPrimitiveStringConstructorsSet(): Set<String> =
|
||||
signatures {
|
||||
listOf(JvmPrimitiveType.BOOLEAN, JvmPrimitiveType.BYTE, JvmPrimitiveType.DOUBLE, JvmPrimitiveType.FLOAT,
|
||||
|
||||
Reference in New Issue
Block a user