Merge pull request #431 from gavinkeusch/split_if_new

KT-4794: Added functionality to KT-4574: Split If. Intention is now offered inside IF keyword
This commit is contained in:
Pavel Talanov
2014-04-09 09:10:50 -07:00
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.lexer.JetTokens
import org.jetbrains.jet.lang.psi.psiUtil.getParentByType
import org.jetbrains.jet.lang.psi.JetExpression
import com.intellij.psi.util.PsiTreeUtil
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()
if (operator != JetTokens.ANDAND && operator != JetTokens.OROR) return false
@@ -53,32 +116,5 @@ public class SplitIfIntention : JetSelfTargetingIntention<JetSimpleNameExpressio
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");
}
@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")
public void testSplitIfNotIf() throws Exception {
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")
public void testSplitIfOneAND() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfOneAND.kt");
@@ -3051,6 +3091,11 @@ public class CodeTransformationTestGenerated extends AbstractCodeTransformationT
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")
public void testSplitIfTwoOperatorsFirst() throws Exception {
doTestSplitIf("idea/testData/intentions/splitIf/splitIfTwoOperatorsFirst.kt");