From a21f19d6136b8c210b23d93fa0d192d933b5854f Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Sat, 4 Mar 2017 17:34:15 +0300 Subject: [PATCH] Move: Use Kotlin declaration mover to handle KtFile IDEA-provided file mover does not process conflicts #KT-13911 Fixed --- .../jetbrains/kotlin/idea/test/testUtils.kt | 28 +-- .../MoveKotlinDeclarationsHandler.kt | 24 ++- .../declarations/commonTargets/pack/test2.kt | 5 + .../declarations/commonTargets/test.kt | 5 + .../fileAndTopLevelDeclarations/test.kt | 7 + .../fileAndTopLevelDeclarations/test2.kt | 7 + .../declarations/innerClass/test.kt | 5 + .../declarations/localClass/test.kt | 3 + .../moveHandler/declarations/localFun/test.kt | 5 + .../moveHandler/declarations/localVal/test.kt | 3 + .../declarations/memberFun/test.kt | 5 + .../declarations/memberVal/test.kt | 3 + .../multipleNestedClasses/test.kt | 7 + .../multipleTopLevelDeclarations/test.kt | 7 + .../test1/test.kt | 7 + .../test2/test2.kt | 7 + .../test.kt | 7 + .../test2.kt | 7 + .../nestedAndTopLevelClass/test.kt | 5 + .../declarations/nestedClass/test.kt | 5 + .../declarations/nestedClassToClass/test.kt | 7 + .../declarations/nestedClassToClass/test2.kt | 5 + .../declarations/objectLiteral/test.kt | 7 + .../declarations/topLevelClass/test.kt | 5 + .../declarations/topLevelClassToClass/test.kt | 5 + .../topLevelClassToClass/test2.kt | 5 + .../declarations/topLevelFun/test.kt | 5 + .../declarations/topLevelVal/test.kt | 3 + .../move/MoveKotlinDeclarationsHandlerTest.kt | 201 ++++++++++++++++++ 29 files changed, 378 insertions(+), 17 deletions(-) create mode 100644 idea/testData/refactoring/moveHandler/declarations/commonTargets/pack/test2.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/commonTargets/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test2.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/innerClass/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/localClass/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/localFun/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/localVal/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/memberFun/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/memberVal/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/multipleNestedClasses/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarations/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test1/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test2/test2.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test2.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/nestedAndTopLevelClass/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/nestedClass/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test2.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/objectLiteral/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/topLevelClass/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test2.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/topLevelFun/test.kt create mode 100644 idea/testData/refactoring/moveHandler/declarations/topLevelVal/test.kt create mode 100644 idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinDeclarationsHandlerTest.kt diff --git a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt index ae9cb1402d2..275ad30d6df 100644 --- a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt +++ b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.idea.test -import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Document import com.intellij.openapi.module.Module @@ -30,7 +29,6 @@ import com.intellij.psi.impl.PsiManagerEx import com.intellij.psi.impl.file.impl.FileManagerImpl import com.intellij.psi.impl.source.PsiFileImpl import com.intellij.testFramework.LightPlatformTestCase -import com.intellij.testFramework.ThreadTracker import com.intellij.util.Consumer import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages @@ -42,8 +40,6 @@ import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.psi.KtFile import java.lang.IllegalArgumentException import java.util.* -import java.util.concurrent.ForkJoinPool -import java.util.concurrent.atomic.AtomicBoolean enum class ModuleKind { KOTLIN_JVM_WITH_STDLIB_SOURCES, @@ -129,20 +125,28 @@ fun invalidateLibraryCache(project: Project) { } fun Document.extractMarkerOffset(project: Project, caretMarker: String = ""): Int { - val offset = runWriteAction { + return extractMultipleMarkerOffsets(project, caretMarker).singleOrNull() ?: -1 +} + +fun Document.extractMultipleMarkerOffsets(project: Project, caretMarker: String = ""): List { + val offsets = ArrayList() + + runWriteAction { val text = StringBuilder(text) - val offset = text.indexOf(caretMarker) + while (true) { + val offset = text.indexOf(caretMarker) + if (offset >= 0) { + text.delete(offset, offset + caretMarker.length) + setText(text.toString()) - if (offset >= 0) { - text.delete(offset, offset + caretMarker.length) - setText(text.toString()) + offsets += offset + } + else break } - - offset } PsiDocumentManager.getInstance(project).commitAllDocuments() PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(this) - return offset + return offsets } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsHandler.kt index 0d912e5cf93..ece33932ec4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/MoveKotlinDeclarationsHandler.kt @@ -46,7 +46,11 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() { private fun getUniqueContainer(elements: Array): PsiElement? { val getContainer: (PsiElement) -> PsiElement? = if (elements.any { it.parent !is KtFile }) { e -> - (e as? KtNamedDeclaration)?.containingClassOrObject + when (e) { + is KtNamedDeclaration -> e.containingClassOrObject ?: e.parent + is KtFile -> e.parent + else -> null + } } else { e -> e.containingFile?.parent @@ -69,7 +73,13 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() { return false } - val elementsToSearch = elements.mapTo(LinkedHashSet()) { it as KtNamedDeclaration } + val elementsToSearch = elements.flatMapTo(LinkedHashSet()) { + when (it) { + is KtNamedDeclaration -> listOf(it) + is KtFile -> it.declarations.filterIsInstance() + else -> emptyList() + } + } // todo: allow moving companion object if (elementsToSearch.any { it is KtObjectDeclaration && it.isCompanion() }) { @@ -142,10 +152,14 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() { } return elements.all { e -> - if (e is KtClass || (e is KtObjectDeclaration && !e.isObjectLiteral()) || e is KtNamedFunction || e is KtProperty) { - (editorMode || (e as KtNamedDeclaration).canMove()) && e.canRefactor() + when { + e is KtClass || e is KtObjectDeclaration && !e.isObjectLiteral() || e is KtNamedFunction || e is KtProperty -> + (editorMode || (e as KtNamedDeclaration).canMove()) && e.canRefactor() + e is KtFile -> + e.declarations.any { it is KtNamedDeclaration } && e.canRefactor() + else -> + false } - else false } } diff --git a/idea/testData/refactoring/moveHandler/declarations/commonTargets/pack/test2.kt b/idea/testData/refactoring/moveHandler/declarations/commonTargets/pack/test2.kt new file mode 100644 index 00000000000..339890cc3e3 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/commonTargets/pack/test2.kt @@ -0,0 +1,5 @@ +package pack + +fun test() { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/commonTargets/test.kt b/idea/testData/refactoring/moveHandler/declarations/commonTargets/test.kt new file mode 100644 index 00000000000..48a90cfe8d5 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/commonTargets/test.kt @@ -0,0 +1,5 @@ +class A + +fun foo() { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test.kt b/idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test.kt new file mode 100644 index 00000000000..b217e893add --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test.kt @@ -0,0 +1,7 @@ +class A + +fun foo() { + +} + +val bar = 1 \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test2.kt b/idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test2.kt new file mode 100644 index 00000000000..f6e12e9a5be --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/fileAndTopLevelDeclarations/test2.kt @@ -0,0 +1,7 @@ +class A2 + +fun foo2() { + +} + +val bar2 = 1 \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/innerClass/test.kt b/idea/testData/refactoring/moveHandler/declarations/innerClass/test.kt new file mode 100644 index 00000000000..b7989b20483 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/innerClass/test.kt @@ -0,0 +1,5 @@ +class A { + inner class B { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/localClass/test.kt b/idea/testData/refactoring/moveHandler/declarations/localClass/test.kt new file mode 100644 index 00000000000..1024c0fe8d4 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/localClass/test.kt @@ -0,0 +1,3 @@ +fun foo() { + class A +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/localFun/test.kt b/idea/testData/refactoring/moveHandler/declarations/localFun/test.kt new file mode 100644 index 00000000000..a4eb734d470 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/localFun/test.kt @@ -0,0 +1,5 @@ +fun foo() { + fun bar() { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/localVal/test.kt b/idea/testData/refactoring/moveHandler/declarations/localVal/test.kt new file mode 100644 index 00000000000..4acb0f17896 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/localVal/test.kt @@ -0,0 +1,3 @@ +fun foo() { + val bar = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/memberFun/test.kt b/idea/testData/refactoring/moveHandler/declarations/memberFun/test.kt new file mode 100644 index 00000000000..9d2f7bd1083 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/memberFun/test.kt @@ -0,0 +1,5 @@ +class A { + fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/memberVal/test.kt b/idea/testData/refactoring/moveHandler/declarations/memberVal/test.kt new file mode 100644 index 00000000000..98810f200d8 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/memberVal/test.kt @@ -0,0 +1,3 @@ +class A { + val foo = 1 +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/multipleNestedClasses/test.kt b/idea/testData/refactoring/moveHandler/declarations/multipleNestedClasses/test.kt new file mode 100644 index 00000000000..fe3320956d9 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/multipleNestedClasses/test.kt @@ -0,0 +1,7 @@ +class A { + class B + + class C + + class D +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarations/test.kt b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarations/test.kt new file mode 100644 index 00000000000..b217e893add --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarations/test.kt @@ -0,0 +1,7 @@ +class A + +fun foo() { + +} + +val bar = 1 \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test1/test.kt b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test1/test.kt new file mode 100644 index 00000000000..b217e893add --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test1/test.kt @@ -0,0 +1,7 @@ +class A + +fun foo() { + +} + +val bar = 1 \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test2/test2.kt b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test2/test2.kt new file mode 100644 index 00000000000..d5c75efea85 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentDirs/test2/test2.kt @@ -0,0 +1,7 @@ +class A2 + +fun foo2() { + +} + +val bar2 = 1 \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test.kt b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test.kt new file mode 100644 index 00000000000..b217e893add --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test.kt @@ -0,0 +1,7 @@ +class A + +fun foo() { + +} + +val bar = 1 \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test2.kt b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test2.kt new file mode 100644 index 00000000000..d5c75efea85 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/multipleTopLevelDeclarationsInDifferentFiles/test2.kt @@ -0,0 +1,7 @@ +class A2 + +fun foo2() { + +} + +val bar2 = 1 \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/nestedAndTopLevelClass/test.kt b/idea/testData/refactoring/moveHandler/declarations/nestedAndTopLevelClass/test.kt new file mode 100644 index 00000000000..d6667b8e26c --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/nestedAndTopLevelClass/test.kt @@ -0,0 +1,5 @@ +class A { + inner class B { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/nestedClass/test.kt b/idea/testData/refactoring/moveHandler/declarations/nestedClass/test.kt new file mode 100644 index 00000000000..8e72f35163d --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/nestedClass/test.kt @@ -0,0 +1,5 @@ +class A { + class B { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test.kt b/idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test.kt new file mode 100644 index 00000000000..86884e59956 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test.kt @@ -0,0 +1,7 @@ +class X { + class Y +} + +fun foo() { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test2.kt b/idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test2.kt new file mode 100644 index 00000000000..9376782166b --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/nestedClassToClass/test2.kt @@ -0,0 +1,5 @@ +class B { + class C +} + +annotation class Ann \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/objectLiteral/test.kt b/idea/testData/refactoring/moveHandler/declarations/objectLiteral/test.kt new file mode 100644 index 00000000000..b534156c102 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/objectLiteral/test.kt @@ -0,0 +1,7 @@ +open class A + +fun foo() { + val o = object : A() { + + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/topLevelClass/test.kt b/idea/testData/refactoring/moveHandler/declarations/topLevelClass/test.kt new file mode 100644 index 00000000000..48a90cfe8d5 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/topLevelClass/test.kt @@ -0,0 +1,5 @@ +class A + +fun foo() { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test.kt b/idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test.kt new file mode 100644 index 00000000000..1e5918d7d43 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test.kt @@ -0,0 +1,5 @@ +class X + +fun foo() { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test2.kt b/idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test2.kt new file mode 100644 index 00000000000..9376782166b --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/topLevelClassToClass/test2.kt @@ -0,0 +1,5 @@ +class B { + class C +} + +annotation class Ann \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/topLevelFun/test.kt b/idea/testData/refactoring/moveHandler/declarations/topLevelFun/test.kt new file mode 100644 index 00000000000..3e8af9edaa8 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/topLevelFun/test.kt @@ -0,0 +1,5 @@ +class A + +fun foo() { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/moveHandler/declarations/topLevelVal/test.kt b/idea/testData/refactoring/moveHandler/declarations/topLevelVal/test.kt new file mode 100644 index 00000000000..d27e44fc9e4 --- /dev/null +++ b/idea/testData/refactoring/moveHandler/declarations/topLevelVal/test.kt @@ -0,0 +1,3 @@ +class A + +val foo = 1 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinDeclarationsHandlerTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinDeclarationsHandlerTest.kt new file mode 100644 index 00000000000..243a4e30ee9 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/MoveKotlinDeclarationsHandlerTest.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.refactoring.move + +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.testFramework.PlatformTestCase +import com.intellij.testFramework.PsiTestUtil +import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsHandler +import org.jetbrains.kotlin.idea.refactoring.toPsiDirectory +import org.jetbrains.kotlin.idea.refactoring.toPsiFile +import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase +import org.jetbrains.kotlin.idea.test.extractMultipleMarkerOffsets +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance + +class MoveKotlinDeclarationsHandlerTest : KotlinMultiFileTestCase() { + override fun getTestDataPath() = PluginTestCaseBase.getTestDataPathBase() + + override fun getTestRoot() = "/refactoring/moveHandler/declarations" + + private fun doTest(action: (rootDir: VirtualFile, handler: MoveKotlinDeclarationsHandler) -> Unit) { + val path = "$testDataPath$testRoot/${getTestName(true)}" + val rootDir = PsiTestUtil.createTestProjectStructure(myProject, myModule, path, PlatformTestCase.myFilesToDelete, false) + prepareProject(rootDir) + PsiDocumentManager.getInstance(myProject).commitAllDocuments() + action(rootDir, MoveKotlinDeclarationsHandler()) + } + + private fun getPsiDirectory(rootDir: VirtualFile, path: String) = rootDir.findFileByRelativePath(path)!!.toPsiDirectory(project)!! + + private fun getPsiFile(rootDir: VirtualFile, path: String) = rootDir.findFileByRelativePath(path)!!.toPsiFile(project)!! + + private fun getElementAtCaret(rootDir: VirtualFile, path: String) = getElementsAtCarets(rootDir, path).single() + + private fun getElementsAtCarets(rootDir: VirtualFile, path: String): List { + val file = getPsiFile(rootDir, path) + val document = FileDocumentManager.getInstance().getDocument(file.virtualFile)!! + return document.extractMultipleMarkerOffsets(project).map { file.findElementAt(it)!! } + } + + fun testObjectLiteral() = doTest { rootDir, handler -> + val objectDeclaration = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(!handler.canMove(arrayOf(objectDeclaration), null)) + } + + fun testLocalClass() = doTest { rootDir, handler -> + val klass = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(!handler.canMove(arrayOf(klass), null)) + } + + fun testLocalFun() = doTest { rootDir, handler -> + val function = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(!handler.canMove(arrayOf(function), null)) + } + + fun testLocalVal() = doTest { rootDir, handler -> + val property = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(!handler.canMove(arrayOf(property), null)) + } + + fun testMemberFun() = doTest { rootDir, handler -> + val function = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(!handler.canMove(arrayOf(function), null)) + } + + fun testMemberVal() = doTest { rootDir, handler -> + val property = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(!handler.canMove(arrayOf(property), null)) + } + + fun testNestedClass() = doTest { rootDir, handler -> + val klass = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(handler.canMove(arrayOf(klass), null)) + } + + fun testInnerClass() = doTest { rootDir, handler -> + val klass = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(handler.canMove(arrayOf(klass), null)) + } + + fun testTopLevelClass() = doTest { rootDir, handler -> + val klass = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(handler.canMove(arrayOf(klass), null)) + } + + fun testTopLevelFun() = doTest { rootDir, handler -> + val function = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(handler.canMove(arrayOf(function), null)) + } + + fun testTopLevelVal() = doTest { rootDir, handler -> + val property = getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!! + assert(handler.canMove(arrayOf(property), null)) + } + + fun testMultipleNestedClasses() = doTest { rootDir, handler -> + val classes = getElementsAtCarets(rootDir, "test.kt").map { it.getNonStrictParentOfType()!! } + assert(handler.canMove(classes.toTypedArray(), null)) + } + + fun testNestedAndTopLevelClass() = doTest { rootDir, handler -> + val classes = getElementsAtCarets(rootDir, "test.kt").map { it.getNonStrictParentOfType()!! } + assert(!handler.canMove(classes.toTypedArray(), null)) + } + + fun testMultipleTopLevelDeclarations() = doTest { rootDir, handler -> + val declarations = getElementsAtCarets(rootDir, "test.kt").map { it.getNonStrictParentOfType()!! } + assert(handler.canMove(declarations.toTypedArray(), null)) + } + + fun testMultipleTopLevelDeclarationsInDifferentFiles() = doTest { rootDir, handler -> + val declarations = listOf("test.kt", "test2.kt") + .flatMap { getElementsAtCarets(rootDir, it) } + .map { it.getNonStrictParentOfType()!! } + assert(handler.canMove(declarations.toTypedArray(), null)) + + val files = listOf("test.kt", "test2.kt").map { getPsiFile(rootDir, it) } + assert(handler.canMove(files.toTypedArray(), null)) + } + + fun testMultipleTopLevelDeclarationsInDifferentDirs() = doTest { rootDir, handler -> + val declarations = listOf("test1/test.kt", "test2/test2.kt") + .flatMap { getElementsAtCarets(rootDir, it) } + .map { it.getNonStrictParentOfType()!! } + assert(!handler.canMove(declarations.toTypedArray(), null)) + + val files = listOf("test1/test.kt", "test2/test2.kt").map { getPsiFile(rootDir, it) } + assert(!handler.canMove(files.toTypedArray(), null)) + } + + fun testFileAndTopLevelDeclarations() = doTest { rootDir, handler -> + val elements = getElementsAtCarets(rootDir, "test.kt").map { it.getNonStrictParentOfType()!! } + + getPsiFile(rootDir, "test2.kt") + assert(!handler.canMove(elements.toTypedArray(), null)) + } + + fun testCommonTargets() = doTest { rootDir, handler -> + val elementsToMove = arrayOf(getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!!) + + val targetPackage = JavaPsiFacade.getInstance(project).findPackage("pack")!! + assert(handler.canMove(elementsToMove, targetPackage)) + + val targetDirectory = getPsiDirectory(rootDir, "pack") + assert(handler.canMove(elementsToMove, targetDirectory)) + + val targetFile = getPsiFile(rootDir, "pack/test2.kt") + assert(handler.canMove(elementsToMove, targetFile)) + } + + fun testTopLevelClassToClass() = doTest { rootDir, handler -> + val elementsToMove = arrayOf(getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!!) + val targetFile = getPsiFile(rootDir, "test2.kt") as KtFile + + val topLevelTarget = targetFile.declarations.firstIsInstance() + assert(topLevelTarget.name == "B") + assert(!handler.canMove(elementsToMove, topLevelTarget)) + + val annotationTarget = targetFile.declarations.first { it.name == "Ann" } as KtClass + assert(!handler.canMove(elementsToMove, annotationTarget)) + + val nestedTarget = topLevelTarget.declarations.firstIsInstance() + assert(nestedTarget.name == "C") + assert(!handler.canMove(elementsToMove, nestedTarget)) + } + + fun testNestedClassToClass() = doTest { rootDir, handler -> + val elementsToMove = arrayOf(getElementAtCaret(rootDir, "test.kt").getNonStrictParentOfType()!!) + val targetFile = getPsiFile(rootDir, "test2.kt") as KtFile + + val topLevelTarget = targetFile.declarations.firstIsInstance() + assert(topLevelTarget.name == "B") + assert(handler.canMove(elementsToMove, topLevelTarget)) + + val annotationTarget = targetFile.declarations.first { it.name == "Ann" } as KtClass + assert(!handler.canMove(elementsToMove, annotationTarget)) + + val nestedTarget = topLevelTarget.declarations.firstIsInstance() + assert(nestedTarget.name == "C") + assert(handler.canMove(elementsToMove, nestedTarget)) + } +} \ No newline at end of file