KT-7702 Split into 2 if's intention: produce better result for return

#KT-7702 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-05-14 14:32:47 +03:00
parent 8f797e8e69
commit 0fe334fd55
7 changed files with 45 additions and 16 deletions
@@ -360,7 +360,7 @@ public class JetPsiFactory(private val project: Project) {
return JetBlockCodeFragment(project, "fragment.kt", text, null, context)
}
public fun createIf(condition: JetExpression, thenExpr: JetExpression, elseExpr: JetExpression?): JetIfExpression {
public fun createIf(condition: JetExpression, thenExpr: JetExpression, elseExpr: JetExpression? = null): JetIfExpression {
return (if (elseExpr != null)
createExpressionByPattern("if ($0) $1 else $2", condition, thenExpr, elseExpr) as JetIfExpression
else
@@ -208,13 +208,6 @@ public class InvertIfConditionIntention : JetSelfTargetingIntention<JetIfExpress
return null
}
private fun JetExpression.isExitStatement(): Boolean {
when (this) {
is JetContinueExpression, is JetBreakExpression, is JetThrowExpression, is JetReturnExpression -> return true
else -> return false
}
}
companion object {
private val NEGATABLE_OPERATORS = setOf(JetTokens.EQEQ, JetTokens.EXCLEQ, JetTokens.EQEQEQ,
JetTokens.EXCLEQEQEQ, JetTokens.IS_KEYWORD, JetTokens.NOT_IS, JetTokens.IN_KEYWORD,
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class SplitIfIntention : JetSelfTargetingIntention<JetExpression>(javaClass(), "Split if into 2 if's") {
override fun isApplicableTo(element: JetExpression, caretOffset: Int): Boolean {
@@ -41,24 +43,36 @@ public class SplitIfIntention : JetSelfTargetingIntention<JetExpression>(javaCla
val expression = operator.getParent() as JetBinaryExpression
val rightExpression = JetPsiUtil.safeDeparenthesize(getRight(expression, ifExpression!!.getCondition()!!))
val leftExpression = JetPsiUtil.safeDeparenthesize(expression.getLeft()!!)
val thenExpression = ifExpression.getThen()!!
val elseExpression = ifExpression.getElse()
val thenBranch = ifExpression.getThen()!!
val elseBranch = ifExpression.getElse()
val psiFactory = JetPsiFactory(element)
val innerIf = psiFactory.createIf(rightExpression, thenExpression, elseExpression)
val newIf = when (operator.getReferencedNameElementType()) {
JetTokens.ANDAND -> psiFactory.createIf(leftExpression, psiFactory.wrapInABlock(innerIf), elseExpression)
JetTokens.OROR -> psiFactory.createIf(leftExpression, thenExpression, innerIf)
val innerIf = psiFactory.createIf(rightExpression, thenBranch, elseBranch)
when (operator.getReferencedNameElementType()) {
JetTokens.ANDAND -> ifExpression.replace(psiFactory.createIf(leftExpression, psiFactory.wrapInABlock(innerIf), elseBranch))
JetTokens.OROR -> {
val container = ifExpression.getParent()
if (container is JetBlockExpression && elseBranch == null && thenBranch.lastBlockStatementOrThis().isExitStatement()) { // special case
container.addAfter(innerIf, ifExpression)
container.addAfter(psiFactory.createNewLine(), ifExpression)
ifExpression.replace(psiFactory.createIf(leftExpression, thenBranch))
return
}
ifExpression.replace(psiFactory.createIf(leftExpression, thenBranch, innerIf))
}
else -> throw IllegalArgumentException()
}
ifExpression.replace(newIf)
}
private fun getRight(element: JetBinaryExpression, condition: JetExpression): JetExpression {
//gets the textOffset of the right side of the JetBinaryExpression in context to condition
val startOffset = element.getRight()!!.getTextOffset() - condition.getTextOffset()
val startOffset = element.getRight()!!.startOffset - condition.startOffset
val rightString = condition.getText()!!.substring(startOffset, condition.getTextLength())
return JetPsiFactory(element).createExpression(rightString)
@@ -114,3 +114,10 @@ fun JetQualifiedExpression.toResolvedCall(): ResolvedCall<out CallableDescriptor
return callExpression.getResolvedCall(callExpression.analyze()) ?: return null
}
fun JetExpression.isExitStatement(): Boolean {
when (this) {
is JetContinueExpression, is JetBreakExpression, is JetThrowExpression, is JetReturnExpression -> return true
else -> return false
}
}
@@ -0,0 +1,4 @@
fun foo(p: Int): Boolean {
if (p < 0 <caret>|| p == 5) return false
return true
}
@@ -0,0 +1,5 @@
fun foo(p: Int): Boolean {
if (p < 0) return false
if (p == 5) return false
return true
}
@@ -6405,6 +6405,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("ifOrReturn.kt")
public void testIfOrReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/splitIf/ifOrReturn.kt");
doTest(fileName);
}
@TestMetadata("ifWithElse.kt")
public void testIfWithElse() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/splitIf/ifWithElse.kt");