New J2K: Primary constructor conversion

This commit is contained in:
Simon Ogorodnik
2018-07-24 23:27:03 +03:00
committed by Ilya Kirillov
parent 6793c1d08f
commit 65e0694ba1
8 changed files with 194 additions and 51 deletions
@@ -21,22 +21,27 @@ import org.jetbrains.kotlin.j2k.tree.JKTreeElement
object ConversionsRunner {
fun doApply(trees: List<JKTreeElement>, context: ConversionContext) {
private fun createConversions(context: ConversionContext) = listOf(
ModalityConversion(context),
FieldToPropertyConversion(),
TypeMappingConversion(context),
AssignmentAsExpressionToAlsoConversion(context),
AssignmentStatementValCreationConversion(context),
AssignmentStatementOperatorConversion(),
ConstructorConversion(context),
PrimaryConstructorDetectConversion(context),
JavaMethodToKotlinFunctionConversion(),
LiteralConversion(),
InnerClassConversion(),
ModifiersConversion(),
PolyadicExpressionConversion(),
BinaryExpressionConversion()
)
trees.forEach {
ModalityConversion(context).runConversion(it, context)
FieldToPropertyConversion().runConversion(it, context)
TypeMappingConversion(context).runConversion(it, context)
AssignmentAsExpressionToAlsoConversion(context).runConversion(it, context)
AssignmentStatementValCreationConversion(context).runConversion(it, context)
AssignmentStatementOperatorConversion().runConversion(it, context)
ConstructorConversion().runConversion(it, context)
JavaMethodToKotlinFunctionConversion().runConversion(it, context)
LiteralConversion().runConversion(it, context)
InnerClassConversion().runConversion(it, context)
ModifiersConversion().runConversion(it, context)
PolyadicExpressionConversion().runConversion(it, context)
BinaryExpressionConversion().runConversion(it, context)
fun doApply(trees: List<JKTreeElement>, context: ConversionContext) {
val conversions = createConversions(context)
trees.forEach { tree ->
conversions.forEach { it.runConversion(tree, context) }
}
}
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.j2k
import com.intellij.psi.*
import org.jetbrains.kotlin.j2k.tree.JKClass
import org.jetbrains.kotlin.j2k.tree.JKDeclaration
import org.jetbrains.kotlin.j2k.tree.JKField
import org.jetbrains.kotlin.j2k.tree.JKMethod
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -29,7 +26,7 @@ class JKSymbolProvider {
when (psi) {
is PsiClass -> JKMultiverseClassSymbol(psi)
is KtClassOrObject -> JKMultiverseKtClassSymbol(psi)
is PsiMethod -> JKMultiverseMethodSymbol(psi)
is PsiMethod -> JKMultiverseMethodSymbol(psi, this)
is PsiField -> JKMultiverseFieldSymbol(psi)
is KtNamedFunction -> JKMultiverseFunctionSymbol(psi)
else -> TODO(psi::class.toString())
@@ -55,12 +52,18 @@ class JKSymbolProvider {
fun provideUniverseSymbol(psi: PsiElement): JKSymbol = symbolsByPsi.getOrPut(psi) {
when (psi) {
is PsiField, is PsiParameter, is PsiLocalVariable -> JKUniverseFieldSymbol()
is PsiMethod -> JKUniverseMethodSymbol()
is PsiMethod -> JKUniverseMethodSymbol(this)
is PsiClass -> JKUniverseClassSymbol()
else -> TODO()
}
}
fun transferSymbol(to: JKDeclaration, from: JKDeclaration) = symbolsByJK[from]!!.let {
it as JKUniverseSymbol<*>
it.target = to
symbolsByJK[to] = it
}
fun provideUniverseSymbol(jk: JKClass): JKClassSymbol = symbolsByJK.getOrPut(jk) {
JKUniverseClassSymbol().also { it.target = jk }
} as JKClassSymbol
@@ -70,7 +73,7 @@ class JKSymbolProvider {
} as JKFieldSymbol
fun provideUniverseSymbol(jk: JKMethod): JKMethodSymbol = symbolsByJK.getOrPut(jk) {
JKUniverseMethodSymbol().also { it.target = jk }
JKUniverseMethodSymbol(this).also { it.target = jk }
} as JKMethodSymbol
private inner class ElementVisitor : JavaElementVisitor() {
@@ -23,6 +23,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 {
@@ -96,10 +97,6 @@ class NewCodeBuilder {
)
}
override fun visitInheritanceInfo(inheritanceInfo: JKInheritanceInfo) {
renderList(inheritanceInfo.inherit) { it.accept(this) }
}
private inline fun <T> renderList(list: List<T>, separator: String = ", ", renderElement: (T) -> Unit) {
val (head, tail) = list.headTail()
@@ -116,9 +113,24 @@ class NewCodeBuilder {
printer.print(classKindString(klass.classKind))
builder.append(" ")
printer.printWithNoIndent(klass.name.value)
val primaryConstructor = klass.primaryConstructor()
if (primaryConstructor != null) {
renderParameterList(primaryConstructor.parameters)
}
if (klass.inheritance.inherit.isNotEmpty()) {
printer.printWithNoIndent(" : ")
klass.inheritance.accept(this)
val delegationCall = primaryConstructor?.delegationCall as? JKDelegationConstructorCall
renderList(klass.inheritance.inherit) {
it.accept(this)
if (delegationCall != null && delegationCall.isCallOfConstructorOf(it.type)) {
printer.par {
delegationCall.arguments.accept(this)
}
}
}
}
if (klass.declarationList.isNotEmpty()) {
@@ -365,13 +377,17 @@ class NewCodeBuilder {
}
}
override fun visitKtConstructor(ktConstructor: JKKtConstructor) {
printer.print("constructor")
private fun renderParameterList(parameters: List<JKParameter>) {
printer.par(ROUND) {
renderList(ktConstructor.parameters) {
renderList(parameters) {
it.accept(this)
}
}
}
override fun visitKtConstructor(ktConstructor: JKKtConstructor) {
printer.print("constructor")
renderParameterList(ktConstructor.parameters)
if (ktConstructor.delegationCall !is JKStubExpression) {
builder.append(" : ")
ktConstructor.delegationCall.accept(this)
@@ -383,6 +399,8 @@ class NewCodeBuilder {
}
}
override fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor) {}
private inline fun Printer.indented(block: () -> Unit) {
this.pushIndent()
block()
@@ -443,4 +461,21 @@ private inline fun <T> List<T>.headTail(): Pair<T?, List<T>?> {
val head = this.firstOrNull()
val tail = if (size <= 1) null else subList(1, size)
return head to tail
}
private inline fun JKClass.primaryConstructor(): JKKtPrimaryConstructor? {
return this.declarationList.firstIsInstanceOrNull()
}
private inline fun JKDelegationConstructorCall.isCallOfConstructorOf(type: JKType): Boolean {
return when (type) {
is JKClassType -> {
val symbol = type.classReference as? JKClassSymbol ?: return false
this.identifier.name == symbol.name && this.identifier.declaredIn == symbol
}
is JKUnresolvedClassType -> {
this.identifier.name == type.name
}
else -> false
}
}
@@ -5,10 +5,11 @@
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.*
class ConstructorConversion : RecursiveApplicableConversionBase() {
class ConstructorConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKJavaMethod) return recurse(element)
val outerClass = element.parentOfType<JKClass>() ?: return recurse(element)
@@ -18,6 +19,9 @@ class ConstructorConversion : RecursiveApplicableConversionBase() {
val delegationCall = lookupDelegationCall(element.block) ?: JKStubExpressionImpl()
return JKKtConstructorImpl(element.name, element.parameters, element.block, element.modifierList, delegationCall)
.also {
context.symbolProvider.transferSymbol(it, element)
}
}
private fun lookupDelegationCall(block: JKBlock): JKDelegationConstructorCall? {
@@ -0,0 +1,46 @@
/*
* 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.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.JKKtPrimaryConstructorImpl
class PrimaryConstructorDetectConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element is JKClass) {
processClass(element)
}
return recurse(element)
}
private fun processClass(element: JKClass) {
val constructors = element.declarationList.filterIsInstance<JKKtConstructor>()
if (constructors.any { it is JKKtPrimaryConstructor }) return
// TODO: Detecting primary for multiple constructors
// TODO: Detecting primary constructors with field initializers
val single = constructors.singleOrNull { it.block.statements.isEmpty() } ?: return
val delegationCall = single.delegationCall as? JKDelegationConstructorCall
if (delegationCall?.expression is JKThisExpression) return
element.declarationList -= single
single.invalidate()
val primaryConstructor =
JKKtPrimaryConstructorImpl(
single.name,
single.parameters,
single.block,
single.modifierList,
single.delegationCall
)
context.symbolProvider.transferSymbol(primaryConstructor, single)
element.declarationList += primaryConstructor
}
}
@@ -184,4 +184,22 @@ class JKKtConstructorImpl(
override var delegationCall: JKExpression by child(delegationCall)
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitKtConstructor(this, data)
}
class JKKtPrimaryConstructorImpl(
name: JKNameIdentifier,
parameters: List<JKParameter>,
block: JKBlock,
modifierList: JKModifierList,
delegationCall: JKExpression
) : JKBranchElementBase(), JKKtPrimaryConstructor {
override val returnType: JKTypeElement get() = TODO("!")
override var name: JKNameIdentifier by child(name)
override var parameters: List<JKParameter> by children(parameters)
override var block: JKBlock by child(block)
override var modifierList: JKModifierList by child(modifierList)
override var delegationCall: JKExpression by child(delegationCall)
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitKtPrimaryConstructor(this, data)
}
@@ -9,45 +9,64 @@ import com.intellij.psi.PsiClass
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference
import org.jetbrains.kotlin.j2k.JKSymbolProvider
import org.jetbrains.kotlin.j2k.conversions.parentOfType
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.j2k.tree.JKTreeElement
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction
interface JKSymbol {
val target: Any
val declaredIn: JKSymbol
val declaredIn: JKSymbol?
}
interface JKClassSymbol : JKSymbol {
interface JKNamedSymbol : JKSymbol {
val name: String
}
interface JKUniverseSymbol<T: JKTreeElement> : JKSymbol {
override var target: T
}
interface JKClassSymbol : JKNamedSymbol {
val fqName: String?
}
interface JKMethodSymbol : JKSymbol {
interface JKMethodSymbol : JKNamedSymbol {
val fqName: String
}
interface JKFieldSymbol : JKSymbol {
interface JKFieldSymbol : JKNamedSymbol {
val fqName: String
}
class JKUniverseClassSymbol : JKClassSymbol {
class JKUniverseClassSymbol : JKClassSymbol, JKUniverseSymbol<JKClass> {
override lateinit var target: JKClass
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.value // TODO("Fix this")
override val name: String
get() = target.name.value
}
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.qualifiedName
override val name: String
get() = target.name!!
}
class JKMultiverseKtClassSymbol(override val target: KtClassOrObject) : JKClassSymbol {
override val name: String
get() = target.name!!
override val declaredIn: JKSymbol
get() = TODO("not implemented")
override val fqName: String?
@@ -55,51 +74,64 @@ class JKMultiverseKtClassSymbol(override val target: KtClassOrObject) : JKClassS
}
class JKUniverseMethodSymbol : JKMethodSymbol {
override lateinit var target: JKMethod
override val declaredIn: JKSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override val fqName: String
class JKUniverseMethodSymbol(private val symbolProvider: JKSymbolProvider) : JKMethodSymbol, JKUniverseSymbol<JKMethod> {
override val name: String
get() = target.name.value
override lateinit var target: JKMethod
override val declaredIn: JKSymbol?
get() = target.parentOfType<JKClass>()?.let { symbolProvider.provideUniverseSymbol(it) }
override val fqName: String
get() = target.name.value // TODO("Fix this")
}
class JKMultiverseMethodSymbol(override val target: PsiMethod) : JKMethodSymbol {
override val declaredIn: JKSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override val fqName: String
class JKMultiverseMethodSymbol(override val target: PsiMethod, private val symbolProvider: JKSymbolProvider) : JKMethodSymbol {
override val name: String
get() = target.name
override val declaredIn: JKSymbol?
get() = target.containingClass?.let { symbolProvider.provideDirectSymbol(it) }
override val fqName: String
get() = target.name // TODO("Fix this")
}
class JKMultiverseFunctionSymbol(override val target: KtNamedFunction) : JKMethodSymbol {
override val name: String
get() = target.name!!
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!!
get() = target.name!! // TODO("Fix this")
}
class JKUniverseFieldSymbol : JKFieldSymbol {
class JKUniverseFieldSymbol : JKFieldSymbol, JKUniverseSymbol<JKField> {
override val name: String
get() = target.name.value
override lateinit var target: JKField
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.value
get() = target.name.value // TODO("Fix this")
}
class JKMultiverseFieldSymbol(override val target: PsiField) : JKFieldSymbol {
override val name: String
get() = target.name
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
get() = target.name // TODO("Fix this")
}
class JKUnresolvedField(override val target: PsiReference) : JKFieldSymbol {
override val name: String
get() = TODO("not implemented")
override val declaredIn: JKSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override val fqName: String = target.canonicalText
}
class JKUnresolvedMethod(override val target: PsiReference) : JKMethodSymbol {
override val name: String
get() = TODO("not implemented")
override val declaredIn: JKSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
override val fqName: String = target.canonicalText
@@ -25,7 +25,7 @@ interface JKKtFunction : JKMethod {
val block: JKBlock
}
interface JKKtConstructor : JKDeclaration, JKModifierListOwner, JKMethod {
interface JKKtConstructor : JKDeclaration, JKModifierListOwner, JKMethod, JKBranchElement {
override var name: JKNameIdentifier
override var parameters: List<JKParameter>
var block: JKBlock