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,
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.descriptors.annotations
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
class AnnotationsImpl : Annotations {
|
||||
private val annotations: List<AnnotationDescriptor>
|
||||
private val targetedAnnotations: List<AnnotationWithTarget>
|
||||
|
||||
constructor(annotations: List<AnnotationDescriptor>) {
|
||||
this.annotations = annotations
|
||||
this.targetedAnnotations = annotations.map { AnnotationWithTarget(it, null) }
|
||||
}
|
||||
|
||||
// List<AnnotationDescriptor> and List<AnnotationWithTarget> have the same signature
|
||||
private constructor(
|
||||
targetedAnnotations: List<AnnotationWithTarget>,
|
||||
@Suppress("UNUSED_PARAMETER") i: Int
|
||||
) {
|
||||
this.targetedAnnotations = targetedAnnotations
|
||||
this.annotations = targetedAnnotations.filter { it.target == null }.map { it.annotation }
|
||||
}
|
||||
|
||||
override fun isEmpty() = annotations.isEmpty()
|
||||
|
||||
override fun findAnnotation(fqName: FqName) = annotations.firstOrNull {
|
||||
val descriptor = it.type.constructor.declarationDescriptor
|
||||
descriptor is ClassDescriptor && fqName.toUnsafe() == DescriptorUtils.getFqName(descriptor)
|
||||
}
|
||||
|
||||
override fun getUseSiteTargetedAnnotations(): List<AnnotationWithTarget> {
|
||||
return targetedAnnotations
|
||||
.filter { it.target != null }
|
||||
.map { AnnotationWithTarget(it.annotation, it.target!!) }
|
||||
}
|
||||
|
||||
override fun getAllAnnotations() = targetedAnnotations
|
||||
|
||||
override fun findExternalAnnotation(fqName: FqName) = null
|
||||
|
||||
override fun iterator() = annotations.iterator()
|
||||
|
||||
override fun toString() = annotations.toString()
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(annotationsWithTargets: List<AnnotationWithTarget>): AnnotationsImpl {
|
||||
return AnnotationsImpl(annotationsWithTargets, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,9 @@ import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
// This function may be useful if we deprecate something not via the annotation but with special code in the compiler
|
||||
@Suppress("unused")
|
||||
fun KotlinBuiltIns.createDeprecatedAnnotation(
|
||||
message: String,
|
||||
replaceWith: String,
|
||||
replaceWith: String = "",
|
||||
level: String = "WARNING"
|
||||
): AnnotationDescriptor {
|
||||
val deprecatedAnnotation = deprecatedAnnotation
|
||||
|
||||
Reference in New Issue
Block a user