From a55591011a958112a8a35b3c34bc3d13df5cb20f Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Wed, 16 May 2018 01:00:55 +0300 Subject: [PATCH] New J2K: WIP: New field to property conversion --- .../jetbrains/kotlin/j2k/ConversionsRunner.kt | 4 +- .../conversions/FieldToPropertyConversion.kt | 93 +++++++++++++++++++ ...> JavaMethodToKotlinFunctionConversion.kt} | 20 ---- .../j2k/conversions/MatchBasedConversion.kt | 31 +++++++ 4 files changed, 126 insertions(+), 22 deletions(-) create mode 100644 j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt rename j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/{JavaFieldToKotlinPropertyConversion.kt => JavaMethodToKotlinFunctionConversion.kt} (72%) create mode 100644 j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/MatchBasedConversion.kt diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt index 3e68ea52c42..202605d0319 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt @@ -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) { trees.forEach { - JavaFieldToKotlinPropertyConversion().runConversion(it) + FieldToPropertyConversion().runConversion(it) JavaMethodToKotlinFunctionConversion().runConversion(it) } } diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt new file mode 100644 index 00000000000..0a4c75a551b --- /dev/null +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt @@ -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() + + 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 + } + +} diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/JavaFieldToKotlinPropertyConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/JavaMethodToKotlinFunctionConversion.kt similarity index 72% rename from j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/JavaFieldToKotlinPropertyConversion.kt rename to j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/JavaMethodToKotlinFunctionConversion.kt index faa1cda5724..4d1be1f7a73 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/JavaFieldToKotlinPropertyConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/JavaMethodToKotlinFunctionConversion.kt @@ -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) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/MatchBasedConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/MatchBasedConversion.kt new file mode 100644 index 00000000000..81563b6aa22 --- /dev/null +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/MatchBasedConversion.kt @@ -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) +} \ No newline at end of file