Fix moving of value/type parameters

This commit is contained in:
Alexey Sedunov
2013-05-30 17:30:51 +04:00
parent 57edbdfbc4
commit 5345d0a0d5
33 changed files with 526 additions and 11 deletions
@@ -8,6 +8,7 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetFile;
@@ -51,6 +52,11 @@ public abstract class AbstractJetUpDownMover extends LineMover {
return sibling;
}
@Nullable
protected static PsiElement getSiblingOfType(@NotNull PsiElement element, boolean down, @NotNull Class<? extends PsiElement> type) {
return down ? PsiTreeUtil.getNextSiblingOfType(element, type) : PsiTreeUtil.getPrevSiblingOfType(element, type);
}
@Nullable
protected static PsiElement firstNonWhiteSibling(@NotNull LineRange lineRange, boolean down) {
return firstNonWhiteElement(down ? lineRange.lastElement.getNextSibling() : lineRange.firstElement.getPrevSibling(), down);
@@ -49,9 +49,6 @@ public class JetDeclarationMover extends AbstractJetUpDownMover {
PsiElement equalsToken = function.getEqualsToken();
if (equalsToken != null) memberSuspects.add(equalsToken);
JetParameterList parameterList = function.getValueParameterList();
if (parameterList != null) memberSuspects.add(parameterList);
JetTypeParameterList typeParameterList = function.getTypeParameterList();
if (typeParameterList != null) memberSuspects.add(typeParameterList);
@@ -120,6 +117,9 @@ public class JetDeclarationMover extends AbstractJetUpDownMover {
if (element == null) return null;
JetDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetDeclaration.class, false);
if (declaration instanceof JetTypeParameter) {
return getMovableDeclaration(declaration.getParent());
}
return PsiTreeUtil.instanceOf(PsiTreeUtil.getParentOfType(declaration,
DECLARATION_CONTAINER_CLASSES),
@@ -291,6 +291,23 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
return sourceRange;
}
@Nullable
private static PsiElement getMovableElement(@NotNull PsiElement element) {
return PsiTreeUtil.getNonStrictParentOfType(element, MOVABLE_ELEMENT_CLASSES);
}
// return true to forbid the move
// return false to permit the move
// return null to fall back to default line mover behavior
private static Boolean isForbiddenMove(@NotNull PsiElement element, boolean down) {
if (element instanceof JetParameter) {
PsiElement sibling = getSiblingOfType(element, down, element.getClass());
return (sibling != null) ? null : true;
}
return false;
}
@Override
public boolean checkAvailable(@NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) {
if (!super.checkAvailable(editor, file, info, down)) return false;
@@ -309,12 +326,22 @@ public class JetExpressionMover extends AbstractJetUpDownMover {
if (psiRange == null) return false;
//noinspection unchecked
PsiElement firstElement = PsiTreeUtil.getNonStrictParentOfType(psiRange.getFirst(), MOVABLE_ELEMENT_CLASSES);
if (firstElement == null) return false;
PsiElement firstElement = getMovableElement(psiRange.getFirst());
PsiElement lastElement = getMovableElement(psiRange.getSecond());
//noinspection unchecked
PsiElement lastElement = PsiTreeUtil.getNonStrictParentOfType(psiRange.getSecond(), MOVABLE_ELEMENT_CLASSES);
if (lastElement == null) return false;
if (firstElement == null || lastElement == null) return false;
Boolean forbidFirst = isForbiddenMove(firstElement, down);
Boolean forbidLast = isForbiddenMove(lastElement, down);
if (forbidFirst == null || forbidLast == null) {
return true;
}
if (forbidFirst || forbidLast) {
info.toMove2 = null;
return true;
}
LineRange sourceRange = getSourceRange(firstElement, lastElement, editor);
if (sourceRange == null) return false;
@@ -0,0 +1,9 @@
// MOVE: down
class A {
fun <caret>foo() {
}
class B {
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class A {
class B {
fun <caret>foo() {
}
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class A {
fun <caret>foo() {
}
class B {
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class A {
class B {
fun <caret>foo() {
}
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class A {
fun foo(): Unit<caret> {
}
class B {
}
}
@@ -0,0 +1,9 @@
// MOVE: down
class A {
class B {
fun foo(): Unit<caret> {
}
}
}
@@ -0,0 +1,15 @@
// MOVE: down
class A {
fun foo<<caret>T,
U,
W>(
b: Int,
a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,15 @@
// MOVE: down
class A {
class B {
fun foo<<caret>T,
U,
W>(
b: Int,
a: Int,
c: Int
) {
}
}
}
@@ -0,0 +1,15 @@
// MOVE: down
class A {
fun foo<T,
U<caret>,
W>(
b: Int,
a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,15 @@
// MOVE: down
class A {
class B {
fun foo<T,
U<caret>,
W>(
b: Int,
a: Int,
c: Int
) {
}
}
}
@@ -0,0 +1,15 @@
// MOVE: down
class A {
fun foo<T,
U,
W<caret>>(
b: Int,
a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,15 @@
// MOVE: down
class A {
class B {
fun foo<T,
U,
W<caret>>(
b: Int,
a: Int,
c: Int
) {
}
}
}
@@ -0,0 +1,16 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
b:<caret> Int,
a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,16 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
a: Int,
b:<caret> Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,16 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
b: Int,
<caret>a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,16 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
b: Int,
c: Int
<caret>a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,16 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
a: Int,
b:<caret> Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,16 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
b:<caret> Int,
a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,16 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
b: Int,
c: Int
<caret>a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,16 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
class A {
fun foo<T,
U,
W>(
b: Int,
<caret>a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,17 @@
// MOVE: down
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
// IS_APPLICABLE: false
class A {
fun foo<T,
U,
W>(
b: Int,
c: Int
<caret>a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,17 @@
// MOVE: up
// MOVER_CLASS: org.jetbrains.jet.plugin.codeInsight.upDownMover.JetExpressionMover
// IS_APPLICABLE: false
class A {
fun foo<T,
U,
W>(
b: Int<caret>,
c: Int
a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
<caret>val x: String
get() {
return ""
}
set(v: String) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
class B {
<caret>val x: String
get() {
return ""
}
set(v: String) {
}
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
val x<caret>: String
get() {
return ""
}
set(v: String) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
class B {
val x<caret>: String
get() {
return ""
}
set(v: String) {
}
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
val x: String<caret>
get() {
return ""
}
set(v: String) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
class B {
val x: String<caret>
get() {
return ""
}
set(v: String) {
}
}
}
@@ -39,7 +39,7 @@ public abstract class AbstractCodeMoverTest extends LightCodeInsightTestCase {
doTest(path, JetExpressionMover.class);
}
private void doTest(@NotNull String path, @NotNull Class<? extends StatementUpDownMover> moverClass) throws Exception {
private void doTest(@NotNull String path, @NotNull Class<? extends StatementUpDownMover> defaultMoverClass) throws Exception {
configureByFile(path);
String fileText = FileUtil.loadFile(new File(path));
@@ -69,8 +69,13 @@ public abstract class AbstractCodeMoverTest extends LightCodeInsightTestCase {
}
}
String moverClassName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MOVER_CLASS: ");
if (moverClassName == null) {
moverClassName = defaultMoverClass.getName();
}
assertTrue("No mover found", actualMover != null);
assertEquals("Unmatched movers", moverClass, actualMover.getClass());
assertEquals("Unmatched movers", moverClassName, actualMover.getClass().getName());
assertEquals("Invalid applicability", isApplicableExpected, info.toMove2 != null);
if (isApplicableExpected) {
@@ -33,7 +33,7 @@ import org.jetbrains.jet.plugin.codeInsight.moveUpDown.AbstractCodeMoverTest;
@InnerTestClasses({CodeMoverTestGenerated.ClassBodyDeclarations.class, CodeMoverTestGenerated.ClosingBraces.class, CodeMoverTestGenerated.Expressions.class})
public class CodeMoverTestGenerated extends AbstractCodeMoverTest {
@TestMetadata("idea/testData/codeInsight/moveUpDown/classBodyDeclarations")
@InnerTestClasses({ClassBodyDeclarations.Accessors.class, ClassBodyDeclarations.Class.class, ClassBodyDeclarations.ClassInitializer.class, ClassBodyDeclarations.Enums.class, ClassBodyDeclarations.Function.class, ClassBodyDeclarations.Property.class})
@InnerTestClasses({ClassBodyDeclarations.Accessors.class, ClassBodyDeclarations.Class.class, ClassBodyDeclarations.ClassInitializer.class, ClassBodyDeclarations.Enums.class, ClassBodyDeclarations.Function.class, ClassBodyDeclarations.FunctionAnchors.class, ClassBodyDeclarations.Property.class, ClassBodyDeclarations.PropertyAnchors.class})
public static class ClassBodyDeclarations extends AbstractCodeMoverTest {
public void testAllFilesPresentInClassBodyDeclarations() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/codeInsight/moveUpDown/classBodyDeclarations"), Pattern.compile("^(.+)\\.kt$"), true);
@@ -349,6 +349,74 @@ public class CodeMoverTestGenerated extends AbstractCodeMoverTest {
}
@TestMetadata("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors")
public static class FunctionAnchors extends AbstractCodeMoverTest {
public void testAllFilesPresentInFunctionAnchors() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("keyword.kt")
public void testKeyword() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/keyword.kt");
}
@TestMetadata("name.kt")
public void testName() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/name.kt");
}
@TestMetadata("returnType.kt")
public void testReturnType() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/returnType.kt");
}
@TestMetadata("typeParams1.kt")
public void testTypeParams1() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/typeParams1.kt");
}
@TestMetadata("typeParams2.kt")
public void testTypeParams2() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/typeParams2.kt");
}
@TestMetadata("typeParams3.kt")
public void testTypeParams3() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/typeParams3.kt");
}
@TestMetadata("valueParams1.kt")
public void testValueParams1() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueParams1.kt");
}
@TestMetadata("valueParams2.kt")
public void testValueParams2() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueParams2.kt");
}
@TestMetadata("valueParams3.kt")
public void testValueParams3() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueParams3.kt");
}
@TestMetadata("valueParams4.kt")
public void testValueParams4() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueParams4.kt");
}
@TestMetadata("valueParams5.kt")
public void testValueParams5() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueParams5.kt");
}
@TestMetadata("valueParams6.kt")
public void testValueParams6() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/functionAnchors/valueParams6.kt");
}
}
@TestMetadata("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/property")
public static class Property extends AbstractCodeMoverTest {
public void testAllFilesPresentInProperty() throws Exception {
@@ -437,6 +505,29 @@ public class CodeMoverTestGenerated extends AbstractCodeMoverTest {
}
@TestMetadata("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/propertyAnchors")
public static class PropertyAnchors extends AbstractCodeMoverTest {
public void testAllFilesPresentInPropertyAnchors() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/propertyAnchors"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("keyword.kt")
public void testKeyword() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/propertyAnchors/keyword.kt");
}
@TestMetadata("name.kt")
public void testName() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/propertyAnchors/name.kt");
}
@TestMetadata("returnType.kt")
public void testReturnType() throws Exception {
doTestClassBodyDeclaration("idea/testData/codeInsight/moveUpDown/classBodyDeclarations/propertyAnchors/returnType.kt");
}
}
public static Test innerSuite() {
TestSuite suite = new TestSuite("ClassBodyDeclarations");
suite.addTestSuite(ClassBodyDeclarations.class);
@@ -445,7 +536,9 @@ public class CodeMoverTestGenerated extends AbstractCodeMoverTest {
suite.addTestSuite(ClassInitializer.class);
suite.addTestSuite(Enums.class);
suite.addTestSuite(Function.class);
suite.addTestSuite(FunctionAnchors.class);
suite.addTestSuite(Property.class);
suite.addTestSuite(PropertyAnchors.class);
return suite;
}
}