KT-4794: Added functionality to KT-4574: Split If. Intention is now offered inside IF keyword

This commit is contained in:
gavinkeusch
2014-04-08 11:29:30 -07:00
parent f5fb2ea0ab
commit 216ea4940d
19 changed files with 320 additions and 30 deletions
@@ -22,13 +22,76 @@ import org.jetbrains.jet.lang.psi.JetBinaryExpression
import org.jetbrains.jet.lang.psi.JetPsiFactory import org.jetbrains.jet.lang.psi.JetPsiFactory
import org.jetbrains.jet.lexer.JetTokens import org.jetbrains.jet.lexer.JetTokens
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
import org.jetbrains.jet.lang.psi.JetExpression
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
import org.jetbrains.jet.lang.psi.JetExpression
import org.jetbrains.jet.lang.psi.JetPsiUtil
public class SplitIfIntention : JetSelfTargetingIntention<JetSimpleNameExpression>("split.if", javaClass()) { public class SplitIfIntention : JetSelfTargetingIntention<JetExpression>("split.if", javaClass()) {
override fun isApplicableTo(element: JetExpression): Boolean {
throw IllegalStateException("isApplicableTo(JetExpression, Editor) should be called instead")
}
override fun isApplicableTo(element: JetSimpleNameExpression): Boolean { override fun isApplicableTo(element: JetExpression, editor: Editor): Boolean {
if (element !is JetSimpleNameExpression && element !is JetIfExpression) return false
if (element is JetSimpleNameExpression) {
return isOperatorValid(element)
}
if (element is JetIfExpression) {
if (!isCursorOnIfKeyword(element, editor)) return false
if (getFirstValidOperator(element) == null) return false
}
return true
}
override fun applyTo(element: JetExpression, editor: Editor) {
val currentElement = when (element) {
is JetIfExpression -> getFirstValidOperator(element)
else -> element as JetSimpleNameExpression
}
val ifExpression = currentElement!!.getParentByType(javaClass<JetIfExpression>())
val expression = currentElement.getParent() as JetBinaryExpression
val rightExpression = getRight(expression, ifExpression!!.getCondition() as JetExpression)
val leftExpression = expression.getLeft()
val elseExpression = ifExpression.getElse()
val thenExpression = ifExpression.getThen()
if (currentElement.getReferencedNameElementType() == JetTokens.ANDAND) {
ifExpression.replace(JetPsiFactory.createIf(element.getProject(), leftExpression,
JetPsiFactory.wrapInABlock(JetPsiFactory.createIf(element.getProject(), rightExpression, thenExpression,
elseExpression)), elseExpression))
}
else {
ifExpression.replace(JetPsiFactory.createIf(element.getProject(), leftExpression, thenExpression,
JetPsiFactory.createIf(element.getProject(), rightExpression, thenExpression, elseExpression)))
}
}
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 rightString = condition.getText()!![startOffset, condition.getTextLength()].toString()
return JetPsiFactory.createExpression(element.getProject(), rightString)
}
fun isCursorOnIfKeyword(element: JetIfExpression, editor: Editor): Boolean {
val ifKeyword = JetPsiUtil.findChildByType(element, JetTokens.IF_KEYWORD) ?: return false
val cursor = editor.getCaretModel().getOffset()
return (cursor >= ifKeyword.getTextOffset() && cursor <= ifKeyword.getTextOffset() + ifKeyword.getTextLength())
}
fun getFirstValidOperator(element: JetIfExpression): JetSimpleNameExpression? {
if (element.getCondition() == null) return null
val condition = element.getCondition()
val childElements = PsiTreeUtil.findChildrenOfType(condition, javaClass<JetSimpleNameExpression>())
return childElements.firstOrNull { isOperatorValid(it) }
}
fun isOperatorValid(element: JetSimpleNameExpression): Boolean {
val operator = element.getReferencedNameElementType() val operator = element.getReferencedNameElementType()
if (operator != JetTokens.ANDAND && operator != JetTokens.OROR) return false if (operator != JetTokens.ANDAND && operator != JetTokens.OROR) return false
@@ -53,32 +116,5 @@ public class SplitIfIntention : JetSelfTargetingIntention<JetSimpleNameExpressio
return true return true
} }
override fun applyTo(element: JetSimpleNameExpression, editor: Editor) {
val ifExpression = element.getParentByType(javaClass<JetIfExpression>())
val expression = element.getParent() as JetBinaryExpression
val rightExpression = getRight(expression, ifExpression!!.getCondition() as JetExpression)
val leftExpression = expression.getLeft()
val elseExpression = ifExpression.getElse()
val thenExpression = ifExpression.getThen()
if (element.getReferencedNameElementType() == JetTokens.ANDAND) {
ifExpression.replace(JetPsiFactory.createIf(element.getProject(), leftExpression,
JetPsiFactory.wrapInABlock(JetPsiFactory.createIf(element.getProject(), rightExpression, thenExpression,
elseExpression)), elseExpression))
}
else {
ifExpression.replace(JetPsiFactory.createIf(element.getProject(), leftExpression, thenExpression,
JetPsiFactory.createIf(element.getProject(), rightExpression, thenExpression, elseExpression)))
}
}
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 rightString = condition.getText()!![startOffset, condition.getTextLength()].toString()
return JetPsiFactory.createExpression(element.getProject(), rightString)
}
} }
@@ -0,0 +1,11 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
<caret>if ((a && b) && c || d) {
doSomething("test")
}
}
@@ -0,0 +1,13 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
if ((a && b) && c) {
doSomething("test")
} else if (d) {
doSomething("test")
}
}
@@ -0,0 +1,11 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
<caret>if ((a || b) && (c || d)) {
doSomething("test")
}
}
@@ -0,0 +1,13 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
if (a || b) {
if (c || d) {
doSomething("test")
}
}
}
@@ -0,0 +1,9 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
<caret>if (a && b) {
doSomething("test")
}
}
@@ -0,0 +1,11 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
if (a) {
if (b) {
doSomething("test")
}
}
}
@@ -0,0 +1,12 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
if (a) {
<caret>if (b && c) {
doSomething("test")
}
}
}
@@ -0,0 +1,14 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
if (a) {
if (b) {
if (c) {
doSomething("test")
}
}
}
}
@@ -0,0 +1,13 @@
// IS_APPLICABLE: false
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
<caret>if (a) {
if (b && c) {
doSomething("test")
}
}
}
@@ -0,0 +1,13 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
if (a || b) {
<caret>if (c || d) {
doSomething("test")
}
}
}
@@ -0,0 +1,15 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
if (a || b) {
if (c) {
doSomething("test")
} else if (d) {
doSomething("test")
}
}
}
@@ -0,0 +1,13 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
<caret>if (a && b) {
if (c && d) {
doSomething("test")
}
}
}
@@ -0,0 +1,15 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
if (a) {
if (b) {
if (c && d) {
doSomething("test")
}
}
}
}
@@ -0,0 +1,10 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
<caret>if (a && b || c) {
doSomething("test")
}
}
@@ -0,0 +1,12 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
if (a && b) {
doSomething("test")
} else if (c) {
doSomething("test")
}
}
@@ -0,0 +1,11 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
<caret>if ((a && b || c) || d) {
doSomething("test")
}
}
@@ -0,0 +1,13 @@
fun doSomething<T>(a: T) {}
fun foo() {
val a = true
val b = false
val c = true
val d = false
if (a && b || c) {
doSomething("test")
} else if (d) {
doSomething("test")
}
}
@@ -3026,11 +3026,51 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
doTestSplitIf("idea/testData/intentions/splitIf/splitIfAndOr.kt"); doTestSplitIf("idea/testData/intentions/splitIf/splitIfAndOr.kt");
} }
@TestMetadata("splitIfAndOrWithBraces.kt")
public void testSplitIfAndOrWithBraces() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfAndOrWithBraces.kt");
}
@TestMetadata("splitIfAndWithBraces.kt")
public void testSplitIfAndWithBraces() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfAndWithBraces.kt");
}
@TestMetadata("splitIfCaretOnIf.kt")
public void testSplitIfCaretOnIf() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfCaretOnIf.kt");
}
@TestMetadata("splitIfNestedIf.kt")
public void testSplitIfNestedIf() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfNestedIf.kt");
}
@TestMetadata("splitIfNestedIfNotApplicable.kt")
public void testSplitIfNestedIfNotApplicable() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfNestedIfNotApplicable.kt");
}
@TestMetadata("splitIfNestedInside.kt")
public void testSplitIfNestedInside() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfNestedInside.kt");
}
@TestMetadata("splitIfNestedOutside.kt")
public void testSplitIfNestedOutside() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfNestedOutside.kt");
}
@TestMetadata("splitIfNotIf.kt") @TestMetadata("splitIfNotIf.kt")
public void testSplitIfNotIf() throws Exception { public void testSplitIfNotIf() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfNotIf.kt"); doTestSplitIf("idea/testData/intentions/splitIf/splitIfNotIf.kt");
} }
@TestMetadata("splitIfOnIfWithOr.kt")
public void testSplitIfOnIfWithOr() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfOnIfWithOr.kt");
}
@TestMetadata("splitIfOneAND.kt") @TestMetadata("splitIfOneAND.kt")
public void testSplitIfOneAND() throws Exception { public void testSplitIfOneAND() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfOneAND.kt"); doTestSplitIf("idea/testData/intentions/splitIf/splitIfOneAND.kt");
@@ -3051,6 +3091,11 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
doTestSplitIf("idea/testData/intentions/splitIf/splitIfOrAnd.kt"); doTestSplitIf("idea/testData/intentions/splitIf/splitIfOrAnd.kt");
} }
@TestMetadata("splitIfOrWithBraces.kt")
public void testSplitIfOrWithBraces() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfOrWithBraces.kt");
}
@TestMetadata("splitIfTwoOperatorsFirst.kt") @TestMetadata("splitIfTwoOperatorsFirst.kt")
public void testSplitIfTwoOperatorsFirst() throws Exception { public void testSplitIfTwoOperatorsFirst() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfTwoOperatorsFirst.kt"); doTestSplitIf("idea/testData/intentions/splitIf/splitIfTwoOperatorsFirst.kt");