Fixed KT-4417 Converter from java to kotlin incorrectly places nested classes under class object
#KT-4417 Fixed
This commit is contained in:
@@ -83,18 +83,65 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
|||||||
return AnonymousClassBody(this, convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false)
|
return AnonymousClassBody(this, convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertClassBody(psiClass: PsiClass): List<Element> {
|
private fun convertClassBody(psiClass: PsiClass): ClassBody {
|
||||||
val membersToRemove = HashSet<PsiMember>()
|
val membersToRemove = HashSet<PsiMember>()
|
||||||
val convertedMembers = LinkedHashMap<PsiElement, Element>()
|
val convertedElements = LinkedHashMap<PsiElement, Element>()
|
||||||
var inBody = false
|
var inBody = false
|
||||||
val lBrace = psiClass.getLBrace()
|
val lBrace = psiClass.getLBrace()
|
||||||
for (element in psiClass.getChildren()) {
|
for (element in psiClass.getChildren()) {
|
||||||
if (element == lBrace) inBody = true
|
if (element == lBrace) inBody = true
|
||||||
if (inBody) {
|
if (inBody) {
|
||||||
convertedMembers.put(element, convertMember(element, membersToRemove))
|
convertedElements.put(element, convertMember(element, membersToRemove))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return convertedMembers.keySet().filter { !membersToRemove.contains(it) }.map { convertedMembers[it]!! }
|
|
||||||
|
for(member in membersToRemove) {
|
||||||
|
convertedElements.remove(member)
|
||||||
|
}
|
||||||
|
|
||||||
|
val membersMap = splitIntoMembers(convertedElements)
|
||||||
|
|
||||||
|
val constructors = membersMap.values().filter { it.member is Constructor }
|
||||||
|
val primaryConstructor = constructors.map { it.member }.filterIsInstance(javaClass<PrimaryConstructor>()).firstOrNull()
|
||||||
|
val secondaryConstructors = constructors.filter { it.member is SecondaryConstructor }
|
||||||
|
|
||||||
|
val normalMembers = ArrayList<MemberWithComments>()
|
||||||
|
val classObjectMembers = ArrayList<MemberWithComments>()
|
||||||
|
for((psiMember, member) in membersMap) {
|
||||||
|
if (member.member is Constructor) continue
|
||||||
|
if (!psiClass.isEnum() && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) {
|
||||||
|
classObjectMembers.add(member)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
normalMembers.add(member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClassBody(primaryConstructor,
|
||||||
|
secondaryConstructors.toMemberList(),
|
||||||
|
normalMembers.toMemberList(),
|
||||||
|
classObjectMembers.toMemberList())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<MemberWithComments>.toMemberList() = MemberList(flatMap { it.elements })
|
||||||
|
|
||||||
|
private fun splitIntoMembers(elements: Map<PsiElement, Element>): Map<PsiMember, MemberWithComments> {
|
||||||
|
val result = LinkedHashMap<PsiMember, MemberWithComments>()
|
||||||
|
var currentGroup = ArrayList<Element>()
|
||||||
|
var lastMember: PsiMember? = null
|
||||||
|
for ((psiElement, element) in elements) {
|
||||||
|
currentGroup.add(element)
|
||||||
|
if (element is Member) {
|
||||||
|
result.put(psiElement as PsiMember, MemberWithComments(element, currentGroup))
|
||||||
|
currentGroup = ArrayList()
|
||||||
|
lastMember = psiElement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastMember != null) {
|
||||||
|
(result[lastMember]!!.elements as MutableList).addAll(currentGroup)
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertMember(element: PsiElement, membersToRemove: MutableSet<PsiMember>): Element = when(element) {
|
private fun convertMember(element: PsiElement, membersToRemove: MutableSet<PsiMember>): Element = when(element) {
|
||||||
@@ -123,16 +170,16 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
|||||||
val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes())
|
val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes())
|
||||||
val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes())
|
val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes())
|
||||||
val name = Identifier(psiClass.getName()!!)
|
val name = Identifier(psiClass.getName()!!)
|
||||||
val classBodyElements = ArrayList(convertClassBody(psiClass))
|
var classBody = convertClassBody(psiClass)
|
||||||
|
|
||||||
when {
|
when {
|
||||||
psiClass.isInterface() -> return Trait(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBodyElements)
|
psiClass.isInterface() -> return Trait(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody)
|
||||||
|
|
||||||
psiClass.isEnum() -> return Enum(this, name, getComments(psiClass), modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBodyElements)
|
psiClass.isEnum() -> return Enum(this, name, getComments(psiClass), modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) {
|
if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) {
|
||||||
generateArtificialPrimaryConstructor(name, classBodyElements)
|
classBody = generateArtificialPrimaryConstructor(name, classBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
val baseClassParams: List<Expression> = run {
|
val baseClassParams: List<Expression> = run {
|
||||||
@@ -151,46 +198,52 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
|||||||
modifiers.add(Modifier.OPEN)
|
modifiers.add(Modifier.OPEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Class(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBodyElements)
|
if (psiClass.getContainingClass() != null && !psiClass.hasModifierProperty(PsiModifier.STATIC)) {
|
||||||
|
modifiers.add(Modifier.INNER)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Class(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateArtificialPrimaryConstructor(className: Identifier, classBodyElements: MutableList<Element>) {
|
private fun generateArtificialPrimaryConstructor(className: Identifier, classBody: ClassBody): ClassBody {
|
||||||
val finalOrWithEmptyInitializerFields = classBodyElements.filterIsInstance(javaClass<Field>()).filter { it.isVal || it.initializer.toKotlin().isEmpty() }
|
assert(classBody.primaryConstructor == null)
|
||||||
|
|
||||||
|
val finalOrWithEmptyInitializerFields = classBody.normalMembers.members.filterIsInstance(javaClass<Field>()).filter { it.isVal || it.initializer.toKotlin().isEmpty() }
|
||||||
val initializers = HashMap<String, String>()
|
val initializers = HashMap<String, String>()
|
||||||
for (element in classBodyElements) {
|
for (constructor in classBody.secondaryConstructors.members) {
|
||||||
if (element is SecondaryConstructor) {
|
constructor as SecondaryConstructor
|
||||||
for (field in finalOrWithEmptyInitializerFields) {
|
|
||||||
initializers.put(field.identifier.toKotlin(), getDefaultInitializer(field))
|
|
||||||
}
|
|
||||||
|
|
||||||
val newStatements = ArrayList<Statement>()
|
for (field in finalOrWithEmptyInitializerFields) {
|
||||||
for (statement in element.block!!.statements) {
|
initializers.put(field.identifier.toKotlin(), getDefaultInitializer(field))
|
||||||
var keepStatement = true
|
|
||||||
if (statement is AssignmentExpression) {
|
|
||||||
val assignee = statement.left
|
|
||||||
if (assignee is QualifiedExpression) {
|
|
||||||
for (field in finalOrWithEmptyInitializerFields) {
|
|
||||||
val id = field.identifier.toKotlin()
|
|
||||||
if (assignee.identifier.toKotlin().endsWith("." + id)) {
|
|
||||||
initializers.put(id, statement.right.toKotlin())
|
|
||||||
keepStatement = false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keepStatement) {
|
|
||||||
newStatements.add(statement)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
newStatements.add(0, DummyStringExpression("val __ = " + createPrimaryConstructorInvocation(className.toKotlin(), finalOrWithEmptyInitializerFields, initializers)))
|
|
||||||
element.block = Block(newStatements)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val newStatements = ArrayList<Statement>()
|
||||||
|
for (statement in constructor.block!!.statements) {
|
||||||
|
var keepStatement = true
|
||||||
|
if (statement is AssignmentExpression) {
|
||||||
|
val assignee = statement.left
|
||||||
|
if (assignee is QualifiedExpression) {
|
||||||
|
for (field in finalOrWithEmptyInitializerFields) {
|
||||||
|
val id = field.identifier.toKotlin()
|
||||||
|
if (assignee.identifier.toKotlin().endsWith("." + id)) {
|
||||||
|
initializers.put(id, statement.right.toKotlin())
|
||||||
|
keepStatement = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keepStatement) {
|
||||||
|
newStatements.add(statement)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
newStatements.add(0, DummyStringExpression("val __ = " + createPrimaryConstructorInvocation(className.toKotlin(), finalOrWithEmptyInitializerFields, initializers)))
|
||||||
|
constructor.block = Block(newStatements)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: comments?
|
//TODO: comments?
|
||||||
@@ -198,12 +251,10 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
|||||||
val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var
|
val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var
|
||||||
Parameter(field.identifier, field.`type`, varValModifier, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) })
|
Parameter(field.identifier, field.`type`, varValModifier, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) })
|
||||||
}
|
}
|
||||||
classBodyElements.add(PrimaryConstructor(this,
|
|
||||||
MemberComments.Empty,
|
val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty)
|
||||||
setOf(Modifier.PRIVATE),
|
val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) })
|
||||||
ParameterList(parameters),
|
return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers)
|
||||||
Block.Empty))
|
|
||||||
classBodyElements.removeAll(finalOrWithEmptyInitializerFields)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertInitializer(initializer: PsiClassInitializer): Initializer {
|
private fun convertInitializer(initializer: PsiClassInitializer): Initializer {
|
||||||
@@ -509,7 +560,6 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
|||||||
|
|
||||||
private val MODIFIERS_MAP = listOf(
|
private val MODIFIERS_MAP = listOf(
|
||||||
PsiModifier.ABSTRACT to Modifier.ABSTRACT,
|
PsiModifier.ABSTRACT to Modifier.ABSTRACT,
|
||||||
PsiModifier.STATIC to Modifier.STATIC,
|
|
||||||
PsiModifier.PUBLIC to Modifier.PUBLIC,
|
PsiModifier.PUBLIC to Modifier.PUBLIC,
|
||||||
PsiModifier.PROTECTED to Modifier.PROTECTED,
|
PsiModifier.PROTECTED to Modifier.PROTECTED,
|
||||||
PsiModifier.PRIVATE to Modifier.PRIVATE
|
PsiModifier.PRIVATE to Modifier.PRIVATE
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package org.jetbrains.jet.j2k.ast
|
|||||||
import org.jetbrains.jet.j2k.Converter
|
import org.jetbrains.jet.j2k.Converter
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
|
|
||||||
class AnonymousClassBody(converter: Converter, bodyElements: List<Element>, val extendsTrait: Boolean)
|
class AnonymousClassBody(converter: Converter, body: ClassBody, val extendsTrait: Boolean)
|
||||||
: Class(converter,
|
: Class(converter,
|
||||||
Identifier(""),
|
Identifier(""),
|
||||||
MemberComments.Empty,
|
MemberComments.Empty,
|
||||||
@@ -28,6 +28,6 @@ class AnonymousClassBody(converter: Converter, bodyElements: List<Element>, val
|
|||||||
listOf(),
|
listOf(),
|
||||||
listOf(),
|
listOf(),
|
||||||
listOf(),
|
listOf(),
|
||||||
bodyElements) {
|
body) {
|
||||||
override fun toKotlin() = bodyToKotlin()
|
override fun toKotlin() = body.toKotlin(null)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ open class Class(
|
|||||||
val extendsTypes: List<Type>,
|
val extendsTypes: List<Type>,
|
||||||
val baseClassParams: List<Expression>,
|
val baseClassParams: List<Expression>,
|
||||||
val implementsTypes: List<Type>,
|
val implementsTypes: List<Type>,
|
||||||
val bodyElements: List<Element>
|
val body: ClassBody
|
||||||
) : Member(comments, modifiers) {
|
) : Member(comments, modifiers) {
|
||||||
|
|
||||||
override fun toKotlin(): String =
|
override fun toKotlin(): String =
|
||||||
@@ -39,27 +39,13 @@ open class Class(
|
|||||||
primaryConstructorSignatureToKotlin() +
|
primaryConstructorSignatureToKotlin() +
|
||||||
implementTypesToKotlin() +
|
implementTypesToKotlin() +
|
||||||
typeParameterList.whereToKotlin().withPrefix(" ") +
|
typeParameterList.whereToKotlin().withPrefix(" ") +
|
||||||
bodyToKotlin()
|
body.toKotlin(this)
|
||||||
|
|
||||||
protected open val keyword: String
|
protected open val keyword: String
|
||||||
get() = "class"
|
get() = "class"
|
||||||
|
|
||||||
protected val classMembers: ClassMembers = ClassMembers.fromBodyElements(bodyElements)
|
|
||||||
|
|
||||||
protected open fun primaryConstructorSignatureToKotlin(): String
|
protected open fun primaryConstructorSignatureToKotlin(): String
|
||||||
= classMembers.primaryConstructor?.signatureToKotlin() ?: "()"
|
= body.primaryConstructor?.signatureToKotlin() ?: "()"
|
||||||
|
|
||||||
protected fun primaryConstructorBodyToKotlin(): String {
|
|
||||||
val constructor = classMembers.primaryConstructor
|
|
||||||
if (constructor != null && !(constructor.block?.isEmpty ?: true)) {
|
|
||||||
return "\n" + constructor.bodyToKotlin() + "\n"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun secondaryConstructorsAsStaticInitFunctions(): MemberList {
|
|
||||||
return MemberList(classMembers.secondaryConstructors.elements.map { if (it is SecondaryConstructor) it.toInitFunction(this) else it })
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun baseClassSignatureWithParams(): List<String> {
|
private fun baseClassSignatureWithParams(): List<String> {
|
||||||
if (keyword.equals("class") && extendsTypes.size() == 1) {
|
if (keyword.equals("class") && extendsTypes.size() == 1) {
|
||||||
@@ -91,18 +77,10 @@ open class Class(
|
|||||||
modifierList.add(Modifier.OPEN)
|
modifierList.add(Modifier.OPEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (modifiers.contains(Modifier.INNER)) {
|
||||||
|
modifierList.add(Modifier.INNER)
|
||||||
|
}
|
||||||
|
|
||||||
return modifierList.toKotlin()
|
return modifierList.toKotlin()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bodyToKotlin(): String {
|
|
||||||
val innerBody = classMembers.nonStaticMembers.toKotlin() + primaryConstructorBodyToKotlin() + classObjectToKotlin()
|
|
||||||
return if (innerBody.trim().isNotEmpty()) " {" + innerBody + "}" else ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun classObjectToKotlin(): String {
|
|
||||||
val secondaryConstructorsAsStaticInitFunctions = secondaryConstructorsAsStaticInitFunctions()
|
|
||||||
val staticMembers = classMembers.staticMembers
|
|
||||||
if (secondaryConstructorsAsStaticInitFunctions.isEmpty() && staticMembers.isEmpty()) return ""
|
|
||||||
return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin()}${staticMembers.toKotlin()}}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ class SecondaryConstructor(converter: Converter,
|
|||||||
|
|
||||||
public fun toInitFunction(containingClass: Class): Function {
|
public fun toInitFunction(containingClass: Class): Function {
|
||||||
val modifiers = HashSet(modifiers)
|
val modifiers = HashSet(modifiers)
|
||||||
modifiers.add(Modifier.STATIC)
|
|
||||||
val statements = ArrayList(block?.statements ?: listOf())
|
val statements = ArrayList(block?.statements ?: listOf())
|
||||||
statements.add(ReturnStatement(Identifier("__")))
|
statements.add(ReturnStatement(Identifier("__")))
|
||||||
val block = Block(statements)
|
val block = Block(statements)
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ class Enum(
|
|||||||
extendsTypes: List<Type>,
|
extendsTypes: List<Type>,
|
||||||
baseClassParams: List<Expression>,
|
baseClassParams: List<Expression>,
|
||||||
implementsTypes: List<Type>,
|
implementsTypes: List<Type>,
|
||||||
bodyElements: List<Element>
|
body: ClassBody
|
||||||
) : Class(converter, name, comments, modifiers, typeParameterList,
|
) : Class(converter, name, comments, modifiers, typeParameterList,
|
||||||
extendsTypes, baseClassParams, implementsTypes, bodyElements) {
|
extendsTypes, baseClassParams, implementsTypes, body) {
|
||||||
|
|
||||||
override fun primaryConstructorSignatureToKotlin(): String
|
override fun primaryConstructorSignatureToKotlin(): String
|
||||||
= classMembers.primaryConstructor?.signatureToKotlin() ?: ""
|
= body.primaryConstructor?.signatureToKotlin() ?: ""
|
||||||
|
|
||||||
override fun toKotlin(): String {
|
override fun toKotlin(): String {
|
||||||
return modifiersToKotlin() +
|
return modifiersToKotlin() +
|
||||||
@@ -40,9 +40,6 @@ class Enum(
|
|||||||
primaryConstructorSignatureToKotlin() +
|
primaryConstructorSignatureToKotlin() +
|
||||||
typeParameterList.toKotlin() +
|
typeParameterList.toKotlin() +
|
||||||
implementTypesToKotlin() +
|
implementTypesToKotlin() +
|
||||||
" {" +
|
body.toKotlin(this)
|
||||||
classMembers.allMembers.toKotlin() +
|
|
||||||
primaryConstructorBodyToKotlin() +
|
|
||||||
"}"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ open class Field(
|
|||||||
override fun toKotlin(): String {
|
override fun toKotlin(): String {
|
||||||
val declaration = commentsToKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin()
|
val declaration = commentsToKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin()
|
||||||
return if (initializer.isEmpty)
|
return if (initializer.isEmpty)
|
||||||
declaration + (if (isVal && !isStatic() && hasWriteAccesses) "" else " = " + getDefaultInitializer(this))
|
declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this))
|
||||||
else
|
else
|
||||||
declaration + " = " + initializer.toKotlin()
|
declaration + " = " + initializer.toKotlin()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,12 @@
|
|||||||
package org.jetbrains.jet.j2k.ast
|
package org.jetbrains.jet.j2k.ast
|
||||||
|
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import org.jetbrains.jet.j2k.Converter
|
||||||
|
import java.util.HashSet
|
||||||
|
import com.intellij.psi.PsiMember
|
||||||
|
import java.util.LinkedHashMap
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
class MemberComments(elements: List<Element>) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NoSpace) {
|
class MemberComments(elements: List<Element>) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NoSpace) {
|
||||||
class object {
|
class object {
|
||||||
@@ -25,56 +31,43 @@ class MemberComments(elements: List<Element>) : WhiteSpaceSeparatedElementList(e
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class Member(val comments: MemberComments, val modifiers: Set<Modifier>) : Element {
|
abstract class Member(val comments: MemberComments, val modifiers: Set<Modifier>) : Element {
|
||||||
fun isStatic(): Boolean = modifiers.contains(Modifier.STATIC)
|
|
||||||
fun commentsToKotlin(): String = comments.toKotlin()
|
fun commentsToKotlin(): String = comments.toKotlin()
|
||||||
}
|
}
|
||||||
|
|
||||||
//member itself and all the elements before it in the code (comments, whitespaces)
|
//member itself and all the elements before it in the code (comments, whitespaces)
|
||||||
class MemberHolder(val member: Member, val elements: List<Element>)
|
class MemberWithComments(val member: Member, val elements: List<Element>)
|
||||||
|
|
||||||
class MemberList(elements: List<Element>) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) {
|
class MemberList(elements: List<Element>) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) {
|
||||||
val members: List<Member>
|
val members: List<Member>
|
||||||
get() = elements.filter { it is Member }.map { it as Member }
|
get() = elements.filter { it is Member }.map { it as Member }
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClassMembers private(
|
class ClassBody (
|
||||||
val primaryConstructor: PrimaryConstructor?,
|
val primaryConstructor: PrimaryConstructor?,
|
||||||
val secondaryConstructors: MemberList,
|
val secondaryConstructors: MemberList,
|
||||||
val allMembers: MemberList,
|
val normalMembers: MemberList,
|
||||||
val staticMembers: MemberList,
|
val classObjectMembers: MemberList) {
|
||||||
val nonStaticMembers: MemberList) {
|
|
||||||
class object {
|
fun toKotlin(containingClass: Class?): String {
|
||||||
public fun fromBodyElements(elements: List<Element>): ClassMembers {
|
val innerBody = normalMembers.toKotlin() + primaryConstructorBodyToKotlin() + classObjectToKotlin(containingClass)
|
||||||
val groups = splitInGroups(elements)
|
return if (innerBody.trim().isNotEmpty()) " {" + innerBody + "}" else ""
|
||||||
val constructors = groups.filter { it.member is Constructor }
|
}
|
||||||
val primaryConstructor = constructors.map { it.member }.filterIsInstance(javaClass<PrimaryConstructor>()).firstOrNull()
|
|
||||||
val secondaryConstructors = constructors.filter { it.member is SecondaryConstructor }
|
private fun primaryConstructorBodyToKotlin(): String {
|
||||||
val nonConstructors = groups.filter { it.member !is Constructor }
|
val constructor = primaryConstructor
|
||||||
val staticMembers = nonConstructors.filter { it.member.isStatic() }
|
if (constructor != null && !(constructor.block?.isEmpty ?: true)) {
|
||||||
val nonStaticMembers = nonConstructors.filter { !it.member.isStatic() }
|
return "\n" + constructor.bodyToKotlin() + "\n"
|
||||||
return ClassMembers(primaryConstructor,
|
|
||||||
secondaryConstructors.toMemberList(),
|
|
||||||
nonConstructors.toMemberList(),
|
|
||||||
staticMembers.toMemberList(),
|
|
||||||
nonStaticMembers.toMemberList())
|
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun classObjectToKotlin(containingClass: Class?): String {
|
||||||
|
val secondaryConstructorsAsStaticInitFunctions = secondaryConstructorsAsStaticInitFunctions(containingClass)
|
||||||
|
if (secondaryConstructorsAsStaticInitFunctions.isEmpty() && classObjectMembers.isEmpty()) return ""
|
||||||
|
return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin()}${classObjectMembers.toKotlin()}}"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun secondaryConstructorsAsStaticInitFunctions(containingClass: Class?): MemberList {
|
||||||
|
return MemberList(secondaryConstructors.elements.map { if (it is SecondaryConstructor && containingClass != null) it.toInitFunction(containingClass) else it })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<MemberHolder>.toMemberList() = MemberList(flatMap { it.elements })
|
|
||||||
|
|
||||||
private fun splitInGroups(elements: List<Element>): List<MemberHolder> {
|
|
||||||
val result = ArrayList<Pair<Member, MutableList<Element>>>()
|
|
||||||
var currentGroup = ArrayList<Element>()
|
|
||||||
for (element in elements) {
|
|
||||||
currentGroup.add(element)
|
|
||||||
if (element is Member) {
|
|
||||||
result.add(element to currentGroup)
|
|
||||||
currentGroup = ArrayList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.isNotEmpty()) {
|
|
||||||
result.last!!.second.addAll(currentGroup)
|
|
||||||
}
|
|
||||||
return result map { MemberHolder(it.first, it.second) }
|
|
||||||
}
|
|
||||||
@@ -20,10 +20,10 @@ enum class Modifier(val name: String) {
|
|||||||
PUBLIC: Modifier("public")
|
PUBLIC: Modifier("public")
|
||||||
PROTECTED: Modifier("protected")
|
PROTECTED: Modifier("protected")
|
||||||
PRIVATE: Modifier("private")
|
PRIVATE: Modifier("private")
|
||||||
STATIC: Modifier("static")
|
|
||||||
ABSTRACT: Modifier("abstract")
|
ABSTRACT: Modifier("abstract")
|
||||||
OPEN: Modifier("open")
|
OPEN: Modifier("open")
|
||||||
OVERRIDE: Modifier("override")
|
OVERRIDE: Modifier("override")
|
||||||
|
INNER: Modifier("inner")
|
||||||
|
|
||||||
public fun toKotlin(): String = name
|
public fun toKotlin(): String = name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ class Trait(
|
|||||||
extendsTypes: List<Type>,
|
extendsTypes: List<Type>,
|
||||||
baseClassParams: List<Expression>,
|
baseClassParams: List<Expression>,
|
||||||
implementsTypes: List<Type>,
|
implementsTypes: List<Type>,
|
||||||
bodyElements: List<Element>
|
body: ClassBody
|
||||||
) : Class(converter, name, comments, modifiers, typeParameterList,
|
) : Class(converter, name, comments, modifiers, typeParameterList,
|
||||||
extendsTypes, baseClassParams, implementsTypes, bodyElements) {
|
extendsTypes, baseClassParams, implementsTypes, body) {
|
||||||
|
|
||||||
override val keyword: String
|
override val keyword: String
|
||||||
get() = "trait"
|
get() = "trait"
|
||||||
|
|||||||
@@ -621,11 +621,26 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
|
|||||||
doTest("j2k/tests/testData/ast/class/genericClass.java");
|
doTest("j2k/tests/testData/ast/class/genericClass.java");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("innerClassInInterface.java")
|
||||||
|
public void testInnerClassInInterface() throws Exception {
|
||||||
|
doTest("j2k/tests/testData/ast/class/innerClassInInterface.java");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("innerEmptyClass.java")
|
@TestMetadata("innerEmptyClass.java")
|
||||||
public void testInnerEmptyClass() throws Exception {
|
public void testInnerEmptyClass() throws Exception {
|
||||||
doTest("j2k/tests/testData/ast/class/innerEmptyClass.java");
|
doTest("j2k/tests/testData/ast/class/innerEmptyClass.java");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("innerEnum.java")
|
||||||
|
public void testInnerEnum() throws Exception {
|
||||||
|
doTest("j2k/tests/testData/ast/class/innerEnum.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("innerInterface.java")
|
||||||
|
public void testInnerInterface() throws Exception {
|
||||||
|
doTest("j2k/tests/testData/ast/class/innerInterface.java");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("innerStaticClass.java")
|
@TestMetadata("innerStaticClass.java")
|
||||||
public void testInnerStaticClass() throws Exception {
|
public void testInnerStaticClass() throws Exception {
|
||||||
doTest("j2k/tests/testData/ast/class/innerStaticClass.java");
|
doTest("j2k/tests/testData/ast/class/innerStaticClass.java");
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
//file
|
||||||
|
interface A {
|
||||||
|
class B {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
trait A {
|
||||||
|
public class B()
|
||||||
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
class A() {
|
class A() {
|
||||||
class B()
|
inner class B()
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
//file
|
||||||
|
class A {
|
||||||
|
enum E {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class A() {
|
||||||
|
enum class E {
|
||||||
|
A
|
||||||
|
B
|
||||||
|
C
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
//file
|
||||||
|
class A {
|
||||||
|
interface I {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
class A() {
|
||||||
|
trait I
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
class S() {
|
class S() {
|
||||||
class object {
|
class Inner()
|
||||||
class Inner()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
enum class A {}
|
enum class A
|
||||||
@@ -1 +1 @@
|
|||||||
enum class A : I {}
|
enum class A : I
|
||||||
@@ -1 +1 @@
|
|||||||
enum class A : I0, I1, I2 {}
|
enum class A : I0, I1, I2
|
||||||
@@ -1 +1 @@
|
|||||||
enum class Test {}
|
enum class Test
|
||||||
@@ -1 +1 @@
|
|||||||
private enum class Test {}
|
private enum class Test
|
||||||
@@ -1 +1 @@
|
|||||||
protected enum class Test {}
|
protected enum class Test
|
||||||
@@ -1 +1 @@
|
|||||||
public enum class Test {}
|
public enum class Test
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package org.test
|
package org.test
|
||||||
|
|
||||||
class OuterClass() {
|
class OuterClass() {
|
||||||
class InnerClass()
|
inner class InnerClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
class User() {
|
class User() {
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package demo
|
package demo
|
||||||
|
|
||||||
class Foo() {
|
class Foo() {
|
||||||
class object {
|
class Bar()
|
||||||
class Bar()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class User() {
|
class User() {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ class Base() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class A() : Base() {
|
class A() : Base() {
|
||||||
class C() {
|
inner class C() {
|
||||||
fun test() {
|
fun test() {
|
||||||
super@A.foo()
|
super@A.foo()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class Base() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class A() : Base() {
|
class A() : Base() {
|
||||||
class C() {
|
inner class C() {
|
||||||
fun test() {
|
fun test() {
|
||||||
this@A.foo()
|
this@A.foo()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user