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.JavaMethodToKotlinFunctionConversion
import org.jetbrains.kotlin.j2k.conversions.TypeMappingConversion
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
object ConversionsRunner {
fun doApply(trees: List<JKTreeElement>) {
fun doApply(trees: List<JKTreeElement>, context: ConversionContext) {
trees.forEach {
FieldToPropertyConversion().runConversion(it)
JavaMethodToKotlinFunctionConversion().runConversion(it)
FieldToPropertyConversion().runConversion(it, context)
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()
val backAnnotation = mutableMapOf<JKElement, PsiElement>()
val symbols = mutableMapOf<PsiElement, JKSymbol>()
val symbolsByDeclaration = mutableMapOf<JKDeclaration, JKSymbol>()
@@ -152,11 +154,16 @@ class JavaToJKTreeBuilder {
fun PsiReferenceExpression.toJK(): JKExpression {
val impl = this as PsiReferenceExpressionImpl
if (impl.resolve() !is PsiField) {
return JKNullLiteral() // TODO !!!
}
val access = JKJavaFieldAccessExpressionImpl(JKMultiverseFieldSymbol(impl.resolve() as PsiField))
return if (impl.findChildByRole(ChildRole.DOT) != null) {
JKQualifiedExpressionImpl((impl.qualifier as PsiExpression).toJK(), JKJavaQualifierImpl.DOT, access)
} else {
access
return when {
impl.findChildByRole(ChildRole.DOT) != null &&
(impl.qualifierExpression as? PsiReferenceExpression)?.resolve() !is PsiClass ->
JKQualifiedExpressionImpl((impl.qualifier as PsiExpression).toJK(), JKJavaQualifierImpl.DOT, access)
else -> access
}
}
@@ -191,7 +198,7 @@ class JavaToJKTreeBuilder {
}
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 {
@@ -202,9 +209,18 @@ class JavaToJKTreeBuilder {
return JKExpressionListImpl(this?.expressions?.map { it.toJK() } ?: emptyList())
}
fun PsiTypeElement.toJK(): JKType {
return type.toJK().also {
backAnnotation[it] = this
}
}
fun PsiType.toJK(): JKType {
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 PsiPrimitiveType -> when (presentableText) {
"int" -> JKJavaPrimitiveTypeImpl.INT
@@ -238,7 +254,7 @@ class JavaToJKTreeBuilder {
fun PsiField.toJK(): JKJavaField {
return JKJavaFieldImpl(
with(modifierMapper) { modifierList.toJK() },
with(expressionTreeMapper) { type.toJK() },
with(expressionTreeMapper) { typeElement?.toJK() } ?: TODO(),
JKNameIdentifierImpl(this.name),
with(expressionTreeMapper) { initializer?.toJK() } ?: TODO()
).also {
@@ -262,7 +278,7 @@ class JavaToJKTreeBuilder {
}
fun PsiParameter.toJK(): JKValueArgumentImpl {
return JKValueArgumentImpl(with(expressionTreeMapper) { type.toJK() }, name!!)
return JKValueArgumentImpl(with(expressionTreeMapper) { typeElement?.toJK() } ?: TODO(), name!!)
}
fun PsiCodeBlock.toJK(): JKBlock {
@@ -42,7 +42,13 @@ class NewJavaToKotlinConverter(
println(fileTrees.prettyPrintTrees())
ConversionsRunner.doApply(fileTrees)
val context = ConversionContext(
JKSymbolProvider(),
project,
{ treeBuilder.backAnnotation[it] }
)
ConversionsRunner.doApply(fileTrees, context)
val resultTree = fileTrees.prettyPrintTrees()
@@ -16,12 +16,13 @@
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
abstract class BaseConversion {
/**
* @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
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.load.java.JvmAbi
@@ -16,7 +17,7 @@ class FieldToPropertyConversion : MatchBasedConversion() {
var somethingChanged = false
override fun runConversion(treeRoot: JKTreeElement): Boolean {
override fun runConversion(treeRoot: JKTreeElement, context: ConversionContext): Boolean {
val root = applyToElement(treeRoot)
assert(root === treeRoot)
return somethingChanged
@@ -16,13 +16,14 @@
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.visitors.JKVisitorVoid
abstract class TransformerBasedConversion : BaseConversion(), JKVisitorVoid {
protected var somethingChanged = false
override fun runConversion(treeRoot: JKTreeElement): Boolean {
override fun runConversion(treeRoot: JKTreeElement, context: ConversionContext): Boolean {
somethingChanged = false
treeRoot.accept(this, null)
return somethingChanged
@@ -5,17 +5,32 @@
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.JKJavaPrimitiveType
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
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) {
somethingChanged = true
}
override fun runConversion(treeRoot: JKTreeElement): Boolean {
override fun runConversion(treeRoot: JKTreeElement, context: ConversionContext): Boolean {
val root = applyToElement(treeRoot)
assert(root === treeRoot)
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 {
// if (type.classReference?.target) {
//
// }
return type
val fqNameStr = (type.classReference as? JKClassSymbol)?.fqName ?: return type
val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqNameStr)) ?: return type
return classTypeByFqName(context.backAnnotator(type), newFqName, type.parameters, type.nullability) ?: type
}
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
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitorVoid
import org.jetbrains.kotlin.utils.Printer
@@ -77,12 +78,7 @@ private class DebugTreePrinter : JKVisitorVoid {
printer.println(type.classNameWithoutJK(), " \"")
printer.indented {
if (type is JKClassType) {
/*if ((type.classReference as? JKBindableSymbol)?.isBound == true) {
printer.println(type.classReference?.element?.name?.value)
} else {
printer.println("Unbound")
}*/
printer.println((type.classReference as? JKClassSymbol)?.fqName ?: type.classReference?.let { it::class } ?: "Unbound")
}
}
printer.println("\"")
@@ -20,21 +20,21 @@ import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.visitors.JKVisitor
class JKJavaFieldImpl(
override var modifierList: JKModifierList,
override var type: JKType,
override var name: JKNameIdentifier,
override var initializer: JKExpression
) : JKJavaField, JKElementBase() {
modifierList: JKModifierList,
type: JKType,
name: JKNameIdentifier,
initializer: JKExpression
) : JKJavaField, JKBranchElementBase() {
override val valid: Boolean
get() = true
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) {
type.accept(visitor, data)
name.accept(visitor, data)
initializer.accept(visitor, data)
}
override var initializer: JKExpression by child(initializer)
override var modifierList: JKModifierList by child(modifierList)
override var name: JKNameIdentifier by child(name)
override var type: JKType by child(type)
}
class JKJavaLiteralExpressionImpl(
@@ -204,13 +204,13 @@ class JKTypeCastExpressionImpl(override var expression: JKExpression, override v
class JKClassTypeImpl(
override val classReference: JKClassSymbol,
override val parameters: List<JKType>,
parameters: List<JKType>,
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 <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.JKField
import org.jetbrains.kotlin.j2k.tree.JKMethod
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
interface JKSymbol {
val target: Any
@@ -18,7 +20,7 @@ interface JKSymbol {
}
interface JKClassSymbol : JKSymbol {
val fqName: String
val fqName: String?
}
interface JKMethodSymbol : JKSymbol {
@@ -39,8 +41,15 @@ class JKUniverseClassSymbol(override val target: JKClass) : JKClassSymbol {
class JKMultiverseClassSymbol(override val target: PsiClass) : JKClassSymbol {
override val declaredIn: JKSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override val fqName: String
get() = target.name!!
override val fqName: String?
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()
}