New J2K: Primary constructor conversion
This commit is contained in:
committed by
Ilya Kirillov
parent
6793c1d08f
commit
65e0694ba1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user