New J2K: WIP: Field to property conversion

This commit is contained in:
Simon Ogorodnik
2018-08-22 22:03:08 +03:00
committed by Ilya Kirillov
parent dbf4ba536f
commit e0d3ff7507
@@ -5,10 +5,14 @@
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ast.Mutability
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.JKBlockImpl
import org.jetbrains.kotlin.j2k.tree.impl.JKKtPropertyImpl
import org.jetbrains.kotlin.j2k.tree.impl.mutability
import org.jetbrains.kotlin.j2k.tree.impl.visibility
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class FieldToPropertyConversion : RecursiveApplicableConversionBase() {
@@ -35,14 +39,14 @@ class FieldToPropertyConversion : RecursiveApplicableConversionBase() {
when (it) {
is JKJavaField -> propertyInfoFor(it.name.value).field = it
is JKJavaMethod -> {
it.getterFor()?.let { field -> propertyInfoFor(field.name.value).getter = it }
?: it.setterFor()?.let { field -> propertyInfoFor(field.name.value).setter = it }
propertyNameFromGet(it)?.let { fieldName -> propertyInfoFor(fieldName).getter = it }
?: propertyNameFromSet(it)?.let { fieldName -> propertyInfoFor(fieldName).setter = it }
}
}
}
propertyInfos.forEach { (_, info) ->
for ((_, info) in propertyInfos) {
val field = info.field
if (field != null) {
@@ -52,8 +56,19 @@ class FieldToPropertyConversion : RecursiveApplicableConversionBase() {
JKKtPropertyImpl(field.modifierList, field.type, field.name, field.initializer, JKBlockImpl(), JKBlockImpl())
declarations.remove(field)
declarations.remove(info.getter)
declarations.remove(info.setter)
val getter = info.getter
if (getter?.fieldFromGetter(field.name.value) == field) {
declarations.remove(getter)
property.modifierList.mutability = Mutability.NonMutable
property.modifierList.visibility = minOf(getter.modifierList.visibility, property.modifierList.visibility)
}
val setter = info.setter
if (setter?.fieldFromSetter(field.name.value) == field) {
declarations.remove(setter)
property.modifierList.mutability = Mutability.Mutable
property.modifierList.visibility = minOf(setter.modifierList.visibility, property.modifierList.visibility)
}
declarations.add(property)
}
}
@@ -64,19 +79,55 @@ class FieldToPropertyConversion : RecursiveApplicableConversionBase() {
}
private fun JKMethod.getterFor(): JKJavaField? {
if (JvmAbi.isGetterName(name.value)) return null
if (this.parameters.isNotEmpty()) return null
private fun propertyNameFromGet(method: JKMethod): String? {
if (!JvmAbi.isGetterName(method.name.value)) return null
if (method.parameters.isNotEmpty()) return null
if (method !is JKJavaMethod) return null
return method.name.value
.removePrefix("get")
.removePrefix("is")
.decapitalize()
}
private fun propertyNameFromSet(method: JKMethod): String? {
if (!JvmAbi.isSetterName(method.name.value)) return null
if (method.parameters.size != 1) return null
if (method !is JKJavaMethod) return null
return method.name.value
.removePrefix("set")
.decapitalize()
}
private fun JKExpression.unboxFieldReference(): JKFieldAccessExpression? = when {
this is JKFieldAccessExpression -> this
this is JKQualifiedExpression && receiver is JKThisExpression -> selector as? JKFieldAccessExpression
else -> null
}
private fun JKMethod.fieldFromGetter(propertyName: String): JKJavaField? {
if (this !is JKJavaMethod) return null
val returnStatement = block.statements.singleOrNull() as? JKReturnStatement ?: return null
val fieldAccess = returnStatement.expression as? JKFieldAccessExpression ?: return null
val fieldAccess = returnStatement.expression.unboxFieldReference() ?: return null
val field = fieldAccess.identifier.target as? JKJavaField ?: return null
if (name.value.endsWith(field.name.value)) return field
return null
if (propertyName != field.name.value) return null
return field
}
fun JKMethod.setterFor(): JKJavaField? {
return null
private fun JKMethod.fieldFromSetter(propertyName: String): JKJavaField? {
if (this !is JKJavaMethod) return null
val expressionStatement = this.block.statements.singleOrNull() as? JKExpressionStatement ?: return null
val assignment = expressionStatement.expression as? JKJavaAssignmentExpression ?: return null
val lhs = assignment.field
val fieldAccess = lhs.unboxFieldReference()
val target = fieldAccess?.identifier?.target as? JKJavaField ?: return null
if (propertyName != target.name.value) return null
return target
}
private data class AccessorInfo(
val method: JKMethod,
val field: JKField?,
val propertyName: String
)
}