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.lang.psi.*;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class JetExpressionMover extends AbstractJetUpDownMover {
|
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() {
|
public JetExpressionMover() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,14 +158,14 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static JetBlockExpression findClosestBlock(@NotNull PsiElement anchor, boolean down) {
|
private static JetBlockExpression findClosestBlock(@NotNull PsiElement anchor, boolean down, boolean strict) {
|
||||||
PsiElement current = PsiTreeUtil.getParentOfType(anchor, JetBlockExpression.class);
|
PsiElement current = PsiTreeUtil.getParentOfType(anchor, JetBlockExpression.class, strict);
|
||||||
while (current != null) {
|
while (current != null) {
|
||||||
PsiElement parent = current.getParent();
|
PsiElement parent = current.getParent();
|
||||||
if (parent instanceof JetClassBody ||
|
if (parent instanceof JetClassBody ||
|
||||||
parent instanceof JetClassInitializer ||
|
parent instanceof JetClassInitializer ||
|
||||||
parent instanceof JetNamedFunction ||
|
parent instanceof JetNamedFunction ||
|
||||||
parent instanceof JetProperty) {
|
(parent instanceof JetProperty && !((JetProperty) parent).isLocal())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +187,18 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
|||||||
return null;
|
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
|
@Nullable
|
||||||
private static LineRange getExpressionTargetRange(@NotNull Editor editor, @NotNull PsiElement sibling, boolean down) {
|
private static LineRange getExpressionTargetRange(@NotNull Editor editor, @NotNull PsiElement sibling, boolean down) {
|
||||||
PsiElement start = sibling;
|
PsiElement start = sibling;
|
||||||
@@ -188,7 +209,14 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
|||||||
PsiElement parent = sibling.getParent();
|
PsiElement parent = sibling.getParent();
|
||||||
if (!(parent instanceof JetBlockExpression || parent instanceof JetFunctionLiteral)) return null;
|
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 (newBlock == null) return null;
|
||||||
|
|
||||||
if (PsiTreeUtil.isAncestor(newBlock, parent, true)) {
|
if (PsiTreeUtil.isAncestor(newBlock, parent, true)) {
|
||||||
@@ -210,10 +238,19 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// moving into code block
|
||||||
else {
|
else {
|
||||||
// moving into code block
|
PsiElement blockLikeElement;
|
||||||
//noinspection unchecked
|
|
||||||
JetElement blockLikeElement = JetPsiUtil.getOutermostDescendantElement(sibling, down, CHECK_BLOCK_LIKE_ELEMENT);
|
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 (blockLikeElement != null) {
|
||||||
if (down) {
|
if (down) {
|
||||||
end = JetPsiUtil.findChildByType(blockLikeElement, JetTokens.LBRACE);
|
end = JetPsiUtil.findChildByType(blockLikeElement, JetTokens.LBRACE);
|
||||||
@@ -331,7 +368,7 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
|||||||
return block.getLBrace() == null && block.getRBrace() == null;
|
return block.getLBrace() == null && block.getRBrace() == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static PsiElement adjustWhiteSpaceSibling(
|
protected static PsiElement adjustSibling(
|
||||||
@NotNull Editor editor,
|
@NotNull Editor editor,
|
||||||
@NotNull LineRange sourceRange,
|
@NotNull LineRange sourceRange,
|
||||||
@NotNull MoveInfo info,
|
@NotNull MoveInfo info,
|
||||||
@@ -371,6 +408,18 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sibling == null) {
|
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;
|
info.toMove2 = null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -419,7 +468,7 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
|
|||||||
LineRange sourceRange = getSourceRange(firstElement, lastElement, editor, oldRange);
|
LineRange sourceRange = getSourceRange(firstElement, lastElement, editor, oldRange);
|
||||||
if (sourceRange == null) return false;
|
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
|
// Either reached last sibling, or jumped over multi-line whitespace
|
||||||
if (sibling == null) return true;
|
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");
|
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")
|
@TestMetadata("lambda1.kt")
|
||||||
public void testLambda1() throws Exception {
|
public void testLambda1() throws Exception {
|
||||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/lambda1.kt");
|
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");
|
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")
|
@TestMetadata("when1.kt")
|
||||||
public void testWhen1() throws Exception {
|
public void testWhen1() throws Exception {
|
||||||
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/when1.kt");
|
doTestExpression("idea/testData/codeInsight/moveUpDown/expressions/when1.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user