KT-3732 "Move statement" should respect DSLs
This commit is contained in:
@@ -13,8 +13,17 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
|
||||
private static final Predicate<JetElement> IS_CALL_EXPRESSION = new Predicate<JetElement>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable JetElement input) {
|
||||
return input instanceof JetCallExpression;
|
||||
}
|
||||
};
|
||||
|
||||
public JetExpressionMover() {
|
||||
}
|
||||
|
||||
@@ -149,14 +158,14 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetBlockExpression findClosestBlock(@NotNull PsiElement anchor, boolean down) {
|
||||
PsiElement current = PsiTreeUtil.getParentOfType(anchor, JetBlockExpression.class);
|
||||
private static JetBlockExpression findClosestBlock(@NotNull PsiElement anchor, boolean down, boolean strict) {
|
||||
PsiElement current = PsiTreeUtil.getParentOfType(anchor, JetBlockExpression.class, strict);
|
||||
while (current != null) {
|
||||
PsiElement parent = current.getParent();
|
||||
if (parent instanceof JetClassBody ||
|
||||
parent instanceof JetClassInitializer ||
|
||||
parent instanceof JetNamedFunction ||
|
||||
parent instanceof JetProperty) {
|
||||
(parent instanceof JetProperty && !((JetProperty) parent).isLocal())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -178,6 +187,18 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetBlockExpression getDSLLambdaBlock(@NotNull PsiElement element, boolean down) {
|
||||
JetCallExpression callExpression =
|
||||
(JetCallExpression) JetPsiUtil.getOutermostDescendantElement(element, down, IS_CALL_EXPRESSION);
|
||||
if (callExpression == null) return null;
|
||||
|
||||
List<JetExpression> functionLiterals = callExpression.getFunctionLiteralArguments();
|
||||
if (functionLiterals.isEmpty()) return null;
|
||||
|
||||
return ((JetFunctionLiteralExpression) functionLiterals.get(0)).getBodyExpression();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static LineRange getExpressionTargetRange(@NotNull Editor editor, @NotNull PsiElement sibling, boolean down) {
|
||||
PsiElement start = sibling;
|
||||
@@ -188,7 +209,14 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
PsiElement parent = sibling.getParent();
|
||||
if (!(parent instanceof JetBlockExpression || parent instanceof JetFunctionLiteral)) return null;
|
||||
|
||||
JetBlockExpression newBlock = findClosestBlock(sibling, down);
|
||||
JetBlockExpression newBlock;
|
||||
if (parent instanceof JetFunctionLiteral) {
|
||||
//noinspection ConstantConditions
|
||||
newBlock = findClosestBlock(((JetFunctionLiteral) parent).getBodyExpression(), down, false);
|
||||
} else {
|
||||
newBlock = findClosestBlock(sibling, down, true);
|
||||
}
|
||||
|
||||
if (newBlock == null) return null;
|
||||
|
||||
if (PsiTreeUtil.isAncestor(newBlock, parent, true)) {
|
||||
@@ -210,10 +238,19 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
}
|
||||
}
|
||||
}
|
||||
// moving into code block
|
||||
else {
|
||||
// moving into code block
|
||||
//noinspection unchecked
|
||||
JetElement blockLikeElement = JetPsiUtil.getOutermostDescendantElement(sibling, down, CHECK_BLOCK_LIKE_ELEMENT);
|
||||
PsiElement blockLikeElement;
|
||||
|
||||
JetBlockExpression dslBlock = getDSLLambdaBlock(sibling, down);
|
||||
if (dslBlock != null) {
|
||||
// Use JetFunctionLiteral (since it contains braces)
|
||||
blockLikeElement = dslBlock.getParent();
|
||||
} else {
|
||||
// JetBlockExpression and other block-like elements
|
||||
blockLikeElement = JetPsiUtil.getOutermostDescendantElement(sibling, down, CHECK_BLOCK_LIKE_ELEMENT);
|
||||
}
|
||||
|
||||
if (blockLikeElement != null) {
|
||||
if (down) {
|
||||
end = JetPsiUtil.findChildByType(blockLikeElement, JetTokens.LBRACE);
|
||||
@@ -331,7 +368,7 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
return block.getLBrace() == null && block.getRBrace() == null;
|
||||
}
|
||||
|
||||
protected static PsiElement adjustWhiteSpaceSibling(
|
||||
protected static PsiElement adjustSibling(
|
||||
@NotNull Editor editor,
|
||||
@NotNull LineRange sourceRange,
|
||||
@NotNull MoveInfo info,
|
||||
@@ -371,6 +408,18 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
}
|
||||
|
||||
if (sibling == null) {
|
||||
JetCallExpression callExpression = PsiTreeUtil.getParentOfType(element, JetCallExpression.class);
|
||||
if (callExpression != null) {
|
||||
JetBlockExpression dslBlock = getDSLLambdaBlock(callExpression, down);
|
||||
if (PsiTreeUtil.isAncestor(dslBlock, element, false)) {
|
||||
//noinspection ConstantConditions
|
||||
PsiElement blockParent = dslBlock.getParent();
|
||||
return down
|
||||
? JetPsiUtil.findChildByType(blockParent, JetTokens.RBRACE)
|
||||
: JetPsiUtil.findChildByType(blockParent, JetTokens.LBRACE);
|
||||
}
|
||||
}
|
||||
|
||||
info.toMove2 = null;
|
||||
return null;
|
||||
}
|
||||
@@ -419,7 +468,7 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
||||
LineRange sourceRange = getSourceRange(firstElement, lastElement, editor, oldRange);
|
||||
if (sourceRange == null) return false;
|
||||
|
||||
PsiElement sibling = adjustWhiteSpaceSibling(editor, sourceRange, info, down);
|
||||
PsiElement sibling = adjustSibling(editor, sourceRange, info, down);
|
||||
|
||||
// Either reached last sibling, or jumped over multi-line whitespace
|
||||
if (sibling == null) return true;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
<caret>println("foo")
|
||||
run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
run(1, 2) {
|
||||
<caret>println("foo")
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
<caret>println("foo")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
run(1, 2) {
|
||||
println("bar")
|
||||
<caret>println("foo")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
<caret>println("foo")
|
||||
val x = run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
val x = run(1, 2) {
|
||||
<caret>println("foo")
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
val x = run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
<caret>println("foo")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
val x = run(1, 2) {
|
||||
println("bar")
|
||||
<caret>println("foo")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
run(1, 2) {
|
||||
<caret>println("foo")
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
<caret>println("foo")
|
||||
run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
run(1, 2) {
|
||||
println("bar")
|
||||
<caret>println("foo")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
<caret>println("foo")
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
val x = run(1, 2) {
|
||||
<caret>println("foo")
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: up
|
||||
fun foo() {
|
||||
<caret>println("foo")
|
||||
val x = run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
val x = run(1, 2) {
|
||||
println("bar")
|
||||
<caret>println("foo")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// MOVE: down
|
||||
fun foo() {
|
||||
val x = run(1, 2) {
|
||||
println("bar")
|
||||
}
|
||||
<caret>println("foo")
|
||||
}
|
||||
+40
@@ -847,6 +847,26 @@ public class CodeMoverTestGenerated extends AbstractCodeMoverTest {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/if4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intoClosure1.kt")
|
||||
public void testIntoClosure1() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/intoClosure1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intoClosure2.kt")
|
||||
public void testIntoClosure2() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/intoClosure2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intoNestedClosure1.kt")
|
||||
public void testIntoNestedClosure1() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/intoNestedClosure1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("intoNestedClosure2.kt")
|
||||
public void testIntoNestedClosure2() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/intoNestedClosure2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lambda1.kt")
|
||||
public void testLambda1() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/lambda1.kt");
|
||||
@@ -862,6 +882,26 @@ public class CodeMoverTestGenerated extends AbstractCodeMoverTest {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/lambda3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("outOfClosure1.kt")
|
||||
public void testOutOfClosure1() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/outOfClosure1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("outOfClosure2.kt")
|
||||
public void testOutOfClosure2() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/outOfClosure2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("outOfNestedClosure1.kt")
|
||||
public void testOutOfNestedClosure1() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/outOfNestedClosure1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("outOfNestedClosure2.kt")
|
||||
public void testOutOfNestedClosure2() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/outOfNestedClosure2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("when1.kt")
|
||||
public void testWhen1() throws Exception {
|
||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/when1.kt");
|
||||
|
||||
Reference in New Issue
Block a user