From 2f1c621b5f7b5cf227efac12812863bdee743748 Mon Sep 17 00:00:00 2001 From: Dimach Date: Tue, 31 Jul 2018 17:09:49 +0300 Subject: [PATCH] New J2K: Improve type system and nullability computation in type mapper --- .../kotlin/j2k/JavaToJKTreeBuilder.kt | 8 +- .../jetbrains/kotlin/j2k/NewCodeBuilder.kt | 25 ++--- .../j2k/conversions/TypeMappingConversion.kt | 105 +++++++++--------- .../kotlin/j2k/tree/DebugTreePrinter.kt | 2 +- .../org/jetbrains/kotlin/j2k/tree/impl/j.kt | 5 +- .../org/jetbrains/kotlin/j2k/tree/impl/jk.kt | 7 +- .../org/jetbrains/kotlin/j2k/tree/impl/k.kt | 3 +- .../org/jetbrains/kotlin/j2k/tree/markers.kt | 5 +- 8 files changed, 80 insertions(+), 80 deletions(-) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt index bf8a708c86a..4b975b4b7ef 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/JavaToJKTreeBuilder.kt @@ -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() } } diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt index 830407ad3d5..044bd95d29f 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt @@ -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) { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt index e720b4a9039..4de489432f6 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt @@ -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, - 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()!!)!! + ), + 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() } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/DebugTreePrinter.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/DebugTreePrinter.kt index fd97b7bb720..f20255ede42 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/DebugTreePrinter.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/DebugTreePrinter.kt @@ -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) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt index a783cb01e99..ca6a192ddef 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/j.kt @@ -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 { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt index 6401b824f5d..b3e2ed3eb2d 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/jk.kt @@ -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 accept(visitor: JKVisitor, data: D): R = visitor.visitTypeElement(this, data) } class JKClassTypeImpl( override val classReference: JKClassSymbol, - override var parameters: List = emptyList(), + override val parameters: List = emptyList(), override val nullability: Nullability = Nullability.Default ) : JKClassType class JKUnresolvedClassType( val name: String, - override var parameters: List, + override val parameters: List, 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()) override val expression: JKExpression by child(expression) override val arguments: JKExpressionList by child(arguments) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt index 1db146357a3..b882ef53996 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt @@ -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, diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt index b5224252072..b3694dc3f5f 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/markers.kt @@ -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 {