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