New J2K: WIP: Type mapper

This commit is contained in:
Simon Ogorodnik
2018-05-22 20:38:03 +03:00
committed by Ilya Kirillov
parent f64c32fd71
commit 7cccb99982
13 changed files with 151 additions and 46 deletions
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.j2k.tree.JKElement
data class ConversionContext(
val symbolProvider: JKSymbolProvider,
val project: Project,
val backAnnotator: (JKElement) -> PsiElement?
)
@@ -18,15 +18,17 @@ package org.jetbrains.kotlin.j2k
import org.jetbrains.kotlin.j2k.conversions.FieldToPropertyConversion import org.jetbrains.kotlin.j2k.conversions.FieldToPropertyConversion
import org.jetbrains.kotlin.j2k.conversions.JavaMethodToKotlinFunctionConversion import org.jetbrains.kotlin.j2k.conversions.JavaMethodToKotlinFunctionConversion
import org.jetbrains.kotlin.j2k.conversions.TypeMappingConversion
import org.jetbrains.kotlin.j2k.tree.JKTreeElement import org.jetbrains.kotlin.j2k.tree.JKTreeElement
object ConversionsRunner { object ConversionsRunner {
fun doApply(trees: List<JKTreeElement>) { fun doApply(trees: List<JKTreeElement>, context: ConversionContext) {
trees.forEach { trees.forEach {
FieldToPropertyConversion().runConversion(it) FieldToPropertyConversion().runConversion(it, context)
JavaMethodToKotlinFunctionConversion().runConversion(it) TypeMappingConversion(context).runConversion(it, context)
JavaMethodToKotlinFunctionConversion().runConversion(it, context)
} }
} }
@@ -0,0 +1,19 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k
class JKSymbolProvider {
//
//
// fun provideSymbol(clz: PsiClass): JKClassSymbol {
//
// }
//
// fun provideSymbol(clz: KtClassOrObject): JKClassSymbol {
//
// }
}
@@ -34,6 +34,8 @@ class JavaToJKTreeBuilder {
private val modifierMapper = ModifierMapper() private val modifierMapper = ModifierMapper()
val backAnnotation = mutableMapOf<JKElement, PsiElement>()
val symbols = mutableMapOf<PsiElement, JKSymbol>() val symbols = mutableMapOf<PsiElement, JKSymbol>()
val symbolsByDeclaration = mutableMapOf<JKDeclaration, JKSymbol>() val symbolsByDeclaration = mutableMapOf<JKDeclaration, JKSymbol>()
@@ -152,11 +154,16 @@ class JavaToJKTreeBuilder {
fun PsiReferenceExpression.toJK(): JKExpression { fun PsiReferenceExpression.toJK(): JKExpression {
val impl = this as PsiReferenceExpressionImpl val impl = this as PsiReferenceExpressionImpl
if (impl.resolve() !is PsiField) {
return JKNullLiteral() // TODO !!!
}
val access = JKJavaFieldAccessExpressionImpl(JKMultiverseFieldSymbol(impl.resolve() as PsiField)) val access = JKJavaFieldAccessExpressionImpl(JKMultiverseFieldSymbol(impl.resolve() as PsiField))
return if (impl.findChildByRole(ChildRole.DOT) != null) { return when {
JKQualifiedExpressionImpl((impl.qualifier as PsiExpression).toJK(), JKJavaQualifierImpl.DOT, access) impl.findChildByRole(ChildRole.DOT) != null &&
} else { (impl.qualifierExpression as? PsiReferenceExpression)?.resolve() !is PsiClass ->
access JKQualifiedExpressionImpl((impl.qualifier as PsiExpression).toJK(), JKJavaQualifierImpl.DOT, access)
else -> access
} }
} }
@@ -191,7 +198,7 @@ class JavaToJKTreeBuilder {
} }
fun PsiTypeCastExpression.toJK(): JKExpression { fun PsiTypeCastExpression.toJK(): JKExpression {
return JKTypeCastExpressionImpl(operand?.toJK() ?: TODO(), castType?.type?.toJK() ?: TODO()) return JKTypeCastExpressionImpl(operand?.toJK() ?: TODO(), castType?.toJK() ?: TODO())
} }
fun PsiParenthesizedExpression.toJK(): JKExpression { fun PsiParenthesizedExpression.toJK(): JKExpression {
@@ -202,9 +209,18 @@ class JavaToJKTreeBuilder {
return JKExpressionListImpl(this?.expressions?.map { it.toJK() } ?: emptyList()) return JKExpressionListImpl(this?.expressions?.map { it.toJK() } ?: emptyList())
} }
fun PsiTypeElement.toJK(): JKType {
return type.toJK().also {
backAnnotation[it] = this
}
}
fun PsiType.toJK(): JKType { fun PsiType.toJK(): JKType {
return when (this) { return when (this) {
is PsiClassType -> JKClassTypeImpl(resolve()?.let { provideSymbol(it) as? JKClassSymbol }!!, parameters.map { it.toJK() }) is PsiClassType -> JKClassTypeImpl(
resolve()?.let { provideSymbol(it) as? JKClassSymbol }!!,
parameters.map { it.toJK() }
)
is PsiArrayType -> JKJavaArrayTypeImpl(componentType.toJK()) is PsiArrayType -> JKJavaArrayTypeImpl(componentType.toJK())
is PsiPrimitiveType -> when (presentableText) { is PsiPrimitiveType -> when (presentableText) {
"int" -> JKJavaPrimitiveTypeImpl.INT "int" -> JKJavaPrimitiveTypeImpl.INT
@@ -238,7 +254,7 @@ class JavaToJKTreeBuilder {
fun PsiField.toJK(): JKJavaField { fun PsiField.toJK(): JKJavaField {
return JKJavaFieldImpl( return JKJavaFieldImpl(
with(modifierMapper) { modifierList.toJK() }, with(modifierMapper) { modifierList.toJK() },
with(expressionTreeMapper) { type.toJK() }, with(expressionTreeMapper) { typeElement?.toJK() } ?: TODO(),
JKNameIdentifierImpl(this.name), JKNameIdentifierImpl(this.name),
with(expressionTreeMapper) { initializer?.toJK() } ?: TODO() with(expressionTreeMapper) { initializer?.toJK() } ?: TODO()
).also { ).also {
@@ -262,7 +278,7 @@ class JavaToJKTreeBuilder {
} }
fun PsiParameter.toJK(): JKValueArgumentImpl { fun PsiParameter.toJK(): JKValueArgumentImpl {
return JKValueArgumentImpl(with(expressionTreeMapper) { type.toJK() }, name!!) return JKValueArgumentImpl(with(expressionTreeMapper) { typeElement?.toJK() } ?: TODO(), name!!)
} }
fun PsiCodeBlock.toJK(): JKBlock { fun PsiCodeBlock.toJK(): JKBlock {
@@ -42,7 +42,13 @@ class NewJavaToKotlinConverter(
println(fileTrees.prettyPrintTrees()) println(fileTrees.prettyPrintTrees())
ConversionsRunner.doApply(fileTrees) val context = ConversionContext(
JKSymbolProvider(),
project,
{ treeBuilder.backAnnotation[it] }
)
ConversionsRunner.doApply(fileTrees, context)
val resultTree = fileTrees.prettyPrintTrees() val resultTree = fileTrees.prettyPrintTrees()
@@ -16,12 +16,13 @@
package org.jetbrains.kotlin.j2k.conversions package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.JKTreeElement import org.jetbrains.kotlin.j2k.tree.JKTreeElement
abstract class BaseConversion { abstract class BaseConversion {
/** /**
* @return true if something changed * @return true if something changed
*/ */
abstract fun runConversion(treeRoot: JKTreeElement): Boolean abstract fun runConversion(treeRoot: JKTreeElement, context: ConversionContext): Boolean
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.j2k.conversions package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.* import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
@@ -16,7 +17,7 @@ class FieldToPropertyConversion : MatchBasedConversion() {
var somethingChanged = false var somethingChanged = false
override fun runConversion(treeRoot: JKTreeElement): Boolean { override fun runConversion(treeRoot: JKTreeElement, context: ConversionContext): Boolean {
val root = applyToElement(treeRoot) val root = applyToElement(treeRoot)
assert(root === treeRoot) assert(root === treeRoot)
return somethingChanged return somethingChanged
@@ -16,13 +16,14 @@
package org.jetbrains.kotlin.j2k.conversions package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.JKTreeElement import org.jetbrains.kotlin.j2k.tree.JKTreeElement
import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitorVoid import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitorVoid
abstract class TransformerBasedConversion : BaseConversion(), JKVisitorVoid { abstract class TransformerBasedConversion : BaseConversion(), JKVisitorVoid {
protected var somethingChanged = false protected var somethingChanged = false
override fun runConversion(treeRoot: JKTreeElement): Boolean { override fun runConversion(treeRoot: JKTreeElement, context: ConversionContext): Boolean {
somethingChanged = false somethingChanged = false
treeRoot.accept(this, null) treeRoot.accept(this, null)
return somethingChanged return somethingChanged
@@ -5,17 +5,32 @@
package org.jetbrains.kotlin.j2k.conversions package org.jetbrains.kotlin.j2k.conversions
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReferenceExpression
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.j2k.tree.JKClassType import org.jetbrains.kotlin.j2k.tree.JKClassType
import org.jetbrains.kotlin.j2k.tree.JKJavaPrimitiveType import org.jetbrains.kotlin.j2k.tree.JKJavaPrimitiveType
import org.jetbrains.kotlin.j2k.tree.JKTreeElement import org.jetbrains.kotlin.j2k.tree.JKTreeElement
import org.jetbrains.kotlin.j2k.tree.JKType import org.jetbrains.kotlin.j2k.tree.JKType
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
import org.jetbrains.kotlin.j2k.tree.impl.JKClassTypeImpl
import org.jetbrains.kotlin.j2k.tree.impl.JKMultiverseKtClassSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
class TypeMappingConversion : MatchBasedConversion() { class TypeMappingConversion(val context: ConversionContext) : MatchBasedConversion() {
override fun onElementChanged(new: JKTreeElement, old: JKTreeElement) { override fun onElementChanged(new: JKTreeElement, old: JKTreeElement) {
somethingChanged = true somethingChanged = true
} }
override fun runConversion(treeRoot: JKTreeElement): Boolean { override fun runConversion(treeRoot: JKTreeElement, context: ConversionContext): Boolean {
val root = applyToElement(treeRoot) val root = applyToElement(treeRoot)
assert(root === treeRoot) assert(root === treeRoot)
return somethingChanged return somethingChanged
@@ -32,14 +47,37 @@ class TypeMappingConversion : MatchBasedConversion() {
} }
} }
fun fqNameRef(classId: ClassId, element: PsiElement): PsiReferenceExpression? {
return KtPsiFactory(element)
.createExpressionCodeFragment(classId.asString(), element)
.findChildByClass(PsiReferenceExpression::class.java)
}
fun classTypeByFqName(
contextElement: PsiElement?,
fqName: ClassId,
parameters: List<JKType>,
nullability: Nullability = Nullability.Default
): JKType? {
contextElement ?: return null
val newTarget = fqNameRef(fqName, contextElement)?.resolve() as? KtClassOrObject ?: return null
val newSymbol = JKMultiverseKtClassSymbol(newTarget)
return JKClassTypeImpl(newSymbol, parameters, nullability)
}
fun mapClassType(type: JKClassType): JKType { fun mapClassType(type: JKClassType): JKType {
// if (type.classReference?.target) { val fqNameStr = (type.classReference as? JKClassSymbol)?.fqName ?: return type
//
// } val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqNameStr)) ?: return type
return type
return classTypeByFqName(context.backAnnotator(type), newFqName, type.parameters, type.nullability) ?: type
} }
fun mapPrimitiveType(type: JKJavaPrimitiveType): JKType { fun mapPrimitiveType(type: JKJavaPrimitiveType): JKType {
return type val fqName = JvmPrimitiveType.get(type.name).primitiveType.typeFqName
return classTypeByFqName(context.backAnnotator(type), ClassId.topLevel(fqName), emptyList()) ?: type
} }
} }
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.j2k.tree package org.jetbrains.kotlin.j2k.tree
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitorVoid import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitorVoid
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
@@ -77,12 +78,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) {
/*if ((type.classReference as? JKBindableSymbol)?.isBound == true) { printer.println((type.classReference as? JKClassSymbol)?.fqName ?: type.classReference?.let { it::class } ?: "Unbound")
printer.println(type.classReference?.element?.name?.value)
} else {
printer.println("Unbound")
}*/
} }
} }
printer.println("\"") printer.println("\"")
@@ -20,21 +20,21 @@ import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitor import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitor
class JKJavaFieldImpl( class JKJavaFieldImpl(
override var modifierList: JKModifierList, modifierList: JKModifierList,
override var type: JKType, type: JKType,
override var name: JKNameIdentifier, name: JKNameIdentifier,
override var initializer: JKExpression initializer: JKExpression
) : JKJavaField, JKElementBase() { ) : JKJavaField, JKBranchElementBase() {
override val valid: Boolean override val valid: Boolean
get() = true get() = true
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitJavaField(this, data) override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitJavaField(this, data)
override fun <D> acceptChildren(visitor: JKVisitor<Unit, D>, data: D) { override var initializer: JKExpression by child(initializer)
type.accept(visitor, data) override var modifierList: JKModifierList by child(modifierList)
name.accept(visitor, data) override var name: JKNameIdentifier by child(name)
initializer.accept(visitor, data) override var type: JKType by child(type)
}
} }
class JKJavaLiteralExpressionImpl( class JKJavaLiteralExpressionImpl(
@@ -204,13 +204,13 @@ class JKTypeCastExpressionImpl(override var expression: JKExpression, override v
class JKClassTypeImpl( class JKClassTypeImpl(
override val classReference: JKClassSymbol, override val classReference: JKClassSymbol,
override val parameters: List<JKType>, parameters: List<JKType>,
override val nullability: Nullability = Nullability.Default override val nullability: Nullability = Nullability.Default
) : JKClassType, JKElementBase() { ) : JKClassType, JKBranchElementBase() {
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitClassType(this, data) override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitClassType(this, data)
override fun <D> acceptChildren(visitor: JKVisitor<Unit, D>, data: D) { override var parameters: List<JKType> by children(parameters)
}
} class JKNullLiteral : JKExpression, JKElementBase()
}
@@ -11,6 +11,8 @@ import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.j2k.tree.JKClass import org.jetbrains.kotlin.j2k.tree.JKClass
import org.jetbrains.kotlin.j2k.tree.JKField import org.jetbrains.kotlin.j2k.tree.JKField
import org.jetbrains.kotlin.j2k.tree.JKMethod import org.jetbrains.kotlin.j2k.tree.JKMethod
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
interface JKSymbol { interface JKSymbol {
val target: Any val target: Any
@@ -18,7 +20,7 @@ interface JKSymbol {
} }
interface JKClassSymbol : JKSymbol { interface JKClassSymbol : JKSymbol {
val fqName: String val fqName: String?
} }
interface JKMethodSymbol : JKSymbol { interface JKMethodSymbol : JKSymbol {
@@ -39,8 +41,15 @@ class JKUniverseClassSymbol(override val target: JKClass) : JKClassSymbol {
class JKMultiverseClassSymbol(override val target: PsiClass) : JKClassSymbol { class JKMultiverseClassSymbol(override val target: PsiClass) : JKClassSymbol {
override val declaredIn: JKSymbol override val declaredIn: JKSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override val fqName: String override val fqName: String?
get() = target.name!! get() = target.qualifiedName
}
class JKMultiverseKtClassSymbol(override val target: KtClassOrObject): JKClassSymbol {
override val declaredIn: JKSymbol
get() = TODO("not implemented")
override val fqName: String?
get() = target.fqName?.asString()
} }