KT-4794: Added functionality to KT-4574: Split If. Intention is now offered inside IF keyword
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user