New J2K: Add ConvertDataClass PostProcessing
This commit is contained in:
committed by
Ilya Kirillov
parent
5c8035b339
commit
c7df104b36
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.idea.j2k.postProcessing
|
||||||
|
|
||||||
|
import com.intellij.psi.impl.source.tree.PsiWhiteSpaceImpl
|
||||||
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.idea.core.setDefaultValue
|
||||||
|
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessing
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.addRemoveModifier.setModifierList
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.asAssignment
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.containingClass
|
||||||
|
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||||
|
|
||||||
|
class ConvertDataClass : J2kPostProcessing {
|
||||||
|
override val writeActionNeeded: Boolean = true
|
||||||
|
|
||||||
|
fun KtCallableDeclaration.rename(newName: String) {
|
||||||
|
val factory = KtPsiFactory(this)
|
||||||
|
ReferencesSearch.search(this, LocalSearchScope(containingKtFile)).forEach {
|
||||||
|
it.element.replace(factory.createExpression(newName))
|
||||||
|
}
|
||||||
|
setName(newName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class DataClassInfo(
|
||||||
|
val constructorParameter: KtParameter,
|
||||||
|
val property: KtProperty,
|
||||||
|
val initBlockStatement: KtBinaryExpression
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun collectPropertiesData(klass: KtClass): List<DataClassInfo> =
|
||||||
|
klass.getAnonymousInitializers()
|
||||||
|
.flatMap { (it.body as KtBlockExpression).statements }
|
||||||
|
.asSequence()
|
||||||
|
.mapNotNull { it.asAssignment() }
|
||||||
|
.mapNotNull { statement ->
|
||||||
|
val property =
|
||||||
|
statement.left
|
||||||
|
?.unpackedReferenceToProperty()
|
||||||
|
?.takeIf { it.containingClass() == klass } ?: return@mapNotNull null
|
||||||
|
if (property.getter != null || property.setter != null) return@mapNotNull null
|
||||||
|
val constructorParameter =
|
||||||
|
((statement.right as? KtReferenceExpression)
|
||||||
|
?.references
|
||||||
|
?.firstOrNull { it is KtSimpleNameReference }
|
||||||
|
?.resolve() as? KtParameter)
|
||||||
|
?.takeIf {
|
||||||
|
it.containingClass() == klass && !it.hasValOrVar()
|
||||||
|
} ?: return@mapNotNull null
|
||||||
|
|
||||||
|
if (constructorParameter.type() != property.type()) return@mapNotNull null
|
||||||
|
|
||||||
|
DataClassInfo(constructorParameter, property, statement)
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
|
||||||
|
if (element !is KtClass) return null
|
||||||
|
return {
|
||||||
|
val factory = KtPsiFactory(element)
|
||||||
|
for ((constructorParameter, property, statement) in collectPropertiesData(element)) {
|
||||||
|
constructorParameter.addBefore(property.valOrVarKeyword, constructorParameter.nameIdentifier!!)
|
||||||
|
constructorParameter.addAfter(factory.createWhiteSpace(), constructorParameter.valOrVarKeyword!!)
|
||||||
|
constructorParameter.rename(property.name!!)
|
||||||
|
if (property.modifierList != null) {
|
||||||
|
constructorParameter.setModifierList(property.modifierList!!)
|
||||||
|
}
|
||||||
|
property.delete()
|
||||||
|
statement.delete()
|
||||||
|
}
|
||||||
|
for (initBlock in element.getAnonymousInitializers()) {
|
||||||
|
if ((initBlock.body as KtBlockExpression).statements.isEmpty()) {
|
||||||
|
initBlock.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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.idea.j2k.postProcessing
|
||||||
|
|
||||||
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
|
||||||
|
|
||||||
|
fun KtExpression.asProperty(): KtProperty? =
|
||||||
|
(this as? KtNameReferenceExpression)
|
||||||
|
?.references
|
||||||
|
?.firstOrNull { it is KtSimpleNameReference }
|
||||||
|
?.resolve() as? KtProperty
|
||||||
|
|
||||||
|
fun KtExpression.unpackedReferenceToProperty(): KtProperty? =
|
||||||
|
when (this) {
|
||||||
|
is KtDotQualifiedExpression ->
|
||||||
|
if (receiverExpression is KtThisExpression) selectorExpression as? KtNameReferenceExpression
|
||||||
|
else null
|
||||||
|
is KtNameReferenceExpression -> this
|
||||||
|
else -> null
|
||||||
|
}?.references
|
||||||
|
?.firstOrNull { it is KtSimpleNameReference }
|
||||||
|
?.resolve() as? KtProperty
|
||||||
|
|
||||||
|
|
||||||
|
fun KtDeclaration.type() =
|
||||||
|
(resolveToDescriptorIfAny() as? CallableDescriptor)?.returnType
|
||||||
Reference in New Issue
Block a user