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() } 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 {