Converter:
Preserve formatting in member lists Introduce MemberList Refactor handling of static/non static members in classes
This commit is contained in:
committed by
Pavel V. Talanov
parent
30c016fa2a
commit
35f9d7b834
@@ -84,12 +84,15 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun convertAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass {
|
public fun convertAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass {
|
||||||
return AnonymousClass(this, getMembers(anonymousClass))
|
return AnonymousClass(this, convertMembers(anonymousClass))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMembers(psiClass: PsiClass): List<Node> {
|
private fun convertMembers(psiClass: PsiClass): List<Element> {
|
||||||
val members = ArrayList<Node>()
|
val members = ArrayList<Element>()
|
||||||
for (e in psiClass.getChildren()) {
|
for (e in psiClass.getChildren()) {
|
||||||
|
if (psiClass is PsiAnonymousClass && psiClass.getBaseClassReference() == e) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
val converted = convertMember(e, psiClass)
|
val converted = convertMember(e, psiClass)
|
||||||
if (converted != null) members.add(converted)
|
if (converted != null) members.add(converted)
|
||||||
}
|
}
|
||||||
@@ -101,14 +104,13 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
|
|||||||
return if (psiDocComment != null) Comment(psiDocComment.getText()!!) else null
|
return if (psiDocComment != null) Comment(psiDocComment.getText()!!) else null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertMember(e: PsiElement?, containingClass: PsiClass): Node? = when(e) {
|
private fun convertMember(e: PsiElement?, containingClass: PsiClass): Element? = when(e) {
|
||||||
is PsiMethod -> convertMethod(e, true)
|
is PsiMethod -> convertMethod(e, true)
|
||||||
is PsiField -> convertField(e, containingClass)
|
is PsiField -> convertField(e, containingClass)
|
||||||
is PsiClass -> convertClass(e)
|
is PsiClass -> convertClass(e)
|
||||||
is PsiClassInitializer -> convertInitializer(e)
|
is PsiClassInitializer -> convertInitializer(e)
|
||||||
is PsiDocComment -> null
|
is PsiDocComment -> null
|
||||||
is PsiComment -> Comment(e.getText()!!)
|
else -> convertElement(e)
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun convertClass(psiClass: PsiClass): Class {
|
private fun convertClass(psiClass: PsiClass): Class {
|
||||||
@@ -119,7 +121,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
|
|||||||
val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes())
|
val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes())
|
||||||
val name: Identifier = Identifier(psiClass.getName()!!)
|
val name: Identifier = Identifier(psiClass.getName()!!)
|
||||||
val baseClassParams = ArrayList<Expression>()
|
val baseClassParams = ArrayList<Expression>()
|
||||||
val members = ArrayList(getMembers(psiClass))
|
val members = ArrayList(convertMembers(psiClass))
|
||||||
val visitor = SuperVisitor()
|
val visitor = SuperVisitor()
|
||||||
psiClass.accept(visitor)
|
psiClass.accept(visitor)
|
||||||
val resolvedSuperCallParameters = visitor.resolvedSuperCallParameters
|
val resolvedSuperCallParameters = visitor.resolvedSuperCallParameters
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.jetbrains.jet.j2k.Converter
|
|||||||
import org.jetbrains.jet.j2k.ast.types.Type
|
import org.jetbrains.jet.j2k.ast.types.Type
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
|
|
||||||
public class AnonymousClass(converter: Converter, members: List<Node>)
|
public class AnonymousClass(converter: Converter, members: List<Element>)
|
||||||
: Class(converter,
|
: Class(converter,
|
||||||
Identifier("anonClass"),
|
Identifier("anonClass"),
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -30,32 +30,27 @@ public open class Class(val converter: Converter,
|
|||||||
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 members: List<Node>) : Member(docComment, modifiers) {
|
val members: List<Element>) : Member(docComment, modifiers) {
|
||||||
open val TYPE: String
|
open val TYPE: String
|
||||||
get() = "class"
|
get() = "class"
|
||||||
|
|
||||||
private fun getPrimaryConstructor(): Constructor? {
|
val classMembers = parseClassMembers(members)
|
||||||
return members.find { it is Constructor && it.isPrimary } as Constructor?
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun primaryConstructorSignatureToKotlin(): String {
|
open fun primaryConstructorSignatureToKotlin(): String {
|
||||||
val maybeConstructor: Constructor? = getPrimaryConstructor()
|
val constructor = classMembers.primaryConstructor
|
||||||
return if (maybeConstructor != null) maybeConstructor.primarySignatureToKotlin() else "()"
|
return if (constructor != null) constructor.primarySignatureToKotlin() else "()"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun primaryConstructorBodyToKotlin(): String? {
|
fun primaryConstructorBodyToKotlin(): String? {
|
||||||
val maybeConstructor = getPrimaryConstructor()
|
val maybeConstructor = classMembers.primaryConstructor
|
||||||
if (maybeConstructor != null && !(maybeConstructor.block?.isEmpty() ?: true)) {
|
if (maybeConstructor != null && !(maybeConstructor.block?.isEmpty() ?: true)) {
|
||||||
return maybeConstructor.primaryBodyToKotlin() + "\n"
|
return "\n" + maybeConstructor.primaryBodyToKotlin() + "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
fun membersExceptConstructors(): List<Node> = members.filterNot { it is Constructor }
|
fun secondaryConstructorsAsStaticInitFunction(): MemberList {
|
||||||
|
return MemberList(classMembers.secondaryConstructors.elements.map { if (it is Constructor) constructorToInit(it) else it })
|
||||||
fun secondaryConstructorsAsStaticInitFunction(): List<Function> {
|
|
||||||
return members.filter { it is Constructor && !it.isPrimary }.map { constructorToInit(it as Function) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun constructorToInit(f: Function): Function {
|
private fun constructorToInit(f: Function): Function {
|
||||||
@@ -110,14 +105,16 @@ public open class Class(val converter: Converter,
|
|||||||
open fun needsOpenModifier() = !isDefinitelyFinal() && converter.settings.openByDefault
|
open fun needsOpenModifier() = !isDefinitelyFinal() && converter.settings.openByDefault
|
||||||
|
|
||||||
fun bodyToKotlin(): String {
|
fun bodyToKotlin(): String {
|
||||||
return " {\n" + getNonStatic(membersExceptConstructors()).toKotlin("\n", "", "\n") + primaryConstructorBodyToKotlin() + classObjectToKotlin() + "}"
|
return " {" + classMembers.nonStaticMembers.toKotlin() + primaryConstructorBodyToKotlin() + classObjectToKotlin() + "}"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun classObjectToKotlin(): String {
|
fun classObjectToKotlin(): String {
|
||||||
val staticMembers = ArrayList<Node>()
|
val secondaryConstructorsAsStaticInitFunction = secondaryConstructorsAsStaticInitFunction()
|
||||||
staticMembers.addAll(secondaryConstructorsAsStaticInitFunction())
|
val staticMembers = classMembers.staticMembers
|
||||||
staticMembers.addAll(getStatic(membersExceptConstructors()))
|
if (secondaryConstructorsAsStaticInitFunction.isEmpty() && staticMembers.isEmpty()) {
|
||||||
return staticMembers.toKotlin("\n", "class object {\n", "\n}")
|
return ""
|
||||||
|
}
|
||||||
|
return "\nclass object {${secondaryConstructorsAsStaticInitFunction.toKotlin()}${staticMembers.toKotlin()}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toKotlin(): String =
|
override fun toKotlin(): String =
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class Enum(converter: Converter,
|
|||||||
extendsTypes: List<Type>,
|
extendsTypes: List<Type>,
|
||||||
baseClassParams: List<Expression>,
|
baseClassParams: List<Expression>,
|
||||||
implementsTypes: List<Type>,
|
implementsTypes: List<Type>,
|
||||||
members: List<Node>) : Class(converter, name, docComments, modifiers, typeParameterList,
|
members: List<Element>) : Class(converter, name, docComments, modifiers, typeParameterList,
|
||||||
extendsTypes, baseClassParams, implementsTypes, members) {
|
extendsTypes, baseClassParams, implementsTypes, members) {
|
||||||
|
|
||||||
override fun primaryConstructorSignatureToKotlin(): String {
|
override fun primaryConstructorSignatureToKotlin(): String {
|
||||||
@@ -44,8 +44,9 @@ public class Enum(converter: Converter,
|
|||||||
primaryConstructorSignatureToKotlin() +
|
primaryConstructorSignatureToKotlin() +
|
||||||
typeParameterList.toKotlin() +
|
typeParameterList.toKotlin() +
|
||||||
implementTypesToKotlin() +
|
implementTypesToKotlin() +
|
||||||
" {\n" + membersExceptConstructors().toKotlin("\n", "", "\n") +
|
" {" +
|
||||||
(if (primaryConstructorBody.isEmpty()) "" else primaryConstructorBody) +
|
classMembers.allMembers.toKotlin() +
|
||||||
|
( if (primaryConstructorBody.isEmpty()) "" else primaryConstructorBody) +
|
||||||
"}"
|
"}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,4 +18,5 @@ package org.jetbrains.jet.j2k.ast
|
|||||||
|
|
||||||
public open class ExpressionList(val expressions: List<Expression>) : Expression() {
|
public open class ExpressionList(val expressions: List<Expression>) : Expression() {
|
||||||
public override fun toKotlin(): String = expressions.map { it.toKotlin() }.makeString(", ")
|
public override fun toKotlin(): String = expressions.map { it.toKotlin() }.makeString(", ")
|
||||||
|
override fun isEmpty(): Boolean = expressions.isEmpty()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2013 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.jet.j2k.ast
|
|
||||||
|
|
||||||
public abstract class Member(val docComment: Comment?, val modifiers: Set<Modifier>) : Node {
|
|
||||||
fun accessModifier(): Modifier? {
|
|
||||||
return modifiers.find { m -> m == Modifier.PUBLIC || m == Modifier.PROTECTED || m == Modifier.PRIVATE }
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun isAbstract(): Boolean = modifiers.contains(Modifier.ABSTRACT)
|
|
||||||
public fun isStatic(): Boolean = modifiers.contains(Modifier.STATIC)
|
|
||||||
public fun docCommentToKotlin(): String = if (docComment != null) docComment.toKotlin() + "\n" else ""
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2013 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.jet.j2k.ast
|
||||||
|
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
public abstract class Member(val docComment: Comment?, val modifiers: Set<Modifier>) : Element {
|
||||||
|
fun accessModifier(): Modifier? {
|
||||||
|
return modifiers.find { m -> m == Modifier.PUBLIC || m == Modifier.PROTECTED || m == Modifier.PRIVATE }
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun isAbstract(): Boolean = modifiers.contains(Modifier.ABSTRACT)
|
||||||
|
public fun isStatic(): Boolean = modifiers.contains(Modifier.STATIC)
|
||||||
|
public fun docCommentToKotlin(): String = if (docComment != null) docComment.toKotlin() + "\n" else ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//member itself and all the elements before it in the code (comments, whitespaces)
|
||||||
|
class MemberHolder(val member: Member, val elements: List<Element>)
|
||||||
|
|
||||||
|
public class MemberList(elements: List<Element>) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) {
|
||||||
|
val members: List<Member>
|
||||||
|
get() = elements.filter { it is Member }.map { it as Member }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClassMembers(
|
||||||
|
val primaryConstructor: Constructor?,
|
||||||
|
val secondaryConstructors: MemberList,
|
||||||
|
val allMembers: MemberList,
|
||||||
|
val staticMembers: MemberList,
|
||||||
|
val nonStaticMembers: MemberList
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseClassMembers(elements: List<Element>): ClassMembers {
|
||||||
|
val groups = splitInGroups(elements)
|
||||||
|
val constructors = groups.filter { it.member is Constructor }
|
||||||
|
val primaryConstructor = constructors.map { it.member }.find { (it as Constructor).isPrimary }
|
||||||
|
val secondaryConstructors = constructors.filter { !(it.member as Constructor).isPrimary }
|
||||||
|
val nonConstructors = groups.filter { it.member !is Constructor }
|
||||||
|
val staticMembers = nonConstructors.filter { it.member.isStatic() }
|
||||||
|
val nonStaticMembers = nonConstructors.filter { !it.member.isStatic() }
|
||||||
|
return ClassMembers(primaryConstructor as Constructor?,
|
||||||
|
secondaryConstructors.toMemberList(),
|
||||||
|
nonConstructors.toMemberList(),
|
||||||
|
staticMembers.toMemberList(),
|
||||||
|
nonStaticMembers.toMemberList())
|
||||||
|
}
|
||||||
|
|
||||||
|
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(Pair(element, currentGroup))
|
||||||
|
currentGroup = ArrayList<Element>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result.isNotEmpty()) {
|
||||||
|
result.last!!.second.addAll(currentGroup)
|
||||||
|
}
|
||||||
|
return result map { MemberHolder(it.first, it.second) }
|
||||||
|
}
|
||||||
@@ -27,8 +27,8 @@ public class Trait(converter: Converter,
|
|||||||
extendsTypes: List<Type>,
|
extendsTypes: List<Type>,
|
||||||
baseClassParams: List<Expression>,
|
baseClassParams: List<Expression>,
|
||||||
implementsTypes: List<Type>,
|
implementsTypes: List<Type>,
|
||||||
members: List<Node>) : Class(converter, name, docComment, modifiers, typeParameterList,
|
members: List<Element>) : Class(converter, name, docComment, modifiers, typeParameterList,
|
||||||
extendsTypes, baseClassParams, implementsTypes, members) {
|
extendsTypes, baseClassParams, implementsTypes, members) {
|
||||||
|
|
||||||
override val TYPE: String
|
override val TYPE: String
|
||||||
get() = "trait"
|
get() = "trait"
|
||||||
|
|||||||
@@ -52,8 +52,10 @@ open class WhiteSpaceSeparatedElementList(
|
|||||||
) {
|
) {
|
||||||
val nonEmptyElements = elements.filterNot { it.isEmpty() }
|
val nonEmptyElements = elements.filterNot { it.isEmpty() }
|
||||||
|
|
||||||
|
fun isEmpty() = nonEmptyElements.all { it is WhiteSpace }
|
||||||
|
|
||||||
fun toKotlin(): String {
|
fun toKotlin(): String {
|
||||||
if (nonEmptyElements.isEmpty()) {
|
if (isEmpty()) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin() }.makeString("")
|
return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin() }.makeString("")
|
||||||
|
|||||||
Reference in New Issue
Block a user