New J2K: Fix TypeMappingConversion
This commit is contained in:
committed by
Ilya Kirillov
parent
6b889bdf57
commit
f3cb76ff56
@@ -12,15 +12,14 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.j2k.*
|
import org.jetbrains.kotlin.j2k.*
|
||||||
|
import org.jetbrains.kotlin.j2k.ast.Mutability
|
||||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||||
import org.jetbrains.kotlin.j2k.tree.*
|
import org.jetbrains.kotlin.j2k.tree.*
|
||||||
import org.jetbrains.kotlin.j2k.tree.impl.*
|
import org.jetbrains.kotlin.j2k.tree.impl.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
|
||||||
|
|
||||||
class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
||||||
|
|
||||||
private val typeFlavorCalculator = TypeFlavorCalculator(object : TypeFlavorConverterFacade {
|
private val typeFlavorCalculator = TypeFlavorCalculator(object : TypeFlavorConverterFacade {
|
||||||
override val referenceSearcher: ReferenceSearcher
|
override val referenceSearcher: ReferenceSearcher
|
||||||
get() = context.converter.converterServices.oldServices.referenceSearcher
|
get() = context.converter.converterServices.oldServices.referenceSearcher
|
||||||
@@ -30,75 +29,132 @@ class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicabl
|
|||||||
get() = context.converter.converterServices.oldServices.resolverForConverter
|
get() = context.converter.converterServices.oldServices.resolverForConverter
|
||||||
|
|
||||||
override fun inConversionScope(element: PsiElement): Boolean = context.inConversionContext(element)
|
override fun inConversionScope(element: PsiElement): Boolean = context.inConversionContext(element)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||||
return recurse(
|
return when (element) {
|
||||||
if (element is JKTypeElement) {
|
is JKTypeElement -> {
|
||||||
val newType = refineNullability(mapType(element.type, element), element)
|
val newType = element.type
|
||||||
|
.fixRawType(element)
|
||||||
|
.mapType(element)
|
||||||
|
.refineNullability(element)
|
||||||
JKTypeElementImpl(newType)
|
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 {
|
private fun JKType.refineNullability(typeElement: JKTypeElement): JKType {
|
||||||
if (type.nullability == Nullability.Default && type is JKClassType) {
|
if (nullability == Nullability.Default && this is JKClassType) {
|
||||||
val newNullability = calculateNullability(element.parent)
|
val newNullability = calculateNullability(typeElement)
|
||||||
if (newNullability != type.nullability) {
|
if (newNullability != nullability) {
|
||||||
return JKClassTypeImpl(type.classReference, type.parameters, newNullability)
|
return JKClassTypeImpl(classReference, parameters, newNullability)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return type
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mapType(type: JKType, element: JKTreeElement): JKType = when (type) {
|
private fun JKType.fixRawType(typeElement: JKTypeElement) =
|
||||||
is JKJavaPrimitiveType -> mapPrimitiveType(type)
|
when (typeElement.parent) {
|
||||||
is JKClassType -> mapClassType(type, element)
|
is JKKtIsExpression ->
|
||||||
is JKJavaVoidType ->
|
addTypeParametersToRawProjectionType(JKStarProjectionTypeImpl())
|
||||||
kotlinTypeByName(
|
.updateNullability(Nullability.NotNull)
|
||||||
KotlinBuiltIns.FQ_NAMES.unit.toSafe().asString(),
|
is JKTypeCastExpression ->
|
||||||
context.symbolProvider,
|
addTypeParametersToRawProjectionType(JKStarProjectionTypeImpl())
|
||||||
Nullability.NotNull
|
|
||||||
)
|
else ->
|
||||||
is JKJavaArrayType -> JKClassTypeImpl(
|
addTypeParametersToRawProjectionType(
|
||||||
context.symbolProvider.provideByFqName(arrayFqName(type.type)),
|
JKStarProjectionTypeImpl()
|
||||||
if (type.type is JKJavaPrimitiveType) emptyList() else listOf(mapType(type.type, element)),
|
)
|
||||||
type.nullability
|
}
|
||||||
|
|
||||||
|
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 {
|
private fun JKClassSymbol.kotlinStandardType(): String? =
|
||||||
val fqName = type.classReference.fqName ?: return type
|
fqName?.let {
|
||||||
val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqName))
|
JavaToKotlinClassMap.mapJavaToKotlin(FqName(it))?.asString()
|
||||||
?: mapCollectionClass(fqName)?.let { ClassId.fromString(it) }
|
}
|
||||||
?: return type
|
|
||||||
|
private fun JKJavaPrimitiveType.mapPrimitiveType(): JKClassType {
|
||||||
|
val fqName = jvmPrimitiveType.primitiveType.typeFqName
|
||||||
return JKClassTypeImpl(
|
return JKClassTypeImpl(
|
||||||
context.symbolProvider.provideByFqName(newFqName),
|
context.symbolProvider.provideByFqName(ClassId.topLevel(fqName)),
|
||||||
type.parameters.map { mapType(it, element) },
|
nullability = Nullability.NotNull
|
||||||
type.nullability
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mapCollectionClass(fqName: String): String? =
|
private fun calculateNullability(typeElement: JKTypeElement?): Nullability {
|
||||||
mapOf("java.util.Collection" to "kotlin.collections.Collection")[fqName]
|
val parent = typeElement?.parent ?: return Nullability.Default
|
||||||
|
val psi = parent.psi ?: return Nullability.Default
|
||||||
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 {
|
|
||||||
return when (parent) {
|
return when (parent) {
|
||||||
is JKJavaMethod -> typeFlavorCalculator.methodNullability(parent.psi as PsiMethod)
|
is JKJavaMethod -> typeFlavorCalculator.methodNullability(psi as PsiMethod)
|
||||||
is JKJavaField -> typeFlavorCalculator.variableNullability(parent.psi as PsiVariable)
|
is JKJavaField -> typeFlavorCalculator.variableNullability(psi as PsiVariable)
|
||||||
is JKVariable -> typeFlavorCalculator.variableNullability(parent.psi as PsiVariable)
|
is JKVariable -> typeFlavorCalculator.variableNullability(psi as PsiVariable)
|
||||||
else -> Nullability.Default
|
else -> Nullability.Default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun arrayFqName(type: JKType): String = if (type is JKJavaPrimitiveType)
|
private fun calculateStructureMutability(typeElement: JKTypeElement?): Boolean {
|
||||||
PrimitiveType.valueOf(type.jvmPrimitiveType.name).arrayTypeFqName.asString()
|
val parent = typeElement?.parent ?: return false
|
||||||
else KotlinBuiltIns.FQ_NAMES.array.asString()
|
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()
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,9 @@ interface JKType {
|
|||||||
val nullability: Nullability
|
val nullability: Nullability
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun JKType.isNullable(): Boolean =
|
||||||
|
nullability != Nullability.NotNull
|
||||||
|
|
||||||
interface JKVarianceTypeParameterType : JKType {
|
interface JKVarianceTypeParameterType : JKType {
|
||||||
val variance: Variance
|
val variance: Variance
|
||||||
val boundType: JKType
|
val boundType: JKType
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ fun Converter.convertToKotlinAnalogIdentifier(classQualifiedName: String?, mutab
|
|||||||
return Identifier.withNoPrototype(kotlinClassName.substringAfterLast('.'))
|
return Identifier.withNoPrototype(kotlinClassName.substringAfterLast('.'))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val toKotlinTypesMap: Map<String, String> = mapOf(
|
val toKotlinTypesMap: Map<String, String> = mapOf(
|
||||||
CommonClassNames.JAVA_LANG_OBJECT to KotlinBuiltIns.FQ_NAMES.any.asString(),
|
CommonClassNames.JAVA_LANG_OBJECT to KotlinBuiltIns.FQ_NAMES.any.asString(),
|
||||||
CommonClassNames.JAVA_LANG_BYTE to KotlinBuiltIns.FQ_NAMES._byte.asString(),
|
CommonClassNames.JAVA_LANG_BYTE to KotlinBuiltIns.FQ_NAMES._byte.asString(),
|
||||||
CommonClassNames.JAVA_LANG_CHARACTER to KotlinBuiltIns.FQ_NAMES._char.asString(),
|
CommonClassNames.JAVA_LANG_CHARACTER to KotlinBuiltIns.FQ_NAMES._char.asString(),
|
||||||
|
|||||||
Reference in New Issue
Block a user