Java to Kotlin converter: refactoring working with constructors (in progress)

This commit is contained in:
Valentin Kipyatkov
2014-06-25 19:39:32 +04:00
parent b7bcb0d9e3
commit 0edd9d24be
8 changed files with 87 additions and 65 deletions
+56 -21
View File
@@ -122,22 +122,22 @@ public class Converter private(val project: Project, val settings: ConverterSett
convertedMembers.remove(member) convertedMembers.remove(member)
} }
val primaryConstructor = convertedMembers.values().filterIsInstance(javaClass<PrimaryConstructor>()).firstOrNull()
val secondaryConstructors = convertedMembers.values().filterIsInstance(javaClass<SecondaryConstructor>())
val useClassObject = shouldGenerateClassObject(psiClass, convertedMembers) val useClassObject = shouldGenerateClassObject(psiClass, convertedMembers)
val members = ArrayList<Member>() val members = ArrayList<Member>()
val classObjectMembers = ArrayList<Member>() val classObjectMembers = ArrayList<Member>()
var primaryConstructorSignature: PrimaryConstructorSignature? = null
for ((psiMember, member) in convertedMembers) { for ((psiMember, member) in convertedMembers) {
if (member is SecondaryConstructor) continue
if (member is PrimaryConstructor) { if (member is PrimaryConstructor) {
assert(primaryConstructorSignature == null)
primaryConstructorSignature = member.signature()
val initializer = member.initializer() val initializer = member.initializer()
if (initializer != null) { if (initializer != null) {
members.add(initializer) members.add(initializer)
} }
} }
else if (useClassObject && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) { else if (useClassObject && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC) ||
member is FactoryFunction) {
classObjectMembers.add(member) classObjectMembers.add(member)
} }
else { else {
@@ -147,7 +147,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
val lBrace = LBrace().assignPrototype(psiClass.getLBrace()) val lBrace = LBrace().assignPrototype(psiClass.getLBrace())
val rBrace = RBrace().assignPrototype(psiClass.getRBrace()) val rBrace = RBrace().assignPrototype(psiClass.getRBrace())
return ClassBody(primaryConstructor?.signature(), members, secondaryConstructors, classObjectMembers, lBrace, rBrace) return ClassBody(primaryConstructorSignature, members, classObjectMembers, lBrace, rBrace)
} }
// do not convert private static methods into class object if possible // do not convert private static methods into class object if possible
@@ -190,6 +190,9 @@ public class Converter private(val project: Project, val settings: ConverterSett
if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) { if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) {
classBody = generateArtificialPrimaryConstructor(name, classBody) classBody = generateArtificialPrimaryConstructor(name, classBody)
} }
else {
correctFactoryFunctions(classBody, psiClass.getName()!!)
}
val baseClassParams: List<Expression> = run { val baseClassParams: List<Expression> = run {
val superVisitor = SuperVisitor() val superVisitor = SuperVisitor()
@@ -216,22 +219,24 @@ public class Converter private(val project: Project, val settings: ConverterSett
}.assignPrototype(psiClass) }.assignPrototype(psiClass)
} }
private fun ClassBody.factoryFunctions() = classObjectMembers.filterIsInstance(javaClass<FactoryFunction>())
private fun generateArtificialPrimaryConstructor(className: Identifier, classBody: ClassBody): ClassBody { private fun generateArtificialPrimaryConstructor(className: Identifier, classBody: ClassBody): ClassBody {
assert(classBody.primaryConstructorSignature == null) assert(classBody.primaryConstructorSignature == null)
val finalOrWithEmptyInitializerFields = classBody.members.filterIsInstance(javaClass<Field>()).filter { it.isVal || it.initializer.isEmpty } val finalOrWithEmptyInitializerFields = classBody.members.filterIsInstance(javaClass<Field>()).filter { it.isVal || it.initializer.isEmpty }
val initializers = HashMap<Field, Expression>() val initializers = HashMap<Field, Expression>()
for (constructor in classBody.secondaryConstructors) { for (factoryFunction in classBody.factoryFunctions()) {
for (field in finalOrWithEmptyInitializerFields) { for (field in finalOrWithEmptyInitializerFields) {
initializers.put(field, getDefaultInitializer(field)) initializers.put(field, getDefaultInitializer(field))
} }
val newStatements = ArrayList<Statement>() val statements = ArrayList<Statement>()
for (statement in constructor.block!!.statements) { for (statement in factoryFunction.body!!.statements) {
var keepStatement = true var keepStatement = true
if (statement is AssignmentExpression) { if (statement is AssignmentExpression) {
val assignee = statement.left val assignee = statement.left
if (assignee is QualifiedExpression && (assignee.qualifier as? Identifier)?.name == SecondaryConstructor.tempValName) { if (assignee is QualifiedExpression && (assignee.qualifier as? Identifier)?.name == FactoryFunction.tempValName) {
val name = (assignee.identifier as Identifier).name val name = (assignee.identifier as Identifier).name
for (field in finalOrWithEmptyInitializerFields) { for (field in finalOrWithEmptyInitializerFields) {
if (name == field.identifier.name) { if (name == field.identifier.name) {
@@ -245,21 +250,21 @@ public class Converter private(val project: Project, val settings: ConverterSett
} }
if (keepStatement) { if (keepStatement) {
newStatements.add(statement) statements.add(statement)
} }
} }
val initializer = MethodCallExpression.buildNotNull(null, className.name, finalOrWithEmptyInitializerFields.map { initializers[it]!! }) val initializer = MethodCallExpression.buildNotNull(null, className.name, finalOrWithEmptyInitializerFields.map { initializers[it]!! })
initializer.assignNoPrototype() initializer.assignNoPrototype()
val localVar = LocalVariable(SecondaryConstructor.tempValIdentifier(), val localVar = LocalVariable(FactoryFunction.tempValIdentifier(),
Annotations.Empty, Annotations.Empty,
Modifiers.Empty, Modifiers.Empty,
null, null,
initializer, initializer,
true).assignNoPrototype() true).assignNoPrototype()
newStatements.add(0, DeclarationStatement(listOf(localVar)).assignNoPrototype()) statements.add(0, DeclarationStatement(listOf(localVar)).assignNoPrototype())
constructor.block = Block(newStatements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype() statements.add(ReturnStatement(FactoryFunction.tempValIdentifier()).assignNoPrototype())
factoryFunction.body = Block(statements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
} }
val parameters = finalOrWithEmptyInitializerFields.map { field -> val parameters = finalOrWithEmptyInitializerFields.map { field ->
@@ -271,7 +276,31 @@ public class Converter private(val project: Project, val settings: ConverterSett
val parameterList = ParameterList(parameters).assignNoPrototype() val parameterList = ParameterList(parameters).assignNoPrototype()
val constructorSignature = PrimaryConstructorSignature(modifiers, parameterList).assignNoPrototype() val constructorSignature = PrimaryConstructorSignature(modifiers, parameterList).assignNoPrototype()
val updatedMembers = classBody.members.filter { !finalOrWithEmptyInitializerFields.contains(it) } val updatedMembers = classBody.members.filter { !finalOrWithEmptyInitializerFields.contains(it) }
return ClassBody(constructorSignature, updatedMembers, classBody.secondaryConstructors, classBody.classObjectMembers, classBody.lBrace, classBody.rBrace) return ClassBody(constructorSignature, updatedMembers, classBody.classObjectMembers, classBody.lBrace, classBody.rBrace)
}
private fun correctFactoryFunctions(classBody: ClassBody, className: String) {
for (factoryFunction in classBody.factoryFunctions()) {
val body = factoryFunction.body!!
val statements = ArrayList(body.statements)
// searching for other constructor call in form "this(...)"
// it's not necessary the first statement because of statements inserted for writable parameters
for (i in statements.indices) {
val statement = statements[i]
if (statement is MethodCallExpression) {
if ((statement.methodExpression as? Identifier)?.name == "this") {
val constructorCall = MethodCallExpression.buildNotNull(null, className, statement.arguments).assignPrototypesFrom(statement)
val localVar = LocalVariable(FactoryFunction.tempValIdentifier(), Annotations.Empty, Modifiers.Empty, null, constructorCall, true).assignNoPrototype()
statements[i] = DeclarationStatement(listOf(localVar)).assignNoPrototype()
break
}
}
}
statements.add(ReturnStatement(FactoryFunction.tempValIdentifier()).assignNoPrototype())
factoryFunction.body = Block(statements, body.lBrace, body.rBrace).assignPrototypesFrom(body)
}
} }
private fun convertInitializer(initializer: PsiClassInitializer): Initializer { private fun convertInitializer(initializer: PsiClassInitializer): Initializer {
@@ -344,11 +373,11 @@ public class Converter private(val project: Project, val settings: ConverterSett
return false return false
} }
private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>): Function { private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>): Member {
return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove).assignPrototype(method) return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove).assignPrototype(method)
} }
private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>): Function { private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>): Member {
val returnType = typeConverter.convertMethodReturnType(method) val returnType = typeConverter.convertMethodReturnType(method)
val annotations = (convertAnnotations(method) + convertThrows(method)).assignNoPrototype() val annotations = (convertAnnotations(method) + convertThrows(method)).assignNoPrototype()
@@ -382,7 +411,13 @@ public class Converter private(val project: Project, val settings: ConverterSett
else { else {
val params = convertParameterList(method.getParameterList()) val params = convertParameterList(method.getParameterList())
var body = postProcessBody(convertBlock(method.getBody())) var body = postProcessBody(convertBlock(method.getBody()))
return SecondaryConstructor(this, annotations, modifiers, params, body) val containingClass = method.getContainingClass()
val typeParameterList = convertTypeParameterList(containingClass?.getTypeParameterList())
val factoryFunctionType = ClassType(containingClass?.declarationIdentifier() ?: Identifier.Empty,
typeParameterList.parameters,
Nullability.NotNull,
settings).assignNoPrototype()
return FactoryFunction(annotations, modifiers, factoryFunctionType, params, typeParameterList, body)
} }
} }
else { else {
@@ -404,7 +439,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
var params = convertParameterList(method.getParameterList()) var params = convertParameterList(method.getParameterList())
val typeParameterList = convertTypeParameterList(method.getTypeParameterList()) val typeParameterList = convertTypeParameterList(method.getTypeParameterList())
var body = postProcessBody(convertBlock(method.getBody())) var body = postProcessBody(convertBlock(method.getBody()))
return Function(this, method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, body, containingClass?.isInterface() ?: false) return Function(method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, body, containingClass?.isInterface() ?: false)
} }
} }
@@ -499,7 +534,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
convertModifiers(field).filter { it in ACCESS_MODIFIERS }).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false)) convertModifiers(field).filter { it in ACCESS_MODIFIERS }).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false))
} }
}).assignPrototype(constructor.getParameterList()) }).assignPrototype(constructor.getParameterList())
return PrimaryConstructor(this, annotations, modifiers, parameterList, block).assignPrototype(constructor) return PrimaryConstructor(annotations, modifiers, parameterList, block).assignPrototype(constructor)
} }
private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? { private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? {
@@ -21,6 +21,6 @@ import org.jetbrains.jet.j2k.CodeBuilder
class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean)
: Class(Identifier.Empty, Annotations.Empty, Modifiers.Empty, TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { : Class(Identifier.Empty, Annotations.Empty, Modifiers.Empty, TypeParameterList.Empty, listOf(), listOf(), listOf(), body) {
override fun generateCode(builder: CodeBuilder) { override fun generateCode(builder: CodeBuilder) {
body.append(builder, null) body.append(builder)
} }
} }
+1 -1
View File
@@ -41,7 +41,7 @@ open class Class(
} }
appendBaseTypes(builder) appendBaseTypes(builder)
typeParameterList.appendWhere(builder) typeParameterList.appendWhere(builder)
body.append(builder, this) body.append(builder)
} }
protected open val keyword: String protected open val keyword: String
@@ -20,30 +20,29 @@ import org.jetbrains.jet.j2k.*
abstract class Member(val annotations: Annotations, val modifiers: Modifiers) : Element() abstract class Member(val annotations: Annotations, val modifiers: Modifiers) : Element()
//TODO: should be Element?
class ClassBody ( class ClassBody (
val primaryConstructorSignature: PrimaryConstructorSignature?, val primaryConstructorSignature: PrimaryConstructorSignature?,
val members: List<Member>, val members: List<Member>,
val secondaryConstructors: List<SecondaryConstructor>,
val classObjectMembers: List<Member>, val classObjectMembers: List<Member>,
val lBrace: LBrace, val lBrace: LBrace,
val rBrace: RBrace) { val rBrace: RBrace) {
fun append(builder: CodeBuilder, containingClass: Class?) { fun append(builder: CodeBuilder) {
if (members.isEmpty() && classObjectMembers.isEmpty() && secondaryConstructors.isEmpty()) return if (members.isEmpty() && classObjectMembers.isEmpty()) return
builder append " " append lBrace append "\n" builder append " " append lBrace append "\n"
builder.append(members, "\n") builder.append(members, "\n")
appendClassObject(builder, containingClass, members.isNotEmpty()) appendClassObject(builder, members.isNotEmpty())
builder append "\n" append rBrace builder append "\n" append rBrace
} }
private fun appendClassObject(builder: CodeBuilder, containingClass: Class?, blankLineBefore: Boolean) { private fun appendClassObject(builder: CodeBuilder, blankLineBefore: Boolean) {
if (secondaryConstructors.isEmpty() && classObjectMembers.isEmpty()) return if (classObjectMembers.isEmpty()) return
if (blankLineBefore) builder.append("\n\n") if (blankLineBefore) builder.append("\n\n")
val factoryFunctions = secondaryConstructors.map { it.toFactoryFunction(containingClass) } builder.append(classObjectMembers, "\n", "class object {\n", "\n}")
builder.append(factoryFunctions + classObjectMembers, "\n", "class object {\n", "\n}")
} }
} }
@@ -16,37 +16,26 @@
package org.jetbrains.jet.j2k.ast package org.jetbrains.jet.j2k.ast
import java.util.ArrayList
import org.jetbrains.jet.j2k.* import org.jetbrains.jet.j2k.*
import com.intellij.util.IncorrectOperationException import com.intellij.util.IncorrectOperationException
abstract class Constructor( class PrimaryConstructor(annotations: Annotations,
converter: Converter, modifiers: Modifiers,
annotations: Annotations, val parameterList: ParameterList,
modifiers: Modifiers, val block: Block)
parameterList: ParameterList, : Member(annotations, modifiers) {
block: Block
) : Function(converter, Identifier.Empty, annotations, modifiers, ErrorType(), TypeParameterList.Empty, parameterList, block, false) {
override fun generateCode(builder: CodeBuilder) { throw IncorrectOperationException() } override fun generateCode(builder: CodeBuilder) { throw IncorrectOperationException() }
}
class PrimaryConstructor(converter: Converter,
annotations: Annotations,
modifiers: Modifiers,
parameterList: ParameterList,
block: Block)
: Constructor(converter, annotations, modifiers, parameterList, block) {
public fun initializer(): Initializer? { public fun initializer(): Initializer? {
return if (!block!!.isEmpty) return if (!block.isEmpty)
Initializer(block!!, Modifiers.Empty).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false)) Initializer(block, Modifiers.Empty).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false))
else else
null null
} }
public fun signature(): PrimaryConstructorSignature { public fun signature(): PrimaryConstructorSignature {
val noBody = block!!.isEmpty val noBody = block.isEmpty
val inheritance = CommentsAndSpacesInheritance(blankLinesBefore = false, commentsAfter = noBody, commentsInside = noBody) val inheritance = CommentsAndSpacesInheritance(blankLinesBefore = false, commentsAfter = noBody, commentsInside = noBody)
return PrimaryConstructorSignature(modifiers, parameterList).assignPrototypesFrom(this, inheritance) return PrimaryConstructorSignature(modifiers, parameterList).assignPrototypesFrom(this, inheritance)
} }
@@ -63,13 +52,15 @@ class PrimaryConstructorSignature(val modifiers: Modifiers, val parameterList: P
} }
} }
class SecondaryConstructor(converter: Converter, class FactoryFunction(annotations: Annotations,
annotations: Annotations, modifiers: Modifiers,
modifiers: Modifiers, returnType: Type,
parameterList: ParameterList, parameterList: ParameterList,
block: Block) typeParameterList: TypeParameterList,
: Constructor(converter, annotations, modifiers, parameterList, block) { block: Block)
: Function(Identifier("create").assignNoPrototype(), annotations, modifiers, returnType, typeParameterList, parameterList, block, false) {
/*
public fun toFactoryFunction(containingClass: Class?): Function { public fun toFactoryFunction(containingClass: Class?): Function {
val statements = ArrayList(block?.statements ?: listOf()) val statements = ArrayList(block?.statements ?: listOf())
statements.add(ReturnStatement(tempValIdentifier()).assignNoPrototype()) statements.add(ReturnStatement(tempValIdentifier()).assignNoPrototype())
@@ -85,6 +76,7 @@ class SecondaryConstructor(converter: Converter,
return Function(converter, Identifier("create").assignNoPrototype(), annotations, modifiers, return Function(converter, Identifier("create").assignNoPrototype(), annotations, modifiers,
returnType, typeParameterList, parameterList, newBlock, false).assignPrototypesFrom(this) returnType, typeParameterList, parameterList, newBlock, false).assignPrototypesFrom(this)
} }
*/
class object { class object {
public val tempValName: String = "__" public val tempValName: String = "__"
+1 -1
View File
@@ -37,6 +37,6 @@ class Enum(
} }
builder append typeParameterList builder append typeParameterList
appendBaseTypes(builder) appendBaseTypes(builder)
body.append(builder, this) body.append(builder)
} }
} }
@@ -19,14 +19,13 @@ package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.* import org.jetbrains.jet.j2k.*
open class Function( open class Function(
val converter: Converter,
val name: Identifier, val name: Identifier,
annotations: Annotations, annotations: Annotations,
modifiers: Modifiers, modifiers: Modifiers,
val `type`: Type, val `type`: Type,
val typeParameterList: TypeParameterList, val typeParameterList: TypeParameterList,
val parameterList: ParameterList, val parameterList: ParameterList,
var block: Block?, var body: Block?,
val isInTrait: Boolean val isInTrait: Boolean
) : Member(annotations, modifiers) { ) : Member(annotations, modifiers) {
@@ -59,8 +58,8 @@ open class Function(
typeParameterList.appendWhere(builder) typeParameterList.appendWhere(builder)
if (block != null) { if (body != null) {
builder append " " append block!! builder append " " append body!!
} }
} }
} }
@@ -318,10 +318,7 @@ class ExpressionVisitor(private val converter: Converter,
val insideSecondaryConstructor = containingConstructor != null && !containingConstructor.isPrimaryConstructor() val insideSecondaryConstructor = containingConstructor != null && !containingConstructor.isPrimaryConstructor()
if (insideSecondaryConstructor && (expression.getReference()?.resolve() as? PsiField)?.getContainingClass() == containingConstructor!!.getContainingClass()) { if (insideSecondaryConstructor && (expression.getReference()?.resolve() as? PsiField)?.getContainingClass() == containingConstructor!!.getContainingClass()) {
identifier = QualifiedExpression(SecondaryConstructor.tempValIdentifier(), Identifier(referencedName, isNullable).assignNoPrototype()) identifier = QualifiedExpression(FactoryFunction.tempValIdentifier(), Identifier(referencedName, isNullable).assignNoPrototype())
}
else if (insideSecondaryConstructor && expression.isThisConstructorCall()) {
identifier = Identifier("val __ = " + (containingConstructor?.getContainingClass()?.getNameIdentifier()?.getText() ?: "")).assignNoPrototype()
} }
else if (qualifier != null && qualifier.getType() is PsiArrayType && referencedName == "length") { else if (qualifier != null && qualifier.getType() is PsiArrayType && referencedName == "length") {
identifier = Identifier("size", isNullable).assignNoPrototype() identifier = Identifier("size", isNullable).assignNoPrototype()