Java to Kotlin converter: secondary constructors are converted to top-level functions instead of "create" functions in class object

This commit is contained in:
Valentin Kipyatkov
2014-06-26 20:01:28 +04:00
parent f698ca69d7
commit 66005a3469
25 changed files with 225 additions and 256 deletions
@@ -43,10 +43,10 @@ class ConstructorConverter(private val converter: Converter) {
val member = expression.getReference()?.resolve() as? PsiMember
if (member != null &&
!member.isConstructor() &&
member.getContainingClass() == constructor.getContainingClass() &&
!member.hasModifierProperty(PsiModifier.STATIC)) {
member.getContainingClass() == constructor.getContainingClass()) {
val isNullable = member is PsiField && typeConverter.variableNullability(member).isNullable(converter.settings)
result = QualifiedExpression(tempValIdentifier(), Identifier(expression.getReferenceName()!!, isNullable).assignNoPrototype())
val qualifier = if (member.hasModifierProperty(PsiModifier.STATIC)) constructor.declarationIdentifier() else tempValIdentifier()
result = QualifiedExpression(qualifier, Identifier(expression.getReferenceName()!!, isNullable).assignNoPrototype())
return
}
}
@@ -61,7 +61,7 @@ class ConstructorConverter(private val converter: Converter) {
typeParameterList.parameters,
Nullability.NotNull,
converter.settings).assignNoPrototype()
return FactoryFunction(annotations, modifiers, factoryFunctionType, params, typeParameterList, body)
return FactoryFunction(constructor.declarationIdentifier(), annotations, modifiers, factoryFunctionType, params, typeParameterList, body)
}
}
@@ -176,12 +176,13 @@ class ConstructorConverter(private val converter: Converter) {
assert(classBody.primaryConstructorSignature == null)
val fieldsToInitialize = classBody.members.filterIsInstance(javaClass<Field>()).filter { it.isVal }
for (factoryFunction in classBody.factoryFunctions()) {
for (factoryFunction in classBody.factoryFunctions) {
val body = factoryFunction.body!!
// 2 cases: secondary constructor either calls another constructor or does not call any
val newStatements = replaceConstructorCallInFactoryFunction(body, className) ?:
insertCallToArtificialPrimary(body, className, fieldsToInitialize)
factoryFunction.body = Block(newStatements, LBrace().assignNoPrototype(), RBrace().assignNoPrototype()).assignNoPrototype()
//TODO: no assignment here
}
val parameters = fieldsToInitialize.map { field ->
@@ -189,15 +190,17 @@ class ConstructorConverter(private val converter: Converter) {
Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { it in ACCESS_MODIFIERS }).assignPrototypesFrom(field)
}
val modifiers = Modifiers(listOf(Modifier.PRIVATE)).assignNoPrototype()
val modifiers = Modifiers.Empty
//TODO: we can generate it private when secondary constructors are supported by Kotlin
//val modifiers = Modifiers(listOf(Modifier.PRIVATE)).assignNoPrototype()
val parameterList = ParameterList(parameters).assignNoPrototype()
val constructorSignature = PrimaryConstructorSignature(modifiers, parameterList).assignNoPrototype()
val updatedMembers = classBody.members.filter { !fieldsToInitialize.contains(it) }
return ClassBody(constructorSignature, updatedMembers, classBody.classObjectMembers, classBody.lBrace, classBody.rBrace)
return ClassBody(constructorSignature, updatedMembers, classBody.classObjectMembers, classBody.factoryFunctions, classBody.lBrace, classBody.rBrace)
}
private fun replaceConstructorCallsInFactoryFunctions(classBody: ClassBody, className: String) {
for (factoryFunction in classBody.factoryFunctions()) {
for (factoryFunction in classBody.factoryFunctions) {
val body = factoryFunction.body!!
val statements = replaceConstructorCallInFactoryFunction(body, className)
if (statements != null) {
@@ -278,8 +281,6 @@ class ConstructorConverter(private val converter: Converter) {
return statements
}
private fun ClassBody.factoryFunctions() = classObjectMembers.filterIsInstance(javaClass<FactoryFunction>())
private val tempValName: String = "__"
private fun tempValIdentifier(): Identifier = Identifier(tempValName, false).assignNoPrototype()
}
+6 -4
View File
@@ -125,6 +125,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
val members = ArrayList<Member>()
val classObjectMembers = ArrayList<Member>()
val factoryFunctions = ArrayList<FactoryFunction>()
var primaryConstructorSignature: PrimaryConstructorSignature? = null
for ((psiMember, member) in convertedMembers) {
if (member is PrimaryConstructor) {
@@ -135,8 +136,10 @@ public class Converter private(val project: Project, val settings: ConverterSett
members.add(initializer)
}
}
else if (useClassObject && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC) ||
member is FactoryFunction) {
else if (member is FactoryFunction) {
factoryFunctions.add(member)
}
else if (useClassObject && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) {
classObjectMembers.add(member)
}
else {
@@ -146,13 +149,12 @@ public class Converter private(val project: Project, val settings: ConverterSett
val lBrace = LBrace().assignPrototype(psiClass.getLBrace())
val rBrace = RBrace().assignPrototype(psiClass.getRBrace())
return ClassBody(primaryConstructorSignature, members, classObjectMembers, lBrace, rBrace)
return ClassBody(primaryConstructorSignature, members, classObjectMembers, factoryFunctions, lBrace, rBrace)
}
// do not convert private static methods into class object if possible
private fun shouldGenerateClassObject(psiClass: PsiClass, convertedMembers: Map<PsiMember, Member>): Boolean {
if (psiClass.isEnum()) return false
if (convertedMembers.values().any { it is FactoryFunction }) return true
val members = convertedMembers.keySet().filter { !it.isConstructor() }
val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) }
val nestedClasses = members.filterIsInstance(javaClass<PsiClass>()).filter { it.hasModifierProperty(PsiModifier.STATIC) }
@@ -30,17 +30,22 @@ open class Class(
) : Member(annotations, modifiers) {
override fun generateCode(builder: CodeBuilder) {
builder.append(body.factoryFunctions, "\n", "", "\n\n")
builder.append(annotations)
.appendWithSpaceAfter(presentationModifiers())
.append(keyword)
.append(" ")
.append(name)
.append(typeParameterList)
if (body.primaryConstructorSignature != null) {
builder.append(body.primaryConstructorSignature)
}
appendBaseTypes(builder)
typeParameterList.appendWhere(builder)
body.append(builder)
}
@@ -25,6 +25,7 @@ class ClassBody (
val primaryConstructorSignature: PrimaryConstructorSignature?,
val members: List<Member>,
val classObjectMembers: List<Member>,
val factoryFunctions: List<FactoryFunction>,
val lBrace: LBrace,
val rBrace: RBrace) {
@@ -52,10 +52,11 @@ class PrimaryConstructorSignature(val modifiers: Modifiers, val parameterList: P
}
}
class FactoryFunction(annotations: Annotations,
class FactoryFunction(name: Identifier,
annotations: Annotations,
modifiers: Modifiers,
returnType: Type,
parameterList: ParameterList,
typeParameterList: TypeParameterList,
block: Block)
: Function(Identifier("create").assignNoPrototype(), annotations, modifiers, returnType, typeParameterList, parameterList, block, false)
: Function(name, annotations, modifiers, returnType, typeParameterList, parameterList, block, false)
@@ -31,12 +31,18 @@ class Enum(
extendsTypes, baseClassParams, implementsTypes, body) {
override fun generateCode(builder: CodeBuilder) {
builder.append(body.factoryFunctions, "\n", "", "\n\n")
builder append annotations appendWithSpaceAfter presentationModifiers() append "enum class " append name
if (body.primaryConstructorSignature != null) {
builder.append(body.primaryConstructorSignature)
}
builder append typeParameterList
appendBaseTypes(builder)
body.append(builder)
}
}
@@ -264,18 +264,6 @@ open class ExpressionVisitor(private val converter: Converter,
private fun createNewClassExpression(expression: PsiNewExpression): Expression {
val anonymousClass = expression.getAnonymousClass()
val classReference = expression.getClassOrAnonymousClassReference()
var arguments = expression.getArgumentList()?.getExpressions() ?: array()
val constructor = expression.resolveMethod()
if (constructor != null && converter.conversionScope.contains(constructor) && !constructor.isPrimaryConstructor()) {
//TODO: handle anonymous class!
// non-primary constructor converted to factory method in class object
val reference = expression.getClassReference()
val typeParameters = if (reference != null) typeConverter.convertTypes(reference.getTypeParameters()) else listOf()
return QualifiedExpression(Identifier(constructor.getName(), false).assignNoPrototype(),
MethodCallExpression.buildNotNull(null, "create", converter.convertExpressions(arguments), typeParameters).assignNoPrototype())
}
return NewClassExpression(converter.convertElement(classReference),
convertArguments(expression),
converter.convertExpression(expression.getQualifier()),
@@ -94,10 +94,7 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() {
"using the first line of test data file")
}
val reformatInFun = when (prefix) {
"element", "expression", "statement" -> true
else -> false
}
val reformatInFun = prefix in setOf("element", "expression", "statement")
val actual = reformat(rawConverted, project, reformatInFun)
val kotlinPath = javaPath.replace(".java", ".kt")
+9 -11
View File
@@ -2,23 +2,21 @@ package demo
import java.util.HashMap
class Test private() {
class object {
fun create(): Test {
return Test()
}
fun create(s: String): Test {
return Test()
}
}
fun Test(): Test {
return Test()
}
fun Test(s: String): Test {
return Test()
}
class Test
class User {
fun main() {
val m = HashMap(1)
val m2 = HashMap(10)
val t1 = Test.create()
val t2 = Test.create("")
val t1 = Test()
val t2 = Test("")
}
}
@@ -1,3 +1,8 @@
// this is a secondary constructor
fun A(): A {
return A(1)
} // end of secondary constructor body
class A// this is a primary constructor
(p: Int) {
private val v: Int
@@ -5,14 +10,6 @@ class A// this is a primary constructor
{
v = 1
} // end of primary constructor body
class object {
// this is a secondary constructor
fun create(): A {
return A(1)
} // end of secondary constructor body
}
}
class B// this constructor will disappear
@@ -1,4 +1,6 @@
//file
package pack
class C {
C(int arg1, int arg2, int arg3) {
}
@@ -1,22 +1,22 @@
class C(arg1: Int, arg2: Int, arg3: Int) {
class object {
package pack
fun create(arg1: Int, arg2: Int): C {
return C(arg1, arg2, 0)
}
fun create(arg1: Int): C {
return C(arg1, 0, 0)
}
}
fun C(arg1: Int, arg2: Int): C {
return C(arg1, arg2, 0)
}
fun C(arg1: Int): C {
return C(arg1, 0, 0)
}
class C(arg1: Int, arg2: Int, arg3: Int)
public class User {
class object {
public fun main() {
val c1 = C(100, 100, 100)
val c2 = C.create(100, 100)
val c3 = C.create(100)
val c2 = C(100, 100)
val c3 = C(100)
}
}
}
@@ -1,3 +1,17 @@
fun C(arg1: Int, arg2: Int, arg3: Int): C {
val __ = C(arg1)
__.myArg2 = arg2
__.myArg3 = arg3
return __
}
fun C(arg1: Int, arg2: Int): C {
val __ = C(arg1)
__.myArg2 = arg2
__.myArg3 = 0
return __
}
class C(val myArg1: Int) {
var myArg2: Int = 0
var myArg3: Int = 0
@@ -6,30 +20,13 @@ class C(val myArg1: Int) {
myArg2 = 0
myArg3 = 0
}
class object {
fun create(arg1: Int, arg2: Int, arg3: Int): C {
val __ = C(arg1)
__.myArg2 = arg2
__.myArg3 = arg3
return __
}
fun create(arg1: Int, arg2: Int): C {
val __ = C(arg1)
__.myArg2 = arg2
__.myArg3 = 0
return __
}
}
}
public class User {
class object {
public fun main() {
val c1 = C.create(100, 100, 100)
val c2 = C.create(100, 100)
val c1 = C(100, 100, 100)
val c2 = C(100, 100)
val c3 = C(100)
}
}
+14 -17
View File
@@ -1,26 +1,23 @@
class C(arg1: Int, arg2: Int, arg3: Int) {
class object {
fun create(arg1: Int, arg2: Int): C {
val __ = C(arg1, arg2, 0)
System.out.println()
return __
}
fun create(arg1: Int): C {
val __ = C(arg1, 0)
System.out.println()
return __
}
}
fun C(arg1: Int, arg2: Int): C {
val __ = C(arg1, arg2, 0)
System.out.println()
return __
}
fun C(arg1: Int): C {
val __ = C(arg1, 0)
System.out.println()
return __
}
class C(arg1: Int, arg2: Int, arg3: Int)
public class User {
class object {
public fun main() {
val c1 = C(1, 2, 3)
val c2 = C.create(5, 6)
val c3 = C.create(7)
val c2 = C(5, 6)
val c3 = C(7)
}
}
}
@@ -1,36 +1,33 @@
public class Identifier<T> private(private val myName: T, private val myHasDollar: Boolean) {
public fun <T> Identifier(name: T): Identifier<T> {
return Identifier(name, false)
}
public fun <T> Identifier(name: T, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, false)
__.myNullable = isNullable
return __
}
public fun <T> Identifier(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, hasDollar)
__.myNullable = isNullable
return __
}
public class Identifier<T>(private val myName: T, private val myHasDollar: Boolean) {
private var myNullable = true
public fun getName(): T {
return myName
}
class object {
public fun <T> create(name: T): Identifier<T> {
return Identifier(name, false)
}
public fun <T> create(name: T, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, false)
__.myNullable = isNullable
return __
}
public fun <T> create(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, hasDollar)
__.myNullable = isNullable
return __
}
}
}
public class User {
class object {
public fun main() {
val i1 = Identifier.create<String>("name", false, true)
val i2 = Identifier.create<String>("name", false)
val i3 = Identifier.create<String>("name")
val i1 = Identifier<String>("name", false, true)
val i2 = Identifier<String>("name", false)
val i3 = Identifier<String>("name")
}
}
}
@@ -1,36 +1,33 @@
public class Identifier private(private val myName: String, private val myHasDollar: Boolean) {
public fun Identifier(name: String): Identifier {
return Identifier(name, false)
}
public fun Identifier(name: String, isNullable: Boolean): Identifier {
val __ = Identifier(name, false)
__.myNullable = isNullable
return __
}
public fun Identifier(name: String, hasDollar: Boolean, isNullable: Boolean): Identifier {
val __ = Identifier(name, hasDollar)
__.myNullable = isNullable
return __
}
public class Identifier(private val myName: String, private val myHasDollar: Boolean) {
private var myNullable = true
public fun getName(): String {
return myName
}
class object {
public fun create(name: String): Identifier {
return Identifier(name, false)
}
public fun create(name: String, isNullable: Boolean): Identifier {
val __ = Identifier(name, false)
__.myNullable = isNullable
return __
}
public fun create(name: String, hasDollar: Boolean, isNullable: Boolean): Identifier {
val __ = Identifier(name, hasDollar)
__.myNullable = isNullable
return __
}
}
}
public class User {
class object {
public fun main() {
val i1 = Identifier.create("name", false, true)
val i2 = Identifier.create("name", false)
val i3 = Identifier.create("name")
val i1 = Identifier("name", false, true)
val i2 = Identifier("name", false)
val i3 = Identifier("name")
}
}
}
@@ -1,18 +1,15 @@
fun C(arg1: Int, arg2: Int, other: C): C {
val __ = C(arg1, arg2, 0)
System.out.println(__.foo(1) + __.foo(2) + other.foo(3) + C.staticFoo(4) + C.staticFoo(5))
return __
}
class C(private val arg1: Int, private val arg2: Int, private val arg3: Int) {
fun foo(p: Int): Int {
return p
}
class object {
private fun staticFoo(p: Int): Int {
return p
}
fun create(arg1: Int, arg2: Int, other: C): C {
val __ = C(arg1, arg2, 0)
System.out.println(__.foo(1) + __.foo(2) + other.foo(3) + staticFoo(4) + C.staticFoo(5))
return __
}
private fun staticFoo(p: Int): Int {
return p
}
}
}
@@ -1,29 +1,27 @@
class C private() {
class object {
fun create(arg1: Int, arg2: Int, arg3: Int): C {
return C()
}
fun create(arg1: Int, arg2: Int): C {
val __ = C(arg1, arg2, 0)
System.out.println()
return __
}
fun create(arg: Int): C {
val __ = C()
System.out.println(arg)
return __
}
}
fun C(arg1: Int, arg2: Int, arg3: Int): C {
return C()
}
fun C(arg1: Int, arg2: Int): C {
val __ = C(arg1, arg2, 0)
System.out.println()
return __
}
fun C(arg: Int): C {
val __ = C()
System.out.println(arg)
return __
}
class C
public class User {
class object {
public fun main() {
val c1 = C.create(1, 2, 3)
val c2 = C.create(5, 6)
val c3 = C.create(7)
val c1 = C(1, 2, 3)
val c2 = C(5, 6)
val c3 = C(7)
}
}
}
@@ -1,6 +1,6 @@
//file
class C {
private val field;
private int field;
C(int arg1, int arg2, int arg3) {
arg1++;
@@ -1,5 +1,16 @@
fun C(arg1: Int, arg2: Int): C {
var arg2 = arg2
val __ = C(arg1, arg2, 0)
arg2++
return __
}
fun C(arg1: Int): C {
return C(arg1, 0, 0)
}
class C(arg1: Int, arg2: Int, arg3: Int) {
private val field: `val`
private val field: Int
{
var arg1 = arg1
@@ -9,28 +20,14 @@ class C(arg1: Int, arg2: Int, arg3: Int) {
field = arg3
arg3++
}
class object {
fun create(arg1: Int, arg2: Int): C {
var arg2 = arg2
val __ = C(arg1, arg2, 0)
arg2++
return __
}
fun create(arg1: Int): C {
return C(arg1, 0, 0)
}
}
}
public class User {
class object {
public fun main() {
val c1 = C(100, 100, 100)
val c2 = C.create(100, 100)
val c3 = C.create(100)
val c2 = C(100, 100)
val c3 = C(100)
}
}
}
@@ -1,12 +1,9 @@
class C private(arg1: Int, arg2: Int, arg3: Int) {
class object {
private fun create(arg1: Int, arg2: Int): C {
return C(arg1, arg2, 0)
}
public fun create(arg1: Int): C {
return C(arg1, 0, 0)
}
}
private fun C(arg1: Int, arg2: Int): C {
return C(arg1, arg2, 0)
}
public fun C(arg1: Int): C {
return C(arg1, 0, 0)
}
class C private(arg1: Int, arg2: Int, arg3: Int)
@@ -1,17 +1,14 @@
class C(private val arg1: Int, private val arg2: Int, private val arg3: Int) {
class object {
fun create(arg1: Int, arg2: Int, other: C): C {
val __ = C(arg1, arg2, 0)
System.out.println(__.arg1 + other.arg2)
return __
}
}
fun C(arg1: Int, arg2: Int, other: C): C {
val __ = C(arg1, arg2, 0)
System.out.println(__.arg1 + other.arg2)
return __
}
class C(private val arg1: Int, private val arg2: Int, private val arg3: Int)
class User {
fun foo() {
val c1 = C(100, 100, 100)
val c2 = C.create(100, 100, c1)
val c2 = C(100, 100, c1)
}
}
@@ -1,12 +1,12 @@
fun C(p: Int): C {
val __ = C()
System.out.println(C.staticField1 + C.staticField2)
return __
}
class C {
class object {
private val staticField1 = 0
private val staticField2 = 0
fun create(p: Int): C {
val __ = C()
System.out.println(staticField1 + C.staticField2)
return __
}
}
}
}
@@ -1,4 +1,12 @@
public class Test private(private val myName: String) {
public fun Test(): Test {
return Test(null)
}
public fun Test(name: String): Test {
return Test(Test.foo(name))
}
public class Test(private val myName: String) {
var a: Boolean = false
var b: Double = 0.toDouble()
var c: Float = 0.toFloat()
@@ -9,14 +17,6 @@ public class Test private(private val myName: String) {
class object {
public fun create(): Test {
return Test(null)
}
public fun create(name: String): Test {
return Test(foo(name))
}
fun foo(n: String): String {
return ""
}
@@ -26,7 +26,7 @@ public class Test private(private val myName: String) {
public class User {
class object {
public fun main() {
val t = Test.create("name")
val t = Test("name")
}
}
}
+20 -23
View File
@@ -1,36 +1,33 @@
public class Identifier<T> private(private val myName: T, private val myHasDollar: Boolean) {
public fun <T> Identifier(name: T): Identifier<T> {
return Identifier(name, false)
}
public fun <T> Identifier(name: T, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, false)
__.myNullable = isNullable
return __
}
public fun <T> Identifier(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, hasDollar)
__.myNullable = isNullable
return __
}
public class Identifier<T>(private val myName: T, private val myHasDollar: Boolean) {
private var myNullable = true
public fun getName(): T {
return myName
}
class object {
public fun <T> create(name: T): Identifier<T> {
return Identifier(name, false)
}
public fun <T> create(name: T, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, false)
__.myNullable = isNullable
return __
}
public fun <T> create(name: T, hasDollar: Boolean, isNullable: Boolean): Identifier<T> {
val __ = Identifier(name, hasDollar)
__.myNullable = isNullable
return __
}
}
}
public class User {
class object {
public fun main(args: Array<String>) {
val i1 = Identifier.create<String>("name", false, true)
val i2 = Identifier.create<String>("name", false)
val i3 = Identifier.create<String>("name")
val i1 = Identifier<String>("name", false, true)
val i2 = Identifier<String>("name", false)
val i3 = Identifier<String>("name")
}
}
}