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 { 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 { fun doApply(trees: List<JKTreeElement>, context: ConversionContext) {
ModalityConversion(context).runConversion(it, context) val conversions = createConversions(context)
FieldToPropertyConversion().runConversion(it, context) trees.forEach { tree ->
TypeMappingConversion(context).runConversion(it, context) conversions.forEach { it.runConversion(tree, 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)
} }
} }
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.j2k package org.jetbrains.kotlin.j2k
import com.intellij.psi.* import com.intellij.psi.*
import org.jetbrains.kotlin.j2k.tree.JKClass import org.jetbrains.kotlin.j2k.tree.*
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.impl.* import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -29,7 +26,7 @@ class JKSymbolProvider {
when (psi) { when (psi) {
is PsiClass -> JKMultiverseClassSymbol(psi) is PsiClass -> JKMultiverseClassSymbol(psi)
is KtClassOrObject -> JKMultiverseKtClassSymbol(psi) is KtClassOrObject -> JKMultiverseKtClassSymbol(psi)
is PsiMethod -> JKMultiverseMethodSymbol(psi) is PsiMethod -> JKMultiverseMethodSymbol(psi, this)
is PsiField -> JKMultiverseFieldSymbol(psi) is PsiField -> JKMultiverseFieldSymbol(psi)
is KtNamedFunction -> JKMultiverseFunctionSymbol(psi) is KtNamedFunction -> JKMultiverseFunctionSymbol(psi)
else -> TODO(psi::class.toString()) else -> TODO(psi::class.toString())
@@ -55,12 +52,18 @@ class JKSymbolProvider {
fun provideUniverseSymbol(psi: PsiElement): JKSymbol = symbolsByPsi.getOrPut(psi) { fun provideUniverseSymbol(psi: PsiElement): JKSymbol = symbolsByPsi.getOrPut(psi) {
when (psi) { when (psi) {
is PsiField, is PsiParameter, is PsiLocalVariable -> JKUniverseFieldSymbol() is PsiField, is PsiParameter, is PsiLocalVariable -> JKUniverseFieldSymbol()
is PsiMethod -> JKUniverseMethodSymbol() is PsiMethod -> JKUniverseMethodSymbol(this)
is PsiClass -> JKUniverseClassSymbol() is PsiClass -> JKUniverseClassSymbol()
else -> TODO() 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) { fun provideUniverseSymbol(jk: JKClass): JKClassSymbol = symbolsByJK.getOrPut(jk) {
JKUniverseClassSymbol().also { it.target = jk } JKUniverseClassSymbol().also { it.target = jk }
} as JKClassSymbol } as JKClassSymbol
@@ -70,7 +73,7 @@ class JKSymbolProvider {
} as JKFieldSymbol } as JKFieldSymbol
fun provideUniverseSymbol(jk: JKMethod): JKMethodSymbol = symbolsByJK.getOrPut(jk) { fun provideUniverseSymbol(jk: JKMethod): JKMethodSymbol = symbolsByJK.getOrPut(jk) {
JKUniverseMethodSymbol().also { it.target = jk } JKUniverseMethodSymbol(this).also { it.target = jk }
} as JKMethodSymbol } as JKMethodSymbol
private inner class ElementVisitor : JavaElementVisitor() { 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.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 {
@@ -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) { private inline fun <T> renderList(list: List<T>, separator: String = ", ", renderElement: (T) -> Unit) {
val (head, tail) = list.headTail() val (head, tail) = list.headTail()
@@ -116,9 +113,24 @@ class NewCodeBuilder {
printer.print(classKindString(klass.classKind)) printer.print(classKindString(klass.classKind))
builder.append(" ") builder.append(" ")
printer.printWithNoIndent(klass.name.value) printer.printWithNoIndent(klass.name.value)
val primaryConstructor = klass.primaryConstructor()
if (primaryConstructor != null) {
renderParameterList(primaryConstructor.parameters)
}
if (klass.inheritance.inherit.isNotEmpty()) { if (klass.inheritance.inherit.isNotEmpty()) {
printer.printWithNoIndent(" : ") 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()) { if (klass.declarationList.isNotEmpty()) {
@@ -365,13 +377,17 @@ class NewCodeBuilder {
} }
} }
override fun visitKtConstructor(ktConstructor: JKKtConstructor) { private fun renderParameterList(parameters: List<JKParameter>) {
printer.print("constructor")
printer.par(ROUND) { printer.par(ROUND) {
renderList(ktConstructor.parameters) { renderList(parameters) {
it.accept(this) it.accept(this)
} }
} }
}
override fun visitKtConstructor(ktConstructor: JKKtConstructor) {
printer.print("constructor")
renderParameterList(ktConstructor.parameters)
if (ktConstructor.delegationCall !is JKStubExpression) { if (ktConstructor.delegationCall !is JKStubExpression) {
builder.append(" : ") builder.append(" : ")
ktConstructor.delegationCall.accept(this) ktConstructor.delegationCall.accept(this)
@@ -383,6 +399,8 @@ class NewCodeBuilder {
} }
} }
override fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor) {}
private inline fun Printer.indented(block: () -> Unit) { private inline fun Printer.indented(block: () -> Unit) {
this.pushIndent() this.pushIndent()
block() block()
@@ -443,4 +461,21 @@ private inline fun <T> List<T>.headTail(): Pair<T?, List<T>?> {
val head = this.firstOrNull() val head = this.firstOrNull()
val tail = if (size <= 1) null else subList(1, size) val tail = if (size <= 1) null else subList(1, size)
return head to tail 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 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.j2k.tree.impl.* import org.jetbrains.kotlin.j2k.tree.impl.*
class ConstructorConversion : RecursiveApplicableConversionBase() { class ConstructorConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement { override fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKJavaMethod) return recurse(element) if (element !is JKJavaMethod) return recurse(element)
val outerClass = element.parentOfType<JKClass>() ?: return recurse(element) val outerClass = element.parentOfType<JKClass>() ?: return recurse(element)
@@ -18,6 +19,9 @@ class ConstructorConversion : RecursiveApplicableConversionBase() {
val delegationCall = lookupDelegationCall(element.block) ?: JKStubExpressionImpl() val delegationCall = lookupDelegationCall(element.block) ?: JKStubExpressionImpl()
return JKKtConstructorImpl(element.name, element.parameters, element.block, element.modifierList, delegationCall) return JKKtConstructorImpl(element.name, element.parameters, element.block, element.modifierList, delegationCall)
.also {
context.symbolProvider.transferSymbol(it, element)
}
} }
private fun lookupDelegationCall(block: JKBlock): JKDelegationConstructorCall? { 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 var delegationCall: JKExpression by child(delegationCall)
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitKtConstructor(this, data) 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.PsiField
import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference 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.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.j2k.tree.JKTreeElement
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
interface JKSymbol { interface JKSymbol {
val target: Any 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? val fqName: String?
} }
interface JKMethodSymbol : JKSymbol { interface JKMethodSymbol : JKNamedSymbol {
val fqName: String val fqName: String
} }
interface JKFieldSymbol : JKSymbol { interface JKFieldSymbol : JKNamedSymbol {
val fqName: String val fqName: String
} }
class JKUniverseClassSymbol : JKClassSymbol { class JKUniverseClassSymbol : JKClassSymbol, JKUniverseSymbol<JKClass> {
override lateinit var target: JKClass override lateinit var target: JKClass
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.value // TODO("Fix this")
override val name: String
get() = target.name.value get() = target.name.value
} }
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.qualifiedName get() = target.qualifiedName
override val name: String
get() = target.name!!
} }
class JKMultiverseKtClassSymbol(override val target: KtClassOrObject) : JKClassSymbol { class JKMultiverseKtClassSymbol(override val target: KtClassOrObject) : JKClassSymbol {
override val name: String
get() = target.name!!
override val declaredIn: JKSymbol override val declaredIn: JKSymbol
get() = TODO("not implemented") get() = TODO("not implemented")
override val fqName: String? override val fqName: String?
@@ -55,51 +74,64 @@ class JKMultiverseKtClassSymbol(override val target: KtClassOrObject) : JKClassS
} }
class JKUniverseMethodSymbol : JKMethodSymbol { class JKUniverseMethodSymbol(private val symbolProvider: JKSymbolProvider) : JKMethodSymbol, JKUniverseSymbol<JKMethod> {
override lateinit var target: JKMethod override val name: String
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
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 { class JKMultiverseMethodSymbol(override val target: PsiMethod, private val symbolProvider: JKSymbolProvider) : JKMethodSymbol {
override val declaredIn: JKSymbol override val name: String
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
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 { class JKMultiverseFunctionSymbol(override val target: KtNamedFunction) : JKMethodSymbol {
override val name: String
get() = target.name!!
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.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 lateinit var target: JKField
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.value get() = target.name.value // TODO("Fix this")
} }
class JKMultiverseFieldSymbol(override val target: PsiField) : JKFieldSymbol { class JKMultiverseFieldSymbol(override val target: PsiField) : JKFieldSymbol {
override val name: String
get() = target.name
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.name // TODO("Fix this")
} }
class JKUnresolvedField(override val target: PsiReference) : JKFieldSymbol { class JKUnresolvedField(override val target: PsiReference) : JKFieldSymbol {
override val name: String
get() = TODO("not implemented")
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 = target.canonicalText override val fqName: String = target.canonicalText
} }
class JKUnresolvedMethod(override val target: PsiReference) : JKMethodSymbol { class JKUnresolvedMethod(override val target: PsiReference) : JKMethodSymbol {
override val name: String
get() = TODO("not implemented")
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 = target.canonicalText override val fqName: String = target.canonicalText
@@ -25,7 +25,7 @@ interface JKKtFunction : JKMethod {
val block: JKBlock val block: JKBlock
} }
interface JKKtConstructor : JKDeclaration, JKModifierListOwner, JKMethod { interface JKKtConstructor : JKDeclaration, JKModifierListOwner, JKMethod, JKBranchElement {
override var name: JKNameIdentifier override var name: JKNameIdentifier
override var parameters: List<JKParameter> override var parameters: List<JKParameter>
var block: JKBlock var block: JKBlock