From a30311da4523d107dac56f417323827d5167802c Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 21 Nov 2018 12:52:35 +0300 Subject: [PATCH] New J2K: Add dummy field to property conversion --- .../kotlin/idea/j2k/J2kPostProcessings.kt | 3 + .../jetbrains/kotlin/j2k/NewCodeBuilder.kt | 31 +++ .../conversions/FieldToPropertyConversion.kt | 218 +++++++++++++----- .../org/jetbrains/kotlin/j2k/tree/impl/k.kt | 8 +- j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt | 15 +- .../kotlin/j2k/tree/visitors/JKVisitor.kt | 2 + .../kotlin/j2k/tree/visitors/JKVisitorVoid.kt | 4 + 7 files changed, 219 insertions(+), 62 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt index 10a7641c97a..b0b736d22c1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt +++ b/idea/src/org/jetbrains/kotlin/idea/j2k/J2kPostProcessings.kt @@ -94,6 +94,9 @@ object J2KPostProcessingRegistrar { registerGeneralInspectionBasedProcessing(RedundantVisibilityModifierInspection()) registerGeneralInspectionBasedProcessing(RedundantExplicitTypeInspection()) registerGeneralInspectionBasedProcessing(RedundantUnitReturnTypeInspection()) + registerGeneralInspectionBasedProcessing(RedundantGetterInspection()) + registerGeneralInspectionBasedProcessing(RedundantSetterInspection()) + _processings.add(RemoveExplicitPropertyType()) registerGeneralInspectionBasedProcessing(CanBeValInspection(ignoreNotUsedVals = false)) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt index 2ff7938bcd3..c5cb71aaee3 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewCodeBuilder.kt @@ -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(" ") diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt index 4404756ab92..e1466f488f7 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/FieldToPropertyConversion.kt @@ -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.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 - ) } diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt index e2ff24c8d48..3f98ffd396e 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/impl/k.kt @@ -30,8 +30,8 @@ class JKKtPropertyImpl( type: JKTypeElement, name: JKNameIdentifier, initializer: JKExpression, - getter: JKBlock, - setter: JKBlock + getter: JKKtGetterOrSetter, + setter: JKKtGetterOrSetter ) : JKBranchElementBase(), JKKtProperty { override fun accept(visitor: JKVisitor, 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( diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt index 4b60bf4545d..0cd8d5a9101 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/k.kt @@ -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 { diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt index bc11ae891c3..9ae59fcbb14 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitor.kt @@ -93,6 +93,8 @@ interface JKVisitor { 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) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt index 8d511f45add..dd238374d4c 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/tree/visitors/JKVisitorVoid.kt @@ -183,6 +183,10 @@ interface JKVisitorVoid : JKVisitor { 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)