"Simplify comparison": remove if when possible after applying quickfix

#KT-25995 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-08-28 05:39:04 +03:00
committed by Mikhail Glukhikh
parent 688fc386b6
commit 5c83c247d7
6 changed files with 58 additions and 33 deletions
@@ -26,13 +26,17 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class ConstantConditionIfInspection : AbstractKotlinInspection() { class ConstantConditionIfInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return ifExpressionVisitor(fun(expression) { return ifExpressionVisitor { expression -> collectFixesAndRegisterProblem(expression, holder) }
val condition = expression.condition ?: return }
companion object {
private fun collectFixesAndRegisterProblem(expression: KtIfExpression, holder: ProblemsHolder?): List<ConstantConditionIfFix> {
val condition = expression.condition ?: return emptyList()
val context = condition.analyze(BodyResolveMode.PARTIAL_WITH_CFA) val context = condition.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
val constantValue = condition.constantBooleanValue(context) ?: return val constantValue = condition.constantBooleanValue(context) ?: return emptyList()
val fixes = mutableListOf<LocalQuickFix>() val fixes = mutableListOf<ConstantConditionIfFix>()
if (expression.branch(constantValue) != null) { if (expression.branch(constantValue) != null) {
val keepBraces = expression.isElseIf() && expression.branch(constantValue) is KtBlockExpression val keepBraces = expression.isElseIf() && expression.branch(constantValue) is KtBlockExpression
@@ -43,39 +47,57 @@ class ConstantConditionIfInspection : AbstractKotlinInspection() {
fixes += RemoveFix() fixes += RemoveFix()
} }
holder.registerProblem(condition, holder?.registerProblem(
"Condition is always '$constantValue'", condition,
*fixes.toTypedArray()) "Condition is always '$constantValue'",
}) *fixes.toTypedArray()
)
return fixes
}
fun applyFixIfSingle(ifExpression: KtIfExpression) {
collectFixesAndRegisterProblem(ifExpression, null).singleOrNull()?.applyFix(ifExpression)
}
}
private interface ConstantConditionIfFix : LocalQuickFix {
fun applyFix(ifExpression: KtIfExpression)
} }
private class SimplifyFix( private class SimplifyFix(
private val conditionValue: Boolean, private val conditionValue: Boolean,
private val isUsedAsExpression: Boolean, private val isUsedAsExpression: Boolean,
private val keepBraces: Boolean private val keepBraces: Boolean
) : LocalQuickFix { ) : ConstantConditionIfFix {
override fun getFamilyName() = name override fun getFamilyName() = name
override fun getName() = "Simplify expression" override fun getName() = "Simplify expression"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val ifExpression = descriptor.psiElement.getParentOfType<KtIfExpression>(strict = true) ?: return val ifExpression = descriptor.psiElement.getParentOfType<KtIfExpression>(strict = true) ?: return
applyFix(ifExpression)
}
override fun applyFix(ifExpression: KtIfExpression) {
val branch = ifExpression.branch(conditionValue)?.let { val branch = ifExpression.branch(conditionValue)?.let {
if (keepBraces) it else it.unwrapBlockOrParenthesis() if (keepBraces) it else it.unwrapBlockOrParenthesis()
} ?: return } ?: return
ifExpression.replaceWithBranch(branch, isUsedAsExpression, keepBraces) ifExpression.replaceWithBranch(branch, isUsedAsExpression, keepBraces)
} }
} }
private class RemoveFix : LocalQuickFix { private class RemoveFix : ConstantConditionIfFix {
override fun getFamilyName() = name override fun getFamilyName() = name
override fun getName() = "Delete expression" override fun getName() = "Delete expression"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) { override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
val ifExpression = descriptor.psiElement.getParentOfType<KtIfExpression>(strict = true) ?: return val ifExpression = descriptor.psiElement.getParentOfType<KtIfExpression>(strict = true) ?: return
applyFix(ifExpression)
}
override fun applyFix(ifExpression: KtIfExpression) {
ifExpression.delete() ifExpression.delete()
} }
} }
@@ -103,8 +125,7 @@ fun KtExpression.replaceWithBranch(branch: KtExpression, isUsedAsExpression: Boo
if (firstChildSibling != lastChild) { if (firstChildSibling != lastChild) {
if (keepBraces) { if (keepBraces) {
parent.addAfter(branch, this) parent.addAfter(branch, this)
} } else {
else {
parent.addRangeAfter(firstChildSibling, lastChild.prevSibling, this) parent.addRangeAfter(firstChildSibling, lastChild.prevSibling, this)
} }
} }
@@ -22,12 +22,11 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2 import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2
import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.inspections.ConstantConditionIfInspection
import org.jetbrains.kotlin.idea.intentions.SimplifyBooleanWithConstantsIntention import org.jetbrains.kotlin.idea.intentions.SimplifyBooleanWithConstantsIntention
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class SimplifyComparisonFix(element: KtExpression, val value: Boolean) : KotlinQuickFixAction<KtExpression>(element) { class SimplifyComparisonFix(element: KtExpression, val value: Boolean) : KotlinQuickFixAction<KtExpression>(element) {
override fun getFamilyName() = "Simplify $element to '$value'" override fun getFamilyName() = "Simplify $element to '$value'"
@@ -43,10 +42,12 @@ class SimplifyComparisonFix(element: KtExpression, val value: Boolean) : KotlinQ
val simplifyIntention = SimplifyBooleanWithConstantsIntention() val simplifyIntention = SimplifyBooleanWithConstantsIntention()
if (booleanExpression != null && simplifyIntention.isApplicableTo(booleanExpression)) { if (booleanExpression != null && simplifyIntention.isApplicableTo(booleanExpression)) {
simplifyIntention.applyTo(booleanExpression, editor) simplifyIntention.applyTo(booleanExpression, editor)
} } else {
else {
simplifyIntention.removeRedundantAssertion(result) simplifyIntention.removeRedundantAssertion(result)
} }
val ifExpression = result.getStrictParentOfType<KtIfExpression>()?.takeIf { it.condition == result }
if (ifExpression != null) ConstantConditionIfInspection.applyFixIfSingle(ifExpression)
} }
companion object : KotlinSingleIntentionActionFactory() { companion object : KotlinSingleIntentionActionFactory() {
+4 -2
View File
@@ -5,7 +5,9 @@ fun foo(x: String?) {
} }
else { else {
if (<caret>x == null) { if (<caret>x == null) {
bar()
} }
} }
} }
fun bar() {}
@@ -4,8 +4,7 @@ fun foo(x: String?) {
} }
else { else {
if (false) {
}
} }
} }
fun bar() {}
+4 -2
View File
@@ -1,6 +1,8 @@
// "Simplify comparison" "true" // "Simplify comparison" "true"
fun foo(x: Int) { fun foo(x: Int) {
if (<caret>x != null) { if (<caret>x != null) {
bar()
} }
} }
fun bar() {}
+3 -3
View File
@@ -1,6 +1,6 @@
// "Simplify comparison" "true" // "Simplify comparison" "true"
fun foo(x: Int) { fun foo(x: Int) {
if (true) { bar()
}
} fun bar() {}
}