Introduce predefined enhancement info

It can be used to specify enhanced signature for standard JDK methods
without them be actually annotated

 #KT-9194 In Progress
 #KT-5175 In Progress
 #KT-10370 In Progress
 #KT-7127 In Progress
This commit is contained in:
Denis Zharkov
2016-04-21 16:05:08 +03:00
parent 3bda613317
commit 9bf2538e4c
10 changed files with 278 additions and 42 deletions
@@ -0,0 +1,46 @@
/*
* 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.load.java.typeEnhancement
import org.jetbrains.kotlin.load.kotlin.signatures
class TypeEnhancementInfo(val map: Map<Int, JavaTypeQualifiers>) {
constructor(vararg pairs: Pair<Int, JavaTypeQualifiers>) : this(mapOf(*pairs))
}
class PredefinedFunctionEnhancementInfo(
val returnTypeInfo: TypeEnhancementInfo? = null,
val parametersInfo: List<TypeEnhancementInfo?> = emptyList()
)
private val NOT_NULLABLE = JavaTypeQualifiers(NullabilityQualifier.NOT_NULL, null, isNotNullTypeParameter = false)
val PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE = signatures {
mapOf(
signature(javaUtil("Iterator"), "forEachRemaining(Ljava/util/function/Consumer;)V") to
PredefinedFunctionEnhancementInfo(
parametersInfo = listOf(
TypeEnhancementInfo(
0 to NOT_NULLABLE,
1 to NOT_NULLABLE
)
)
),
signature("java/util/function/Consumer", "accept($objectType)V") to
PredefinedFunctionEnhancementInfo(parametersInfo = listOf(TypeEnhancementInfo(0 to NOT_NULLABLE)))
)
}
@@ -17,7 +17,11 @@
package org.jetbrains.kotlin.load.java.typeEnhancement
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
import org.jetbrains.kotlin.types.KotlinType
fun <D : CallableMemberDescriptor> enhanceSignatures(platformSignatures: Collection<D>): Collection<D> {
@@ -41,11 +45,26 @@ private fun <D : CallableMemberDescriptor> D.enhanceSignature(): D {
parts(isCovariant = false) { it.extensionReceiverParameter!!.type }.enhance()
else null
val valueParameterEnhancements = valueParameters.map {
p -> parts(isCovariant = false) { it.valueParameters[p.index].type }.enhance()
val predefinedEnhancementInfo =
if (this is JavaMethodDescriptor)
PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE[
SignatureBuildingComponents.signature(this.containingDeclaration as ClassDescriptor, this.computeJvmDescriptor())]
else null
predefinedEnhancementInfo?.let {
assert(it.parametersInfo.size == valueParameters.size) {
"Predefined enhancement info for $this has ${it.parametersInfo.size}, but ${valueParameters.size} expected"
}
}
val returnTypeEnhancement = parts(isCovariant = true) { it.returnType!! }.enhance()
val valueParameterEnhancements = valueParameters.map {
p ->
parts(isCovariant = false) { it.valueParameters[p.index].type }
.enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index))
}
val returnTypeEnhancement = parts(isCovariant = true) { it.returnType!! }.enhance(predefinedEnhancementInfo?.returnTypeInfo)
if ((receiverTypeEnhancement?.wereChanges ?: false)
|| returnTypeEnhancement.wereChanges || valueParameterEnhancements.any { it.wereChanges }) {
@@ -61,9 +80,16 @@ private class SignatureParts(
val fromOverridden: Collection<KotlinType>,
val isCovariant: Boolean
) {
fun enhance(): PartEnhancementResult {
fun enhance(predefined: TypeEnhancementInfo? = null): PartEnhancementResult {
val qualifiers = fromOverride.computeIndexedQualifiersForOverride(this.fromOverridden, isCovariant)
return fromOverride.enhance(qualifiers)?.let {
val qualifiersWithPredefined: ((Int) -> JavaTypeQualifiers)? = predefined?.let {
{
index -> predefined.map[index] ?: qualifiers(index)
}
}
return fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let {
enhanced -> PartEnhancementResult(enhanced, wereChanges = true)
} ?: PartEnhancementResult(fromOverride, wereChanges = false)
}
@@ -149,10 +149,10 @@ open class JvmBuiltInsAdditionalClassPartsProvider(
}
) {
javaClassDescriptor ->
signature(javaClassDescriptor, jvmDescriptor) in BLACK_LIST_METHOD_SIGNATURES
SignatureBuildingComponents.signature(javaClassDescriptor, jvmDescriptor) in BLACK_LIST_METHOD_SIGNATURES
}) return true
if ((signature(owner, jvmDescriptor) in MUTABLE_METHOD_SIGNATURES) xor isMutable) return true
if ((SignatureBuildingComponents.signature(owner, jvmDescriptor) in MUTABLE_METHOD_SIGNATURES) xor isMutable) return true
return DFS.ifAny<CallableMemberDescriptor>(
listOf(this),
@@ -164,8 +164,6 @@ open class JvmBuiltInsAdditionalClassPartsProvider(
}
}
private fun signature(javaClassDescriptor: ClassDescriptor, jvmDescriptor: String) = javaClassDescriptor.internalName + "." + jvmDescriptor
private fun ClassDescriptor.getJavaAnalogue(): LazyJavaClassDescriptor? {
// Prevents recursive dependency: memberScope(Any) -> memberScope(Object) -> memberScope(Any)
// No additional members should be added to Any
@@ -197,7 +195,7 @@ open class JvmBuiltInsAdditionalClassPartsProvider(
defaultKotlinVersion.constructors.none { it.isEffectivelyTheSameAs(javaConstructor) } &&
!javaConstructor.isTrivialCopyConstructorFor(classDescriptor) &&
!KotlinBuiltIns.isDeprecated(javaConstructor) &&
signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in BLACK_LIST_CONSTRUCTOR_SIGNATURES
SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in BLACK_LIST_CONSTRUCTOR_SIGNATURES
}.map {
javaConstructor ->
javaConstructor.newCopyBuilder().apply {
@@ -230,6 +228,7 @@ open class JvmBuiltInsAdditionalClassPartsProvider(
}
private val BLACK_LIST_METHOD_SIGNATURES: Set<String> =
signatures {
buildPrimitiveValueMethodsSet() +
"java/lang/annotation/Annotation.annotationType()${javaLang("Class").t}" +
@@ -261,17 +260,21 @@ open class JvmBuiltInsAdditionalClassPartsProvider(
inJavaLang("Float", "isInfinite()Z", "isNaN()Z") +
inJavaUtil("Collection", "toArray([$objectType)[$objectType", "toArray()[$objectType")
}
private fun buildPrimitiveValueMethodsSet(): Set<String> =
signatures {
JvmPrimitiveType.values().flatMapTo(LinkedHashSet()) {
inJavaLang(it.wrapperFqName.shortName().asString(), "${it.javaKeywordName}Value()${it.desc}")
}
}
private val MUTABLE_METHOD_SIGNATURES: Set<String> =
signatures {
inJavaUtil("Collection", "removeIf(Ljava/util/function/Predicate;)Z") +
inJavaUtil("List",
"sort(Ljava/util/Comparator;)V", "replaceAll(Ljava/util/function/UnaryOperator;)V") +
"sort(Ljava/util/Comparator;)V", "replaceAll(Ljava/util/function/UnaryOperator;)V") +
inJavaUtil("Map",
"computeIfAbsent(${objectType}Ljava/util/function/Function;)$objectType",
@@ -282,8 +285,10 @@ open class JvmBuiltInsAdditionalClassPartsProvider(
"remove($objectType$objectType)Z", "replaceAll(Ljava/util/function/BiFunction;)V",
"replace($objectType$objectType)$objectType",
"replace($objectType$objectType$objectType)Z")
}
private val BLACK_LIST_CONSTRUCTOR_SIGNATURES: Set<String> =
signatures {
buildPrimitiveStringConstructorsSet() +
inJavaLang("Float", *constructors("D")) +
inJavaLang("String", *constructors(
@@ -295,28 +300,15 @@ open class JvmBuiltInsAdditionalClassPartsProvider(
"Ljava/lang/StringBuffer;",
"Ljava/lang/StringBuilder;"
))
}
private fun buildPrimitiveStringConstructorsSet(): Set<String> =
signatures {
JvmPrimitiveType.values().flatMapTo(LinkedHashSet()) {
inJavaLang(it.wrapperFqName.shortName().asString(), *constructors(stringType))
}
}
}
}
private val ClassDescriptor.isAny: Boolean get() = fqNameUnsafe == KotlinBuiltIns.FQ_NAMES.any
private val String.t: String
get() = "L$this;"
private val stringType = javaLang("String").t
private val objectType = javaLang("Object").t
private fun javaLang(name: String) = "java/lang/$name"
private fun javaUtil(name: String) = "java/util/$name"
private fun constructors(vararg signatures: String) = signatures.map { "<init>($it)V" }.toTypedArray()
private fun inJavaLang(name: String, vararg signatures: String) = inClass(javaLang(name), *signatures)
private fun inJavaUtil(name: String, vararg signatures: String) = inClass(javaUtil(name), *signatures)
private fun inClass(internalName: String, vararg signatures: String) = signatures.mapTo(LinkedHashSet()) { internalName + "." + it }
@@ -0,0 +1,44 @@
/*
* 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.load.kotlin
import org.jetbrains.kotlin.descriptors.*
import java.util.*
fun <T> signatures(block: SignatureBuildingComponents.() -> T) = with(SignatureBuildingComponents, block)
object SignatureBuildingComponents {
val stringType = javaLang("String").t
val objectType = javaLang("Object").t
val String.t: String
get() = "L$this;"
fun javaLang(name: String) = "java/lang/$name"
fun javaUtil(name: String) = "java/util/$name"
fun constructors(vararg signatures: String) = signatures.map { "<init>($it)V" }.toTypedArray()
fun inJavaLang(name: String, vararg signatures: String) = inClass(javaLang(name), *signatures)
fun inJavaUtil(name: String, vararg signatures: String) = inClass(javaUtil(name), *signatures)
fun inClass(internalName: String, vararg signatures: String) = signatures.mapTo(LinkedHashSet()) { internalName + "." + it }
fun signature(classDescriptor: ClassDescriptor, jvmDescriptor: String) = signature(classDescriptor.internalName, jvmDescriptor)
fun signature(internalName: String, jvmDescriptor: String) = internalName + "." + jvmDescriptor
}
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.types.KotlinType
@@ -46,6 +48,10 @@ fun FunctionDescriptor.computeJvmDescriptor()
val ClassDescriptor.internalName: String
get() {
JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqNameSafe.toUnsafe())?.let {
return JvmClassName.byClassId(it).internalName
}
return computeInternalName(this)
}