New J2K: WIP: New field to property conversion

This commit is contained in:
Simon Ogorodnik
2018-05-16 01:00:55 +03:00
committed by Ilya Kirillov
parent edd23c7a83
commit a55591011a
4 changed files with 126 additions and 22 deletions
@@ -16,7 +16,7 @@
package org.jetbrains.kotlin.j2k
import org.jetbrains.kotlin.j2k.conversions.JavaFieldToKotlinPropertyConversion
import org.jetbrains.kotlin.j2k.conversions.FieldToPropertyConversion
import org.jetbrains.kotlin.j2k.conversions.JavaMethodToKotlinFunctionConversion
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
@@ -25,7 +25,7 @@ object ConversionsRunner {
fun doApply(trees: List<JKTreeElement>) {
trees.forEach {
JavaFieldToKotlinPropertyConversion().runConversion(it)
FieldToPropertyConversion().runConversion(it)
JavaMethodToKotlinFunctionConversion().runConversion(it)
}
}
@@ -0,0 +1,93 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k.conversions
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.load.java.JvmAbi
class FieldToPropertyConversion : MatchBasedConversion() {
override fun onElementChanged(new: JKTreeElement, old: JKTreeElement) {
somethingChanged = true
}
var somethingChanged = false
override fun runConversion(treeRoot: JKTreeElement): Boolean {
val root = applyToElement(treeRoot)
assert(root === treeRoot)
return somethingChanged
}
data class PropertyInfo(
val name: String,
var setter: JKMethod? = null,
var getter: JKMethod? = null,
var field: JKJavaField? = null
)
fun applyToElement(element: JKTreeElement): JKTreeElement {
if (element !is JKUDeclarationList) return applyRecursive(element, this::applyToElement)
val propertyInfos = mutableMapOf<String, PropertyInfo>()
fun propertyInfoFor(name: String): PropertyInfo {
return propertyInfos.getOrPut(name) {
PropertyInfo(name)
}
}
val declarations = element.declarations.toMutableList()
declarations.forEach {
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 }
}
}
}
propertyInfos.forEach { (_, info) ->
val field = info.field
if (field != null) {
// TODO: proper accessors
val property =
JKKtPropertyImpl(field.modifierList, field.type, field.name, field.initializer, JKBlockImpl(), JKBlockImpl())
declarations.remove(field)
declarations.remove(info.getter)
declarations.remove(info.setter)
declarations.add(property)
}
}
element.declarations = declarations
return element
}
private fun JKMethod.getterFor(): JKJavaField? {
if (JvmAbi.isGetterName(name.value)) return null
if (this.valueArguments.isNotEmpty()) return null
if (this !is JKJavaMethod) return null
val returnStatement = block.statements.singleOrNull() as? JKReturnStatement ?: return null
val fieldAccess = returnStatement.expression as? JKFieldAccessExpression ?: return null
val field = fieldAccess.identifier.target as? JKJavaField ?: return null
if (name.value.endsWith(field.name.value)) return field
return null
}
fun JKMethod.setterFor(): JKJavaField? {
return null
}
}
@@ -25,26 +25,6 @@ import org.jetbrains.kotlin.j2k.tree.impl.JKJavaPrimitiveTypeImpl
import org.jetbrains.kotlin.j2k.tree.impl.JKKtFunctionImpl
import org.jetbrains.kotlin.j2k.tree.impl.JKKtPropertyImpl
class JavaFieldToKotlinPropertyConversion : TransformerBasedConversion() {
override fun visitElement(element: JKTreeElement) {
element.acceptChildren(this, null)
}
override fun visitUniverseClass(universeClass: JKUniverseClass) {
somethingChanged = true
universeClass.declarationList.declarations = universeClass.declarationList.declarations.map {
if (it is JKJavaField) JKKtPropertyImpl(
it.modifierList,
it.type,
it.name,
it.initializer,
JKBlockImpl(),
JKBlockImpl()
) else it
}
}
}
class JavaMethodToKotlinFunctionConversion : TransformerBasedConversion() {
override fun visitElement(element: JKTreeElement) {
element.acceptChildren(this, null)
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
import org.jetbrains.kotlin.j2k.tree.impl.JKMutableBranchElement
abstract class MatchBasedConversion : BaseConversion() {
fun applyRecursive(element: JKTreeElement, func: (JKTreeElement) -> JKTreeElement): JKTreeElement {
if (element is JKMutableBranchElement) {
val iter = element.children.listIterator()
while (iter.hasNext()) {
val child = iter.next()
val newChild = func(child)
if (child !== newChild) {
onElementChanged(newChild, child)
child.parent = null
newChild.parent = element
iter.set(newChild)
}
}
}
return element
}
abstract fun onElementChanged(new: JKTreeElement, old: JKTreeElement)
}