Refactored SplitIfIntention + JetPsiFactory.createIf uses createExpressionByPattern and does not reformat its arguments

This commit is contained in:
Valentin Kipyatkov
2015-05-05 14:06:19 +03:00
parent de8601bb5d
commit 7499c4bc19
14 changed files with 49 additions and 78 deletions
@@ -349,8 +349,11 @@ public class JetPsiFactory(private val project: Project) {
return createReturn(JetPsiUtil.getText(expression))
}
public fun createIf(condition: JetExpression?, thenExpr: JetExpression?, elseExpr: JetExpression?): JetIfExpression {
return createExpression(JetPsiUnparsingUtils.toIf(condition, thenExpr, elseExpr)) as JetIfExpression
public fun createIf(condition: JetExpression, thenExpr: JetExpression, elseExpr: JetExpression?): JetIfExpression {
return (if (elseExpr != null)
createExpressionByPattern("if ($0) $1 else $2", condition, thenExpr, elseExpr) as JetIfExpression
else
createExpressionByPattern("if ($0) $1", condition, thenExpr)) as JetIfExpression
}
public fun createArgumentWithName(name: String?, argumentExpression: JetExpression): JetValueArgument {
@@ -23,20 +23,6 @@ public class JetPsiUnparsingUtils {
private JetPsiUnparsingUtils() {
}
@NotNull
public static String toIf(@Nullable JetExpression condition, @Nullable JetExpression thenExpression, @Nullable JetExpression elseExpression) {
return toIf(
JetPsiUtil.getText(condition),
JetPsiUtil.getText(thenExpression),
elseExpression != null ? elseExpression.getText() : null
);
}
@NotNull
public static String toIf(@NotNull String condition, @NotNull String thenExpression, @Nullable String elseExpression) {
return "if " + parenthesizeTextIfNeeded(condition) + " " + thenExpression + (elseExpression != null ? " else " + elseExpression : "");
}
@NotNull
public static String toBinaryExpression(@Nullable JetExpression left, @NotNull String op, @Nullable JetElement right) {
return toBinaryExpression(JetPsiUtil.getText(left), op, JetPsiUtil.getText(right));
@@ -80,9 +80,6 @@ public fun JetPsiFactory.createExpressionByPattern(pattern: String, vararg args:
bound = range.getStartOffset() + start
}
expression = codeStyleManager.reformatRange(expression, start, bound + 1, true) as JetExpression
// we need to adjust indent of all lines within expression
codeStyleManager.adjustLineIndent(expression.getContainingFile(), expression.getTextRange())
}
// do not reformat the whole expression in PostprocessReformattingAspect
@@ -97,6 +94,8 @@ public fun JetPsiFactory.createExpressionByPattern(pattern: String, vararg args:
element.replace(arg)
}
codeStyleManager.adjustLineIndent(expression.getContainingFile(), expression.getTextRange())
return expression
}
@@ -46,8 +46,7 @@ import org.jetbrains.kotlin.JetNodeTypes
import org.jetbrains.kotlin.name.FqName
public fun JetCallElement.getCallNameExpression(): JetSimpleNameExpression? {
val calleeExpression = getCalleeExpression()
if (calleeExpression == null) return null
val calleeExpression = getCalleeExpression() ?: return null
return when (calleeExpression) {
is JetSimpleNameExpression -> calleeExpression
@@ -288,8 +288,6 @@ add.name.to.argument.single=Add name to argument\: ''{0}''
add.name.to.argument.multiple=Add name to argument...
add.name.to.argument.action=Add name to argument...
add.name.to.parameter.name.chooser.title=Choose parameter name
split.if=Split into 2 if's
split.if.family=Split If
simplify.boolean.with.constants=Simplify boolean expression
simplify.boolean.with.constants.family=Simplify Boolean Expression
remove.explicit.type.arguments=Remove explicit type arguments
@@ -68,7 +68,10 @@ public class KotlinUnwrappers {
@Override
public boolean isApplicableTo(PsiElement e) {
return e instanceof JetIfExpression && ((JetIfExpression) e).getElse() != null;
return e instanceof JetIfExpression
&& ((JetIfExpression) e).getCondition() != null
&& ((JetIfExpression) e).getThen() != null
&& ((JetIfExpression) e).getElse() != null;
}
@Override
@@ -16,98 +16,74 @@
package org.jetbrains.kotlin.idea.intentions
import org.jetbrains.kotlin.psi.JetIfExpression
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.psi.JetBinaryExpression
import org.jetbrains.kotlin.psi.JetPsiFactory
import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.psi.JetExpression
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.psi.*
public class SplitIfIntention : JetSelfTargetingIntention<JetExpression>("split.if", javaClass()) {
public class SplitIfIntention : JetSelfTargetingIntention<JetExpression>(javaClass(), "Split if into 2 if's") {
override fun isApplicableTo(element: JetExpression, caretOffset: Int): Boolean {
if (element !is JetSimpleNameExpression && element !is JetIfExpression) return false
if (element is JetSimpleNameExpression) {
return isOperatorValid(element)
return when (element) {
is JetSimpleNameExpression -> isOperatorValid(element)
is JetIfExpression -> getFirstValidOperator(element) != null && element.getIfKeyword().getTextRange().containsOffset(caretOffset)
else -> false
}
if (element is JetIfExpression) {
if (!isCursorOnIfKeyword(element, caretOffset)) 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)
val operator = when (element) {
is JetIfExpression -> getFirstValidOperator(element)!!
else -> element as JetSimpleNameExpression
}
val ifExpression = currentElement!!.getNonStrictParentOfType<JetIfExpression>()
val expression = currentElement.getParent() as JetBinaryExpression
val rightExpression = getRight(expression, ifExpression!!.getCondition())
val leftExpression = expression.getLeft()
val ifExpression = operator.getNonStrictParentOfType<JetIfExpression>()
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 thenExpression = ifExpression.getThen()
val psiFactory = JetPsiFactory(element)
if (currentElement.getReferencedNameElementType() == JetTokens.ANDAND) {
ifExpression.replace(
psiFactory.createIf(leftExpression, psiFactory.wrapInABlock(
psiFactory.createIf(rightExpression, thenExpression, elseExpression)
),
elseExpression)
)
}
else {
ifExpression.replace(psiFactory.createIf(leftExpression, thenExpression,
psiFactory.createIf(rightExpression, thenExpression, elseExpression))
)
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)
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 rightString = condition.getText()!![startOffset, condition.getTextLength()].toString()
val rightString = condition.getText()!!.substring(startOffset, condition.getTextLength())
return JetPsiFactory(element).createExpression(rightString)
}
private fun isCursorOnIfKeyword(element: JetIfExpression, offset: Int): Boolean {
val ifKeyword = JetPsiUtil.findChildByType(element, JetTokens.IF_KEYWORD) ?: return false
return (offset >= ifKeyword.getTextOffset() && offset <= ifKeyword.getTextOffset() + ifKeyword.getTextLength())
}
private 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) }
val condition = element.getCondition() ?: return null
return PsiTreeUtil.findChildrenOfType(condition, javaClass<JetSimpleNameExpression>())
.firstOrNull { isOperatorValid(it) }
}
private fun isOperatorValid(element: JetSimpleNameExpression): Boolean {
val operator = element.getReferencedNameElementType()
if (operator != JetTokens.ANDAND && operator != JetTokens.OROR) return false
if (element.getParent() !is JetBinaryExpression) return false
var expression = element.getParent() as JetBinaryExpression
var expression = element.getParent() as? JetBinaryExpression ?: return false
if (expression.getRight() == null || expression.getLeft() == null) return false
while (expression.getParent() is JetBinaryExpression) {
expression = expression.getParent() as JetBinaryExpression
if (operator == JetTokens.ANDAND && expression.getOperationToken() != JetTokens.ANDAND) return false
if (operator == JetTokens.OROR && expression.getOperationToken() != JetTokens.OROR) return false
while (true) {
expression = expression.getParent() as? JetBinaryExpression ?: break
if (expression.getOperationToken() != operator) return false
}
if (expression.getParent()?.getParent() !is JetIfExpression) return false
val ifExpression = expression.getParent()?.getParent() as JetIfExpression
val ifExpression = expression.getParent()?.getParent() as? JetIfExpression ?: return false
if (ifExpression.getCondition() == null) return false
if (!PsiTreeUtil.isAncestor(ifExpression.getCondition(), element, false)) return false
@@ -2,6 +2,7 @@
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
@@ -4,6 +4,7 @@
// ACTION: Create interface 'A'
// ACTION: Create enum 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
@@ -1,5 +1,6 @@
// "Create class 'A'" "false"
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
@@ -4,6 +4,7 @@
// ACTION: Create interface 'A'
// ACTION: Create enum 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
@@ -2,6 +2,7 @@
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
@@ -4,6 +4,7 @@
// ACTION: Create interface 'A'
// ACTION: Create enum 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p
@@ -2,6 +2,7 @@
// ACTION: Create class 'A'
// ACTION: Create interface 'A'
// ACTION: Convert to block body
// ACTION: Remove explicit type specification
// ERROR: Unresolved reference: A
package p