Inspection "MoveVariableDeclarationIntoWhen" should inline variable declaration

This commit is contained in:
Dmitry Gridin
2019-03-21 16:29:08 +07:00
parent f9119c001e
commit c84ff1d8b1
3 changed files with 38 additions and 10 deletions
@@ -23,33 +23,61 @@ class MoveVariableDeclarationIntoWhenInspection : AbstractKotlinInspection(), Cl
whenExpressionVisitor(fun(expression: KtWhenExpression) { whenExpressionVisitor(fun(expression: KtWhenExpression) {
val subjectExpression = expression.subjectExpression ?: return val subjectExpression = expression.subjectExpression ?: return
val property = expression.findDeclarationNear() ?: return val property = expression.findDeclarationNear() ?: return
if (!property.isUsedOnlyIn(expression)) return val action = property.action(expression)
if (action == Action.NOTHING) return
val identifier = property.nameIdentifier ?: return val identifier = property.nameIdentifier ?: return
holder.registerProblem( holder.registerProblem(
property, property,
TextRange.from(identifier.startOffsetInParent, identifier.textLength), TextRange.from(identifier.startOffsetInParent, identifier.textLength),
"Variable declaration could be moved inside `when`", action.description, action.createFix(subjectExpression.createSmartPointer())
MoveVariableDeclarationIntoWhenFix(subjectExpression.createSmartPointer())
) )
}) })
} }
private fun KtProperty.isUsedOnlyIn(element: KtElement): Boolean = countUsages() == countUsages(element) private enum class Action {
NOTHING,
MOVE,
INLINE;
val description: String
get() = when (this) {
MOVE -> "Variable declaration could be moved into `when`"
INLINE -> "Variable declaration could be inlined"
NOTHING -> "Nothing to do"
}
fun createFix(subjectExpressionPointer: SmartPsiElementPointer<KtExpression>): VariableDeclarationIntoWhenFix = when (this) {
MOVE -> VariableDeclarationIntoWhenFix("Move variable declaration into `when`", subjectExpressionPointer) { it }
INLINE -> VariableDeclarationIntoWhenFix("Inline variable", subjectExpressionPointer) { it.initializer }
else -> error("Illegal action")
}
}
private fun KtProperty.action(element: KtElement): Action = when (val elementUsages = countUsages(element)) {
countUsages() -> if (elementUsages == 1) Action.INLINE else Action.MOVE
else -> Action.NOTHING
}
private fun KtWhenExpression.findDeclarationNear(): KtProperty? { private fun KtWhenExpression.findDeclarationNear(): KtProperty? {
val previousProperty = previousStatement() as? KtProperty ?: return null val previousProperty = previousStatement() as? KtProperty ?: return null
return previousProperty.takeIf { !it.isVar && it.hasInitializer() && it.nameIdentifier?.text == subjectExpression?.text } return previousProperty.takeIf { !it.isVar && it.hasInitializer() && it.nameIdentifier?.text == subjectExpression?.text }
} }
private class MoveVariableDeclarationIntoWhenFix(val subjectExpressionPointer: SmartPsiElementPointer<KtExpression>) : LocalQuickFix { private class VariableDeclarationIntoWhenFix(
override fun getName() = "Move the variable into `when`" private val actionName: String,
private val subjectExpressionPointer: SmartPsiElementPointer<KtExpression>,
private val transform: (KtProperty) -> KtExpression?
) : LocalQuickFix {
override fun getName() = actionName
override fun getFamilyName() = name override fun getFamilyName() = name
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val property = descriptor.psiElement as? KtProperty ?: return val property = descriptor.psiElement as? KtProperty ?: return
val subjectExpression = subjectExpressionPointer.element ?: return val subjectExpression = subjectExpressionPointer.element ?: return
subjectExpression.replace(property.copy()) val newElement = transform(property)?.copy() ?: return
subjectExpression.replace(newElement)
property.delete() property.delete()
} }
} }
@@ -1,7 +1,7 @@
fun foo() { fun foo() {
// comment // comment
when (val a = 1) { when (1) {
1 -> { 1 -> {
} }
else -> { else -> {
@@ -1,7 +1,7 @@
fun foo() { fun foo() {
when (val a = 1) { when (1) {
1 -> { 1 -> {
} }
else -> { else -> {