From f3cb76ff56822a7826aea2e32a230956e5450939 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 24 Dec 2018 12:45:57 +0300 Subject: [PATCH] New J2K: Fix TypeMappingConversion --- .../j2k/conversions/TypeMappingConversion.kt | 158 ++++++++++++------ .../org/jetbrains/kotlin/j2k/tree/markers.kt | 3 + j2k/src/org/jetbrains/kotlin/j2k/Utils.kt | 2 +- 3 files changed, 111 insertions(+), 52 deletions(-) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt index 298e7ce0e73..9bf5751d832 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt @@ -12,15 +12,14 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.j2k.* +import org.jetbrains.kotlin.j2k.ast.Mutability import org.jetbrains.kotlin.j2k.ast.Nullability import org.jetbrains.kotlin.j2k.tree.* import org.jetbrains.kotlin.j2k.tree.impl.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.KtClassOrObject class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicableConversionBase() { - private val typeFlavorCalculator = TypeFlavorCalculator(object : TypeFlavorConverterFacade { override val referenceSearcher: ReferenceSearcher get() = context.converter.converterServices.oldServices.referenceSearcher @@ -30,75 +29,132 @@ class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicabl get() = context.converter.converterServices.oldServices.resolverForConverter override fun inConversionScope(element: PsiElement): Boolean = context.inConversionContext(element) - }) override fun applyToElement(element: JKTreeElement): JKTreeElement { - return recurse( - if (element is JKTypeElement) { - val newType = refineNullability(mapType(element.type, element), element) + return when (element) { + is JKTypeElement -> { + val newType = element.type + .fixRawType(element) + .mapType(element) + .refineNullability(element) JKTypeElementImpl(newType) - } else element - ) + } + is JKJavaNewExpression -> { + recurse( + JKJavaNewExpressionImpl( + element.classSymbol.mapClassSymbol(null), + element::arguments.detached(), + element::typeArgumentList.detached(), + element::classBody.detached() + ) + ) + } + else -> recurse(element) + } } - private fun refineNullability(type: JKType, element: JKTypeElement): JKType { - if (type.nullability == Nullability.Default && type is JKClassType) { - val newNullability = calculateNullability(element.parent) - if (newNullability != type.nullability) { - return JKClassTypeImpl(type.classReference, type.parameters, newNullability) + private fun JKType.refineNullability(typeElement: JKTypeElement): JKType { + if (nullability == Nullability.Default && this is JKClassType) { + val newNullability = calculateNullability(typeElement) + if (newNullability != nullability) { + return JKClassTypeImpl(classReference, parameters, newNullability) } } - return type + return this } - private fun mapType(type: JKType, element: JKTreeElement): JKType = when (type) { - is JKJavaPrimitiveType -> mapPrimitiveType(type) - is JKClassType -> mapClassType(type, element) - is JKJavaVoidType -> - kotlinTypeByName( - KotlinBuiltIns.FQ_NAMES.unit.toSafe().asString(), - context.symbolProvider, - Nullability.NotNull - ) - is JKJavaArrayType -> JKClassTypeImpl( - context.symbolProvider.provideByFqName(arrayFqName(type.type)), - if (type.type is JKJavaPrimitiveType) emptyList() else listOf(mapType(type.type, element)), - type.nullability + private fun JKType.fixRawType(typeElement: JKTypeElement) = + when (typeElement.parent) { + is JKKtIsExpression -> + addTypeParametersToRawProjectionType(JKStarProjectionTypeImpl()) + .updateNullability(Nullability.NotNull) + is JKTypeCastExpression -> + addTypeParametersToRawProjectionType(JKStarProjectionTypeImpl()) + + else -> + addTypeParametersToRawProjectionType( + JKStarProjectionTypeImpl() + ) + } + + private fun JKType.mapType(typeElement: JKTypeElement?): JKType = + when (this) { + is JKJavaPrimitiveType -> mapPrimitiveType() + is JKClassType -> mapClassType(typeElement) + is JKJavaVoidType -> + kotlinTypeByName( + KotlinBuiltIns.FQ_NAMES.unit.toSafe().asString(), + context.symbolProvider, + Nullability.NotNull + ) + is JKJavaArrayType -> + JKClassTypeImpl( + context.symbolProvider.provideByFqName(arrayFqName(type)), + if (type is JKJavaPrimitiveType) emptyList() else listOf(type.mapType(typeElement)), + type.nullability + ) + else -> this + } + + private fun JKClassSymbol.mapClassSymbol(typeElement: JKTypeElement?): JKClassSymbol { + val newFqName = typeElement?.let { kotlinCollectionClassName(it) } + ?: kotlinStandardType() + ?: fqName + ?: return this + return context.symbolProvider.provideByFqName(newFqName) + } + + private fun JKClassType.mapClassType(typeElement: JKTypeElement?): JKClassType = + JKClassTypeImpl( + classReference.mapClassSymbol(typeElement), + parameters.map { it.mapType(null) }, + nullability ) - else -> type + + + private fun JKClassSymbol.kotlinCollectionClassName(typeElement: JKTypeElement): String? { + val isStructureMutable = calculateStructureMutability(typeElement) + return if (isStructureMutable) toKotlinMutableTypesMap[fqName] + else toKotlinTypesMap[fqName] } - private fun mapClassType(type: JKClassType, element: JKTreeElement): JKClassType { - val fqName = type.classReference.fqName ?: return type - val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqName)) - ?: mapCollectionClass(fqName)?.let { ClassId.fromString(it) } - ?: return type + private fun JKClassSymbol.kotlinStandardType(): String? = + fqName?.let { + JavaToKotlinClassMap.mapJavaToKotlin(FqName(it))?.asString() + } + + private fun JKJavaPrimitiveType.mapPrimitiveType(): JKClassType { + val fqName = jvmPrimitiveType.primitiveType.typeFqName return JKClassTypeImpl( - context.symbolProvider.provideByFqName(newFqName), - type.parameters.map { mapType(it, element) }, - type.nullability + context.symbolProvider.provideByFqName(ClassId.topLevel(fqName)), + nullability = Nullability.NotNull ) } - private fun mapCollectionClass(fqName: String): String? = - mapOf("java.util.Collection" to "kotlin.collections.Collection")[fqName] - - private fun mapPrimitiveType(type: JKJavaPrimitiveType): JKClassType { - val fqName = type.jvmPrimitiveType.primitiveType.typeFqName - return JKClassTypeImpl(context.symbolProvider.provideByFqName(ClassId.topLevel(fqName)), nullability = Nullability.NotNull) - } - - private fun calculateNullability(parent: JKElement?): Nullability { + private fun calculateNullability(typeElement: JKTypeElement?): Nullability { + val parent = typeElement?.parent ?: return Nullability.Default + val psi = parent.psi ?: return Nullability.Default return when (parent) { - is JKJavaMethod -> typeFlavorCalculator.methodNullability(parent.psi as PsiMethod) - is JKJavaField -> typeFlavorCalculator.variableNullability(parent.psi as PsiVariable) - is JKVariable -> typeFlavorCalculator.variableNullability(parent.psi as PsiVariable) + is JKJavaMethod -> typeFlavorCalculator.methodNullability(psi as PsiMethod) + is JKJavaField -> typeFlavorCalculator.variableNullability(psi as PsiVariable) + is JKVariable -> typeFlavorCalculator.variableNullability(psi as PsiVariable) else -> Nullability.Default } } - private fun arrayFqName(type: JKType): String = if (type is JKJavaPrimitiveType) - PrimitiveType.valueOf(type.jvmPrimitiveType.name).arrayTypeFqName.asString() - else KotlinBuiltIns.FQ_NAMES.array.asString() + private fun calculateStructureMutability(typeElement: JKTypeElement?): Boolean { + val parent = typeElement?.parent ?: return false + val psi = parent.psi ?: return false + return when (parent) { + is JKVariable -> typeFlavorCalculator.variableMutability(psi as PsiVariable) == Mutability.Mutable + is JKMethod -> typeFlavorCalculator.methodMutability(psi as PsiMethod) == Mutability.Mutable + else -> false + } + } + + private fun arrayFqName(type: JKType): String = + if (type is JKJavaPrimitiveType) + PrimitiveType.valueOf(type.jvmPrimitiveType.name).arrayTypeFqName.asString() + else KotlinBuiltIns.FQ_NAMES.array.asString() } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt index 07680bff16f..389db7a382f 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt @@ -56,6 +56,9 @@ interface JKType { val nullability: Nullability } +fun JKType.isNullable(): Boolean = + nullability != Nullability.NotNull + interface JKVarianceTypeParameterType : JKType { val variance: Variance val boundType: JKType diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt b/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt index b6fd0e645e1..99d867569f3 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Utils.kt @@ -142,7 +142,7 @@ fun Converter.convertToKotlinAnalogIdentifier(classQualifiedName: String?, mutab return Identifier.withNoPrototype(kotlinClassName.substringAfterLast('.')) } -private val toKotlinTypesMap: Map = mapOf( +val toKotlinTypesMap: Map = mapOf( CommonClassNames.JAVA_LANG_OBJECT to KotlinBuiltIns.FQ_NAMES.any.asString(), CommonClassNames.JAVA_LANG_BYTE to KotlinBuiltIns.FQ_NAMES._byte.asString(), CommonClassNames.JAVA_LANG_CHARACTER to KotlinBuiltIns.FQ_NAMES._char.asString(),