New J2K: Add dummy field to property conversion
This commit is contained in:
committed by
Ilya Kirillov
parent
e0ac21c4ad
commit
a30311da45
@@ -94,6 +94,9 @@ object J2KPostProcessingRegistrar {
|
||||
registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection())
|
||||
registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection())
|
||||
registerGeneralInspectionBasedProcessing(RedundantUnitReturnTypeInspection())
|
||||
registerGeneralInspectionBasedProcessing(RedundantGetterInspection())
|
||||
registerGeneralInspectionBasedProcessing(RedundantSetterInspection())
|
||||
|
||||
_processings.add(RemoveExplicitPropertyType())
|
||||
registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false))
|
||||
|
||||
|
||||
@@ -278,6 +278,14 @@ class NewCodeBuilder {
|
||||
printer.printWithNoIndent(" = ")
|
||||
ktProperty.initializer.accept(this)
|
||||
}
|
||||
if (ktProperty.getter !is JKKtEmptyGetterOrSetter) {
|
||||
printer.printlnWithNoIndent()
|
||||
ktProperty.getter.accept(this)
|
||||
}
|
||||
if (ktProperty.setter !is JKKtEmptyGetterOrSetter) {
|
||||
printer.printlnWithNoIndent()
|
||||
ktProperty.setter.accept(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitEnumConstant(enumConstant: JKEnumConstant) {
|
||||
@@ -381,6 +389,29 @@ class NewCodeBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitKtGetterOrSetter(ktGetterOrSetter: JKKtGetterOrSetter) {
|
||||
printer.indented {
|
||||
ktGetterOrSetter.modifierList.accept(this)
|
||||
printer.printWithNoIndent(" ")
|
||||
when (ktGetterOrSetter.kind) {
|
||||
JKKtGetterOrSetter.Kind.GETTER -> printer.printWithNoIndent("get")
|
||||
JKKtGetterOrSetter.Kind.SETTER -> printer.printWithNoIndent("set")
|
||||
}
|
||||
if (!ktGetterOrSetter.body.isEmpty()) {
|
||||
when (ktGetterOrSetter.kind) {
|
||||
JKKtGetterOrSetter.Kind.GETTER -> printer.printWithNoIndent("() ")
|
||||
JKKtGetterOrSetter.Kind.SETTER -> printer.printWithNoIndent("(value) ")
|
||||
}
|
||||
ktGetterOrSetter.body.accept(this)
|
||||
}
|
||||
}
|
||||
printer.printlnWithNoIndent()
|
||||
}
|
||||
|
||||
override fun visitKtEmptyGetterOrSetter(ktEmptyGetterOrSetter: JKKtEmptyGetterOrSetter) {
|
||||
|
||||
}
|
||||
|
||||
override fun visitBinaryExpression(binaryExpression: JKBinaryExpression) {
|
||||
binaryExpression.left.accept(this)
|
||||
printer.printWithNoIndent(" ")
|
||||
|
||||
@@ -5,24 +5,110 @@
|
||||
|
||||
package org.jetbrains.kotlin.j2k.conversions
|
||||
|
||||
import org.jetbrains.kotlin.j2k.ConversionContext
|
||||
import org.jetbrains.kotlin.j2k.ast.Mutability
|
||||
import org.jetbrains.kotlin.j2k.copyTreeAndDetach
|
||||
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.j2k.tree.impl.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class FieldToPropertyConversion : RecursiveApplicableConversionBase() {
|
||||
|
||||
data class PropertyInfo(
|
||||
class FieldToPropertyConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
||||
private data class PropertyInfo(
|
||||
val name: String,
|
||||
var setter: JKMethod? = null,
|
||||
var getter: JKMethod? = null,
|
||||
var setter: AccessorInfo? = null,
|
||||
var getter: AccessorInfo? = null,
|
||||
var field: JKJavaField? = null
|
||||
)
|
||||
|
||||
private data class AccessorInfo(
|
||||
var method: JKMethod,
|
||||
val target: JKJavaField?
|
||||
)
|
||||
|
||||
private fun AccessorInfo.isTrivialFor(field: JKJavaField) =
|
||||
target == field
|
||||
|
||||
private fun <T : JKTreeElement> T.renamed(
|
||||
fromName: String,
|
||||
toName: String,
|
||||
type: JKType,
|
||||
renameType: RenameType
|
||||
): T =
|
||||
also {
|
||||
Renamer(fromName, toName, type, renameType).runConversion(it, context)
|
||||
}
|
||||
|
||||
private fun PropertyInfo.toKtProperty(): JKKtProperty? {
|
||||
val propertyField = field
|
||||
?: getter?.method
|
||||
?.takeIf { propertyNameFromGet(it) != null }
|
||||
?.let {
|
||||
JKJavaFieldImpl(
|
||||
JKModifierListImpl(),
|
||||
JKTypeElementImpl(it.returnType.type),
|
||||
JKNameIdentifierImpl(propertyNameFromGet(it)!!),
|
||||
JKStubExpressionImpl()
|
||||
)
|
||||
}
|
||||
?: return null
|
||||
|
||||
val ktGetter = getter?.let {
|
||||
val method = it.method
|
||||
val block = if (it.isTrivialFor(propertyField)) JKBodyStub else method::block.detached()
|
||||
JKKtGetterOrSetterImpl(
|
||||
JKBlockStatementImpl(block)
|
||||
.renamed(propertyField.name.value, "field", propertyField.type.type, RenameType.RENAME_FIELD_ACCESS),
|
||||
JKModifierListImpl(JKAccessModifierImpl(method.modifierList.visibility)),
|
||||
JKKtGetterOrSetter.Kind.GETTER
|
||||
)
|
||||
} ?: JKKtGetterOrSetterImpl(
|
||||
JKBlockStatementImpl(JKBodyStub),
|
||||
JKModifierListImpl(JKAccessModifierImpl(propertyField.modifierList.visibility)),
|
||||
JKKtGetterOrSetter.Kind.GETTER
|
||||
)
|
||||
|
||||
val ktSetter = setter?.let {
|
||||
val method = it.method
|
||||
val block = if (it.isTrivialFor(propertyField)) JKBodyStub else method::block.detached()
|
||||
JKKtGetterOrSetterImpl(
|
||||
JKBlockStatementImpl(block)
|
||||
.renamed(
|
||||
method.parameters.single().name.value,
|
||||
"value",
|
||||
method.parameters.single().type.type,
|
||||
RenameType.RENAME_PARAMETER_ACCESS
|
||||
)
|
||||
.renamed(propertyField.name.value, "field", propertyField.type.type, RenameType.RENAME_FIELD_ACCESS),
|
||||
JKModifierListImpl(JKAccessModifierImpl(method.modifierList.visibility)),
|
||||
JKKtGetterOrSetter.Kind.SETTER
|
||||
)
|
||||
} ?: JKKtEmptyGetterOrSetterImpl()
|
||||
propertyField.invalidate()
|
||||
|
||||
return JKKtPropertyImpl(
|
||||
propertyField.modifierList,
|
||||
propertyField.type,
|
||||
propertyField.name,
|
||||
propertyField.initializer,
|
||||
ktGetter,
|
||||
ktSetter
|
||||
).also {
|
||||
it.modifierList.mutability =
|
||||
if (it.modifierList.visibilityOrNull() == JKAccessModifier.Visibility.PRIVATE && ktSetter is JKKtEmptyGetterOrSetter)
|
||||
Mutability.NonMutable
|
||||
else Mutability.Mutable
|
||||
|
||||
it.modifierList.visibility =
|
||||
listOf(
|
||||
ktGetter.modifierList.visibility,
|
||||
ktGetter.modifierList.visibility
|
||||
).min() ?: JKAccessModifier.Visibility.PUBLIC
|
||||
}
|
||||
}
|
||||
|
||||
private fun JKJavaMethod.isGetterOrSetter() =
|
||||
propertyNameFromGet(this) != null || propertyNameFromSet(this) != null
|
||||
|
||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||
if (element !is JKClass) return applyRecursive(element, this::applyToElement)
|
||||
|
||||
@@ -34,48 +120,79 @@ class FieldToPropertyConversion : RecursiveApplicableConversionBase() {
|
||||
}
|
||||
}
|
||||
|
||||
val declarations = element.declarationList.toMutableList()
|
||||
val declarations = element.declarationList
|
||||
declarations.forEach {
|
||||
when (it) {
|
||||
is JKJavaField -> propertyInfoFor(it.name.value).field = it
|
||||
is JKJavaField ->
|
||||
propertyInfoFor(it.name.value).field = it
|
||||
is JKJavaMethod -> {
|
||||
propertyNameFromGet(it)?.let { fieldName -> propertyInfoFor(fieldName).getter = it }
|
||||
?: propertyNameFromSet(it)?.let { fieldName -> propertyInfoFor(fieldName).setter = it }
|
||||
propertyNameFromGet(it)?.let { fieldName ->
|
||||
propertyInfoFor(fieldName).getter = AccessorInfo(it, it.fieldFromGetter())
|
||||
} ?: propertyNameFromSet(it)?.let { fieldName ->
|
||||
propertyInfoFor(fieldName).setter = AccessorInfo(it, it.fieldFromSetter())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for ((_, info) in propertyInfos) {
|
||||
val field = info.field
|
||||
|
||||
if (field != null) {
|
||||
// TODO: proper accessors
|
||||
field.invalidate()
|
||||
val property =
|
||||
JKKtPropertyImpl(field.modifierList, field.type, field.name, field.initializer, JKBlockImpl(), JKBlockImpl())
|
||||
|
||||
declarations.remove(field)
|
||||
property.modifierList.mutability = Mutability.NonMutable
|
||||
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)
|
||||
element.declarationList =
|
||||
declarations.mapNotNull { declaration ->
|
||||
when (declaration) {
|
||||
is JKJavaField -> propertyInfoFor(declaration.name.value).toKtProperty()
|
||||
is JKJavaMethod ->
|
||||
if (declaration.isGetterOrSetter()) {
|
||||
propertyNameFromGet(declaration)?.let { fieldName ->
|
||||
propertyInfoFor(fieldName)
|
||||
}?.takeIf { it.field == null }?.toKtProperty()
|
||||
} else declaration
|
||||
else -> declaration
|
||||
}
|
||||
}
|
||||
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)
|
||||
return recurse(element)
|
||||
}
|
||||
|
||||
|
||||
private enum class RenameType {
|
||||
RENAME_FIELD_ACCESS,
|
||||
RENAME_PARAMETER_ACCESS
|
||||
}
|
||||
|
||||
private inner class Renamer(
|
||||
private val fromName: String,
|
||||
private val toName: String,
|
||||
private val type: JKType,
|
||||
private val renameType: RenameType
|
||||
) : RecursiveApplicableConversionBase() {
|
||||
override fun applyToElement(element: JKTreeElement): JKTreeElement =
|
||||
recurse(
|
||||
when (renameType) {
|
||||
RenameType.RENAME_FIELD_ACCESS -> renameFieldAccessExpression(element)
|
||||
RenameType.RENAME_PARAMETER_ACCESS -> renameParameter(element)
|
||||
} ?: element
|
||||
)
|
||||
|
||||
private fun renameFieldAccessExpression(element: JKTreeElement): JKFieldAccessExpressionImpl? =
|
||||
(element as? JKExpression)?.unboxFieldReference()?.let {
|
||||
if (it.identifier.name == fromName) JKFieldAccessExpressionImpl(createSymbol())
|
||||
else null
|
||||
}
|
||||
|
||||
|
||||
private fun renameParameter(element: JKTreeElement): JKFieldAccessExpressionImpl? {
|
||||
if (element !is JKFieldAccessExpression) return null
|
||||
val target = element.identifier.target as? JKParameter ?: return null
|
||||
return if (target.name.value == fromName) {
|
||||
JKFieldAccessExpressionImpl(createSymbol())
|
||||
} else null
|
||||
}
|
||||
|
||||
element.declarationList = declarations
|
||||
|
||||
return element
|
||||
private fun createSymbol() = object : JKFieldSymbol {
|
||||
override val target: String = toName
|
||||
override val declaredIn: JKSymbol? = null
|
||||
override val name: String = toName
|
||||
override val fqName: String = toName
|
||||
override val fieldType: JKType = type
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,30 +221,19 @@ class FieldToPropertyConversion : RecursiveApplicableConversionBase() {
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun JKMethod.fieldFromGetter(propertyName: String): JKJavaField? {
|
||||
private fun JKMethod.fieldFromGetter(): JKJavaField? {
|
||||
if (this !is JKJavaMethod) return null
|
||||
val returnStatement = block.statements.singleOrNull() as? JKReturnStatement ?: return null
|
||||
val fieldAccess = returnStatement.expression.unboxFieldReference() ?: return null
|
||||
val field = fieldAccess.identifier.target as? JKJavaField ?: return null
|
||||
if (propertyName != field.name.value) return null
|
||||
return field
|
||||
return fieldAccess.identifier.target as? JKJavaField
|
||||
}
|
||||
|
||||
private fun JKMethod.fieldFromSetter(propertyName: String): JKJavaField? {
|
||||
private fun JKMethod.fieldFromSetter(): 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
|
||||
return fieldAccess?.identifier?.target as? JKJavaField
|
||||
}
|
||||
|
||||
|
||||
private data class AccessorInfo(
|
||||
val method: JKMethod,
|
||||
val field: JKField?,
|
||||
val propertyName: String
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ class JKKtPropertyImpl(
|
||||
type: JKTypeElement,
|
||||
name: JKNameIdentifier,
|
||||
initializer: JKExpression,
|
||||
getter: JKBlock,
|
||||
setter: JKBlock
|
||||
getter: JKKtGetterOrSetter,
|
||||
setter: JKKtGetterOrSetter
|
||||
) : JKBranchElementBase(), JKKtProperty {
|
||||
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitKtProperty(this, data)
|
||||
|
||||
@@ -39,8 +39,8 @@ class JKKtPropertyImpl(
|
||||
override var type by child(type)
|
||||
override var name: JKNameIdentifier by child(name)
|
||||
override var initializer: JKExpression by child(initializer)
|
||||
override val getter: JKBlock by child(getter)
|
||||
override val setter: JKBlock by child(setter)
|
||||
override var getter: JKKtGetterOrSetter by child(getter)
|
||||
override var setter: JKKtGetterOrSetter by child(setter)
|
||||
}
|
||||
|
||||
class JKKtFunctionImpl(
|
||||
|
||||
@@ -18,9 +18,20 @@ package org.jetbrains.kotlin.j2k.tree
|
||||
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKMethodSymbol
|
||||
|
||||
interface JKKtGetterOrSetter : JKTreeElement, JKModifierListOwner, JKBranchElement {
|
||||
var body: JKStatement
|
||||
val kind: Kind
|
||||
|
||||
enum class Kind {
|
||||
GETTER, SETTER
|
||||
}
|
||||
}
|
||||
|
||||
interface JKKtEmptyGetterOrSetter : JKKtGetterOrSetter
|
||||
|
||||
interface JKKtProperty : JKField {
|
||||
val getter: JKBlock
|
||||
val setter: JKBlock
|
||||
var getter: JKKtGetterOrSetter
|
||||
var setter: JKKtGetterOrSetter
|
||||
}
|
||||
|
||||
interface JKKtFunction : JKMethod {
|
||||
|
||||
@@ -93,6 +93,8 @@ interface JKVisitor<out R, in D> {
|
||||
fun visitJavaDefaultSwitchCase(javaDefaultSwitchCase: JKJavaDefaultSwitchCase, data: D): R = visitJavaSwitchCase(javaDefaultSwitchCase, data)
|
||||
fun visitJavaLabelSwitchCase(javaLabelSwitchCase: JKJavaLabelSwitchCase, data: D): R = visitJavaSwitchCase(javaLabelSwitchCase, data)
|
||||
fun visitJavaContinueStatement(javaContinueStatement: JKJavaContinueStatement, data: D): R = visitStatement(javaContinueStatement, data)
|
||||
fun visitKtGetterOrSetter(ktGetterOrSetter: JKKtGetterOrSetter, data: D): R = visitTreeElement(ktGetterOrSetter, data)
|
||||
fun visitKtEmptyGetterOrSetter(ktEmptyGetterOrSetter: JKKtEmptyGetterOrSetter, data: D): R = visitKtGetterOrSetter(ktEmptyGetterOrSetter, data)
|
||||
fun visitKtProperty(ktProperty: JKKtProperty, data: D): R = visitField(ktProperty, data)
|
||||
fun visitKtFunction(ktFunction: JKKtFunction, data: D): R = visitMethod(ktFunction, data)
|
||||
fun visitKtConstructor(ktConstructor: JKKtConstructor, data: D): R = visitDeclaration(ktConstructor, data)
|
||||
|
||||
@@ -183,6 +183,10 @@ interface JKVisitorVoid : JKVisitor<Unit, Nothing?> {
|
||||
override fun visitJavaLabelSwitchCase(javaLabelSwitchCase: JKJavaLabelSwitchCase, data: Nothing?) = visitJavaLabelSwitchCase(javaLabelSwitchCase)
|
||||
fun visitJavaContinueStatement(javaContinueStatement: JKJavaContinueStatement) = visitStatement(javaContinueStatement, null)
|
||||
override fun visitJavaContinueStatement(javaContinueStatement: JKJavaContinueStatement, data: Nothing?) = visitJavaContinueStatement(javaContinueStatement)
|
||||
fun visitKtGetterOrSetter(ktGetterOrSetter: JKKtGetterOrSetter) = visitTreeElement(ktGetterOrSetter, null)
|
||||
override fun visitKtGetterOrSetter(ktGetterOrSetter: JKKtGetterOrSetter, data: Nothing?) = visitKtGetterOrSetter(ktGetterOrSetter)
|
||||
fun visitKtEmptyGetterOrSetter(ktEmptyGetterOrSetter: JKKtEmptyGetterOrSetter) = visitKtGetterOrSetter(ktEmptyGetterOrSetter, null)
|
||||
override fun visitKtEmptyGetterOrSetter(ktEmptyGetterOrSetter: JKKtEmptyGetterOrSetter, data: Nothing?) = visitKtEmptyGetterOrSetter(ktEmptyGetterOrSetter)
|
||||
fun visitKtProperty(ktProperty: JKKtProperty) = visitField(ktProperty, null)
|
||||
override fun visitKtProperty(ktProperty: JKKtProperty, data: Nothing?) = visitKtProperty(ktProperty)
|
||||
fun visitKtFunction(ktFunction: JKKtFunction) = visitMethod(ktFunction, null)
|
||||
|
||||
Reference in New Issue
Block a user