diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt index 5c12cab3909..a4c21a95926 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt @@ -21,22 +21,27 @@ import org.jetbrains.kotlin.j2k.tree.JKTreeElement object ConversionsRunner { - fun doApply(trees: List, 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, context: ConversionContext) { + val conversions = createConversions(context) + trees.forEach { tree -> + conversions.forEach { it.runConversion(tree, context) } } } diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/JKSymbolProvider.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/JKSymbolProvider.kt index 58748a3ff1c..9821544a7eb 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/JKSymbolProvider.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/JKSymbolProvider.kt @@ -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() { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt index d0c07560f55..4e20aa3d7d3 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt @@ -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 renderList(list: List, 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) { 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 List.headTail(): Pair?> { 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 + } } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ConstructorConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ConstructorConversion.kt index 9a6a77000ca..df3e44df1b2 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ConstructorConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/ConstructorConversion.kt @@ -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() ?: 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? { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/PrimaryConstructorDetectConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/PrimaryConstructorDetectConversion.kt new file mode 100644 index 00000000000..b93aeb24d9c --- /dev/null +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/PrimaryConstructorDetectConversion.kt @@ -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() + 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 + } +} \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt index 772a6a7af0d..45f546e2be7 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt @@ -184,4 +184,22 @@ class JKKtConstructorImpl( override var delegationCall: JKExpression by child(delegationCall) override fun accept(visitor: JKVisitor, data: D): R = visitor.visitKtConstructor(this, data) +} + +class JKKtPrimaryConstructorImpl( + name: JKNameIdentifier, + parameters: List, + 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 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 accept(visitor: JKVisitor, data: D): R = visitor.visitKtPrimaryConstructor(this, data) } \ No newline at end of file diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/symbols.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/symbols.kt index 7773c05df2f..42383149e58 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/symbols.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/symbols.kt @@ -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 : 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 { 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 { + override val name: String get() = target.name.value + override lateinit var target: JKMethod + override val declaredIn: JKSymbol? + get() = target.parentOfType()?.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 { + 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 diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt index 1abf093ffd2..b0c94c5f712 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt @@ -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 var block: JKBlock