New J2K: Improve type system and nullability computation in type mapper

This commit is contained in:
Dimach
2018-07-31 17:09:49 +03:00
committed by Ilya Kirillov
parent abc4104ba7
commit 2f1c621b5f
8 changed files with 80 additions and 80 deletions
@@ -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 {