New J2K: Improve type system and nullability computation in type mapper
This commit is contained in:
@@ -285,6 +285,7 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) {
|
||||
with(expressionTreeMapper) { initializer.toJK() }
|
||||
).also {
|
||||
symbolProvider.provideUniverseSymbol(this, it)
|
||||
backAnnotation[it] = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,6 +303,7 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) {
|
||||
).also {
|
||||
backAnnotation[it] = this
|
||||
symbolProvider.provideUniverseSymbol(this, it)
|
||||
backAnnotation[it] = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +318,7 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) {
|
||||
JKNameIdentifierImpl(name!!),
|
||||
with(modifierMapper) { modifierList.toJK() }).also {
|
||||
symbolProvider.provideUniverseSymbol(this, it)
|
||||
backAnnotation[it] = this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +334,10 @@ class JavaToJKTreeBuilder(var symbolProvider: JKSymbolProvider) {
|
||||
with(expressionTreeMapper) { it.typeElement.toJK() },
|
||||
JKNameIdentifierImpl(it.name ?: TODO()),
|
||||
with(expressionTreeMapper) { it.initializer.toJK() }
|
||||
).also { i -> symbolProvider.provideUniverseSymbol(it, i) }
|
||||
).also { i ->
|
||||
symbolProvider.provideUniverseSymbol(it, i)
|
||||
backAnnotation[i] = it
|
||||
}
|
||||
} else TODO()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.j2k.tree.impl.*
|
||||
import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitorVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
|
||||
class NewCodeBuilder {
|
||||
|
||||
@@ -264,23 +265,15 @@ class NewCodeBuilder {
|
||||
}
|
||||
|
||||
override fun visitExpressionList(expressionList: JKExpressionList) {
|
||||
expressionList.expressions.firstOrNull()?.accept(this)
|
||||
for (i in 1..expressionList.expressions.lastIndex) {
|
||||
printer.printWithNoIndent(", ")
|
||||
expressionList.expressions[i].accept(this)
|
||||
}
|
||||
renderList(expressionList.expressions) { it.accept(this) }
|
||||
}
|
||||
|
||||
override fun visitMethodCallExpression(methodCallExpression: JKMethodCallExpression) {
|
||||
printer.printWithNoIndent(FqName(methodCallExpression.identifier.fqName).shortName().asString())
|
||||
if (methodCallExpression.typeArguments.isNotEmpty()) {
|
||||
printer.printWithNoIndent("<")
|
||||
methodCallExpression.typeArguments.firstOrNull()?.accept(this)
|
||||
for (i in 1..methodCallExpression.typeArguments.lastIndex) {
|
||||
printer.printWithNoIndent(", ")
|
||||
methodCallExpression.typeArguments[i].accept(this)
|
||||
printer.par(ANGLE) {
|
||||
renderList(methodCallExpression.typeArguments) { it.accept(this) }
|
||||
}
|
||||
printer.printWithNoIndent(">")
|
||||
}
|
||||
printer.par {
|
||||
methodCallExpression.arguments.accept(this)
|
||||
@@ -341,9 +334,7 @@ class NewCodeBuilder {
|
||||
}
|
||||
if (type is JKParametrizedType && type.parameters.isNotEmpty()) {
|
||||
printer.par(ANGLE) {
|
||||
renderList(type.parameters) {
|
||||
renderType(it)
|
||||
}
|
||||
renderList(type.parameters, renderElement = ::renderType)
|
||||
}
|
||||
}
|
||||
when (type.nullability) {
|
||||
@@ -450,9 +441,9 @@ class NewCodeBuilder {
|
||||
}
|
||||
|
||||
override fun visitBlockStatement(blockStatement: JKBlockStatement) {
|
||||
printer.printWithNoIndent("{ ")
|
||||
blockStatement.block.accept(this)
|
||||
printer.printWithNoIndent(" }")
|
||||
printer.par(CURVED) {
|
||||
blockStatement.block.accept(this)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun visitParameter(parameter: JKParameter) {
|
||||
|
||||
@@ -9,17 +9,16 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiVariable
|
||||
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.Nullability
|
||||
import org.jetbrains.kotlin.j2k.tree.*
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKClassTypeImpl
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKJavaVoidType
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKTypeElementImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
||||
|
||||
@@ -36,64 +35,66 @@ class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicabl
|
||||
})
|
||||
|
||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||
return if (element is JKTypeElement) {
|
||||
val type = element.type
|
||||
when (type) {
|
||||
is JKJavaPrimitiveType -> mapPrimitiveType(type, element)
|
||||
is JKClassType -> mapClassType(type, element)
|
||||
is JKJavaVoidType -> classTypeByFqName(
|
||||
context.backAnnotator(element),
|
||||
ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.unit.toSafe()),
|
||||
emptyList(),
|
||||
Nullability.NotNull
|
||||
)?.let { JKTypeElementImpl(it) } ?: element
|
||||
else -> applyRecursive(element, this::applyToElement)
|
||||
return recurse(
|
||||
if (element is JKTypeElement) {
|
||||
val newType = refineNullability(mapType(element.type, element), element)
|
||||
JKTypeElementImpl(newType)
|
||||
} else 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)
|
||||
}
|
||||
} else applyRecursive(element, this::applyToElement)
|
||||
}
|
||||
return type
|
||||
}
|
||||
|
||||
private fun classTypeByFqName(
|
||||
contextElement: PsiElement?,
|
||||
fqName: ClassId,
|
||||
parameters: List<JKType>,
|
||||
nullability: Nullability = Nullability.Default
|
||||
): JKType? {
|
||||
contextElement ?: return null
|
||||
val newTarget = resolveFqName(fqName, contextElement) as? KtClassOrObject ?: return null
|
||||
|
||||
return JKClassTypeImpl(context.symbolProvider.provideDirectSymbol(newTarget) as JKClassSymbol, parameters, nullability)
|
||||
private fun mapType(type: JKType, element: JKTreeElement): JKType = when (type) {
|
||||
is JKJavaPrimitiveType -> mapPrimitiveType(type)
|
||||
is JKClassType -> mapClassType(type, element)
|
||||
is JKJavaVoidType -> JKClassTypeImpl(
|
||||
context.symbolProvider.provideByFqName(
|
||||
ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.unit.toSafe()),
|
||||
context.backAnnotator.invoke(element.parentOfType<JKClass>()!!)!!
|
||||
),
|
||||
nullability = 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
|
||||
)
|
||||
else -> type
|
||||
}
|
||||
|
||||
private fun calculateNullability(typeElement: JKTypeElement): Nullability {
|
||||
val parent = typeElement.parent
|
||||
private fun mapClassType(type: JKClassType, element: JKTreeElement): JKClassType {
|
||||
val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(type.classReference.fqName ?: return type)) ?: return type
|
||||
return JKClassTypeImpl(
|
||||
context.symbolProvider.provideByFqName(newFqName),
|
||||
type.parameters.map { mapType(it, element) },
|
||||
type.nullability
|
||||
)
|
||||
}
|
||||
|
||||
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) {
|
||||
is JKJavaMethod -> typeFlavorCalculator.methodNullability(context.backAnnotator(typeElement)!!.parent as PsiMethod)
|
||||
is JKJavaField -> typeFlavorCalculator.variableNullability(context.backAnnotator(typeElement)!!.parent as PsiVariable)
|
||||
is JKLocalVariable -> typeFlavorCalculator.variableNullability(context.backAnnotator(typeElement)!!.parent as PsiVariable)
|
||||
is JKJavaMethod -> typeFlavorCalculator.methodNullability(context.backAnnotator(parent) as PsiMethod)
|
||||
is JKJavaField -> typeFlavorCalculator.variableNullability(context.backAnnotator(parent) as PsiVariable)
|
||||
is JKLocalVariable -> typeFlavorCalculator.variableNullability(context.backAnnotator(parent) as PsiVariable)
|
||||
else -> Nullability.Default
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapClassType(type: JKClassType, typeElement: JKTypeElement): JKTypeElement {
|
||||
val fqNameStr = (type.classReference as? JKClassSymbol)?.fqName ?: return typeElement
|
||||
|
||||
val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqNameStr)) ?: return typeElement
|
||||
|
||||
return classTypeByFqName(context.backAnnotator(typeElement), newFqName, type.parameters, calculateNullability(typeElement))?.let {
|
||||
JKTypeElementImpl(it)
|
||||
} ?: typeElement
|
||||
}
|
||||
|
||||
private fun mapPrimitiveType(type: JKJavaPrimitiveType, typeElement: JKTypeElement): JKTypeElement {
|
||||
val fqName = type.jvmPrimitiveType.primitiveType.typeFqName
|
||||
|
||||
val convertedType = classTypeByFqName(
|
||||
context.backAnnotator(typeElement),
|
||||
ClassId.topLevel(fqName),
|
||||
emptyList(),
|
||||
nullability = Nullability.NotNull
|
||||
) ?: return typeElement
|
||||
|
||||
return JKTypeElementImpl(convertedType)
|
||||
}
|
||||
private fun arrayFqName(type: JKType): String = if (type is JKJavaPrimitiveType)
|
||||
PrimitiveType.valueOf(type.jvmPrimitiveType.name).arrayTypeFqName.asString()
|
||||
else KotlinBuiltIns.FQ_NAMES.array.asString()
|
||||
}
|
||||
@@ -79,7 +79,7 @@ private class DebugTreePrinter : JKVisitorVoid {
|
||||
printer.println(type.classNameWithoutJK(), " \"")
|
||||
printer.indented {
|
||||
if (type is JKClassType) {
|
||||
printer.println((type.classReference as? JKClassSymbol)?.fqName ?: type.classReference?.let { it::class } ?: "Unbound")
|
||||
printer.println((type.classReference as? JKClassSymbol)?.fqName ?: type.classReference.let { it::class })
|
||||
}
|
||||
if (type is JKJavaPrimitiveType) {
|
||||
printer.println(type.jvmPrimitiveType.javaKeywordName)
|
||||
|
||||
@@ -146,11 +146,12 @@ sealed class JKJavaPrimitiveTypeImpl(override val jvmPrimitiveType: JvmPrimitive
|
||||
}
|
||||
|
||||
object JKJavaVoidType : JKType {
|
||||
override val nullability: Nullability
|
||||
override var nullability: Nullability
|
||||
get() = Nullability.NotNull
|
||||
set(it) {}
|
||||
}
|
||||
|
||||
class JKJavaArrayTypeImpl(override val type: JKType, override val nullability: Nullability = Nullability.Default) : JKJavaArrayType {
|
||||
class JKJavaArrayTypeImpl(override val type: JKType, override var nullability: Nullability = Nullability.Default) : JKJavaArrayType {
|
||||
}
|
||||
|
||||
class JKReturnStatementImpl(expression: JKExpression) : JKBranchElementBase(), JKReturnStatement {
|
||||
|
||||
@@ -177,20 +177,20 @@ class JKTypeCastExpressionImpl(override var expression: JKExpression, type: JKTy
|
||||
override var type by child(type)
|
||||
}
|
||||
|
||||
class JKTypeElementImpl(override val type: JKType) : JKTypeElement, JKElementBase() {
|
||||
class JKTypeElementImpl(override var type: JKType) : JKTypeElement, JKElementBase() {
|
||||
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitTypeElement(this, data)
|
||||
}
|
||||
|
||||
class JKClassTypeImpl(
|
||||
override val classReference: JKClassSymbol,
|
||||
override var parameters: List<JKType> = emptyList(),
|
||||
override val parameters: List<JKType> = emptyList(),
|
||||
override val nullability: Nullability = Nullability.Default
|
||||
) : JKClassType
|
||||
|
||||
|
||||
class JKUnresolvedClassType(
|
||||
val name: String,
|
||||
override var parameters: List<JKType>,
|
||||
override val parameters: List<JKType>,
|
||||
override val nullability: Nullability = Nullability.Default
|
||||
) : JKParametrizedType
|
||||
|
||||
@@ -354,6 +354,7 @@ class JKDelegationConstructorCallImpl(
|
||||
expression: JKExpression,
|
||||
arguments: JKExpressionList
|
||||
) : JKBranchElementBase(), JKDelegationConstructorCall {
|
||||
override var typeArguments by children(emptyList<JKTypeElement>())
|
||||
override val expression: JKExpression by child(expression)
|
||||
override val arguments: JKExpressionList by child(arguments)
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
package org.jetbrains.kotlin.j2k.tree.impl
|
||||
|
||||
import com.intellij.psi.JavaTokenType
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
import org.jetbrains.kotlin.j2k.tree.*
|
||||
import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitor
|
||||
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
|
||||
class JKKtPropertyImpl(
|
||||
modifierList: JKModifierList,
|
||||
@@ -184,6 +184,7 @@ object JKContextType : JKType {
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.Default
|
||||
}
|
||||
|
||||
class JKKtConstructorImpl(
|
||||
name: JKNameIdentifier,
|
||||
parameters: List<JKParameter>,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.j2k.tree
|
||||
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKSymbol
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
|
||||
interface JKOperator {
|
||||
@@ -55,8 +55,7 @@ interface JKParametrizedType : JKType {
|
||||
}
|
||||
|
||||
interface JKClassType : JKParametrizedType {
|
||||
val classReference: JKSymbol?
|
||||
override val nullability: Nullability
|
||||
val classReference: JKClassSymbol
|
||||
}
|
||||
|
||||
interface JKJavaPrimitiveType : JKType {
|
||||
|
||||
Reference in New Issue
Block a user