Fix moving of value parameters and arguments

This commit is contained in:
Alexey Sedunov
2013-06-04 15:35:43 +04:00
parent a78822ddba
commit 7805ee01eb
16 changed files with 200 additions and 28 deletions
@@ -73,6 +73,13 @@ public class JetPsiFactory {
return star;
}
@NotNull
public static PsiElement createComma(Project project) {
PsiElement comma = createType(project, "T<X, Y>").findElementAt(3);
assert comma != null;
return comma;
}
//the pair contains the first and the last elements of a range
public static Pair<PsiElement, PsiElement> createColonAndWhiteSpaces(Project project) {
JetProperty property = createProperty(project, "val x : Int");
@@ -64,6 +64,11 @@ public abstract class AbstractJetUpDownMover extends LineMover {
return firstNonWhiteElement(down ? lineRange.lastElement.getNextSibling() : lineRange.firstElement.getPrevSibling(), down);
}
@Nullable
protected static PsiElement firstNonWhiteSibling(@NotNull PsiElement element, boolean down) {
return firstNonWhiteElement(down ? element.getNextSibling() : element.getPrevSibling(), down);
}
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
return (file instanceof JetFile) && super.checkAvailable(editor, file, info, down);
@@ -5,10 +5,7 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -20,7 +17,7 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
}
@SuppressWarnings("FieldMayBeFinal")
private static Class[] MOVABLE_ELEMENT_CLASSES = {JetExpression.class, JetWhenEntry.class, PsiComment.class};
private static Class[] MOVABLE_ELEMENT_CLASSES = {JetExpression.class, JetWhenEntry.class, JetValueArgument.class, PsiComment.class};
@SuppressWarnings("FieldMayBeFinal")
private static Class[] BLOCKLIKE_ELEMENT_CLASSES =
@@ -231,12 +228,35 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
}
@Nullable
private static LineRange getTargetRange(
private LineRange getValueParamOrArgTargetRange(@NotNull Editor editor, @NotNull PsiElement elementToCheck, @NotNull PsiElement sibling, boolean down) {
PsiElement next = sibling;
if (next.getNode().getElementType() == JetTokens.COMMA) {
next = firstNonWhiteSibling(next, down);
}
LineRange range = (next instanceof JetParameter || next instanceof JetValueArgument)
? new LineRange(next, next, editor.getDocument())
: null;
if (range != null) {
parametersOrArgsToMove = new Pair<PsiElement, PsiElement>(elementToCheck, next);
}
return range;
}
@Nullable
private LineRange getTargetRange(
@NotNull Editor editor,
@Nullable PsiElement elementToCheck,
@NotNull PsiElement sibling,
boolean down
) {
if (elementToCheck instanceof JetParameter || elementToCheck instanceof JetValueArgument) {
return getValueParamOrArgTargetRange(editor, elementToCheck, sibling, down);
}
if (elementToCheck instanceof JetExpression || elementToCheck instanceof PsiComment) {
return getExpressionTargetRange(editor, sibling, down);
}
@@ -276,19 +296,16 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
return movableElement;
}
private static enum MoveStatus {
DEFAULT,
FORBIDDEN,
PERMITTED
private static boolean isLastOfItsKind(@NotNull PsiElement element, boolean down) {
return getSiblingOfType(element, down, element.getClass()) == null;
}
private static MoveStatus getMoveStatus(@NotNull PsiElement element, boolean down) {
if (element instanceof JetParameter) {
PsiElement sibling = getSiblingOfType(element, down, element.getClass());
return (sibling != null) ? MoveStatus.DEFAULT : MoveStatus.FORBIDDEN;
private static boolean isForbiddenMove(@NotNull PsiElement element, boolean down) {
if (element instanceof JetParameter || element instanceof JetValueArgument) {
return isLastOfItsKind(element, down);
}
return MoveStatus.PERMITTED;
return false;
}
private static boolean isBracelessBlock(@NotNull PsiElement element) {
@@ -348,6 +365,8 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
parametersOrArgsToMove = null;
if (!super.checkAvailable(editor, file, info, down)) return false;
switch (checkForMovableClosingBrace(editor, file, info, down)) {
@@ -370,16 +389,13 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
if (firstElement == null || lastElement == null) return false;
MoveStatus firstMoveStatus = getMoveStatus(firstElement, down);
MoveStatus lastMoveStatus = getMoveStatus(lastElement, down);
if (firstMoveStatus == MoveStatus.DEFAULT || lastMoveStatus == MoveStatus.DEFAULT) {
if (isForbiddenMove(firstElement, down) || isForbiddenMove(lastElement, down)) {
info.toMove2 = null;
return true;
}
if (firstMoveStatus == MoveStatus.FORBIDDEN || lastMoveStatus == MoveStatus.FORBIDDEN) {
info.toMove2 = null;
return true;
if ((firstElement instanceof JetParameter || firstElement instanceof JetValueArgument) && PsiTreeUtil.isAncestor(lastElement, firstElement, false)) {
lastElement = firstElement;
}
LineRange sourceRange = getSourceRange(firstElement, lastElement, editor, oldRange);
@@ -394,4 +410,39 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
info.toMove2 = getTargetRange(editor, sourceRange.firstElement, sibling, down);
return true;
}
@Nullable
private Pair<PsiElement, PsiElement> parametersOrArgsToMove;
private static PsiElement getComma(@NotNull PsiElement element) {
PsiElement sibling = firstNonWhiteSibling(element, true);
return sibling != null && (sibling.getNode().getElementType() == JetTokens.COMMA) ? sibling : null;
}
private static void fixCommaIfNeeded(@NotNull PsiElement element, boolean willBeLast) {
PsiElement comma = getComma(element);
if (willBeLast && comma != null) {
comma.delete();
}
else if (!willBeLast && comma == null) {
PsiElement parent = element.getParent();
assert parent != null;
parent.addAfter(JetPsiFactory.createComma(parent.getProject()), element);
}
}
@Override
public void beforeMove(@NotNull Editor editor, @NotNull MoveInfo info, boolean down) {
if (parametersOrArgsToMove != null) {
PsiElement element1 = parametersOrArgsToMove.first;
PsiElement element2 = parametersOrArgsToMove.second;
fixCommaIfNeeded(element1, down && isLastOfItsKind(element2, true));
fixCommaIfNeeded(element2, !down && isLastOfItsKind(element1, true));
//noinspection ConstantConditions
PsiDocumentManager.getInstance(editor.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument());
}
}
}
@@ -0,0 +1,7 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
<caret>a,
b,
c
)
@@ -0,0 +1,7 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,7 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,7 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
b,
c,
<caret>a
)
@@ -0,0 +1,8 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
// IS_APPLICABLE: false
val x = foo(
b,
c,
<caret>a
)
@@ -0,0 +1,7 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
b,
c,
<caret>a
)
@@ -0,0 +1,7 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,7 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,7 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
val x = foo(
<caret>a,
b,
c
)
@@ -0,0 +1,8 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
// IS_APPLICABLE: false
val x = foo(
<caret>a,
b,
c
)
@@ -5,9 +5,9 @@ class A {
U,
W>(
b: Int,
c: Int
<caret>a: Int,
) {
c: Int,
<caret>a: Int
) {
}
class B {
@@ -19,9 +19,11 @@ package org.jetbrains.jet.plugin.codeInsight.moveUpDown;
import com.intellij.codeInsight.editorActions.moveUpDown.MoveStatementDownAction;
import com.intellij.codeInsight.editorActions.moveUpDown.MoveStatementUpAction;
import com.intellij.codeInsight.editorActions.moveUpDown.StatementUpDownMover;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.testFramework.LightCodeInsightTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.InTextDirectivesUtils;
@@ -83,9 +85,14 @@ public abstract class AbstractCodeMoverTest extends LightCodeInsightTestCase {
}
}
private void invokeAndCheck(@NotNull String path, boolean down) {
EditorAction action = down ? new MoveStatementDownAction() : new MoveStatementUpAction();
action.actionPerformed(getEditor(), getCurrentEditorDataContext());
private void invokeAndCheck(@NotNull String path, final boolean down) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
EditorAction action = down ? new MoveStatementDownAction() : new MoveStatementUpAction();
action.actionPerformed(getEditor(), getCurrentEditorDataContext());
}
});
checkResultByFile(path + ".after");
}
@@ -385,6 +385,36 @@ public class CodeMoverTestGenerated extends AbstractCodeMoverTest {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/typeParams3.kt");
}
@TestMetadata("valueArgs1.kt")
public void testValueArgs1() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueArgs1.kt");
}
@TestMetadata("valueArgs2.kt")
public void testValueArgs2() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueArgs2.kt");
}
@TestMetadata("valueArgs3.kt")
public void testValueArgs3() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueArgs3.kt");
}
@TestMetadata("valueArgs4.kt")
public void testValueArgs4() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueArgs4.kt");
}
@TestMetadata("valueArgs5.kt")
public void testValueArgs5() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueArgs5.kt");
}
@TestMetadata("valueArgs6.kt")
public void testValueArgs6() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueArgs6.kt");
}
@TestMetadata("valueParams1.kt")
public void testValueParams1() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueParams1.kt");