From 46fe7dc7a1768e3fc7cce8ba890b3528965be564 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 14 Aug 2015 14:25:36 +0300 Subject: [PATCH] Move Directory: Support Kotlin files #KT-8350 Fixed #KT-8351 Fixed --- idea/src/META-INF/plugin.xml | 3 + .../idea/refactoring/jetRefactoringUtil.kt | 16 +++ .../KotlinChangePackageRefactoring.kt | 2 +- .../KotlinMoveDirectoryWithClassesHelper.kt | 122 ++++++++++++++++++ .../MoveKotlinFileHandler.kt | 75 ++++++----- .../KotlinMoveTarget.kt | 9 +- ...MoveKotlinTopLevelDeclarationsProcessor.kt | 4 +- .../kotlin/idea/refactoring/move/moveUtils.kt | 7 +- .../move/kotlin/moveDirectory/after/p1/M.kt | 9 ++ .../kotlin/moveDirectory/after/p2/JJ.java | 9 ++ .../move/kotlin/moveDirectory/after/p2/L.kt | 9 ++ .../kotlin/moveDirectory/after/p2/p/J.java | 5 + .../move/kotlin/moveDirectory/after/p2/p/K.kt | 5 + .../move/kotlin/moveDirectory/before/p1/M.kt | 9 ++ .../kotlin/moveDirectory/before/p1/p/J.java | 5 + .../kotlin/moveDirectory/before/p1/p/K.kt | 5 + .../kotlin/moveDirectory/before/p2/JJ.java | 9 ++ .../move/kotlin/moveDirectory/before/p2/L.kt | 9 ++ .../kotlin/moveDirectory/moveDirectory.test | 6 + .../after/newPackage/{fun.kt => foo.kt} | 0 .../refactoring/move/AbstractJetMoveTest.kt | 11 ++ .../move/JetMoveTestGenerated.java | 6 + 22 files changed, 298 insertions(+), 37 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/after/p1/M.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/JJ.java create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/L.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/J.java create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/K.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/M.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/J.java create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/K.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/JJ.java create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/L.kt create mode 100644 idea/testData/refactoring/move/kotlin/moveDirectory/moveDirectory.test rename idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/moveOnlyFunctionToPackageUsedInJava/after/newPackage/{fun.kt => foo.kt} (100%) diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 984561b4f8a..7df0566acaf 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -286,6 +286,9 @@ implementation="org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsHandler" order="before kotlin.moveFilesOrDirectories"/> + diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt index 87d29ed4848..c1e7efe898a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/jetRefactoringUtil.kt @@ -22,6 +22,9 @@ import com.intellij.codeInsight.unwrap.UnwrapHandler import com.intellij.ide.util.PsiElementListCellRenderer import com.intellij.lang.java.JavaLanguage import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.command.CommandAdapter +import com.intellij.openapi.command.CommandEvent +import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.colors.EditorColors import com.intellij.openapi.editor.colors.EditorColorsManager @@ -111,6 +114,8 @@ public fun File.toPsiDirectory(project: Project): PsiDirectory? { public fun VirtualFile.toPsiFile(project: Project): PsiFile? = PsiManager.getInstance(project).findFile(this) +public fun VirtualFile.toPsiDirectory(project: Project): PsiDirectory? = PsiManager.getInstance(project).findDirectory(this) + public fun PsiElement.getUsageContext(): PsiElement { return when (this) { is JetElement -> PsiTreeUtil.getParentOfType(this, javaClass(), javaClass())!! @@ -645,4 +650,15 @@ public fun Project.runSynchronouslyWithProgress(progressTitle: String, var result: T? = null ProgressManager.getInstance().runProcessWithProgressSynchronously( { result = action() }, progressTitle, canBeCanceled, this) return result +} + +public fun invokeOnceOnCommandFinish(action: () -> Unit) { + val commandProcessor = CommandProcessor.getInstance() + val listener = object: CommandAdapter() { + override fun beforeCommandFinished(event: CommandEvent?) { + action() + commandProcessor.removeCommandListener(this) + } + } + commandProcessor.addCommandListener(listener) } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt index 6c6fee53952..1a038881afa 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/changePackage/KotlinChangePackageRefactoring.kt @@ -58,7 +58,7 @@ public class KotlinChangePackageRefactoring(val file: JetFile) { ) val declarationUsages = declarationProcessor.findUsages().toList() - val internalUsages = file.getInternalReferencesToUpdateOnPackageNameChange(PackageNameInfo(currentFqName, newFqName)) + val internalUsages = file.getInternalReferencesToUpdateOnPackageNameChange(PackageNameInfo(currentFqName, newFqName.toUnsafe())) project.executeWriteCommand("Change file's package to '${newFqName.asString()}'") { packageDirective.setFqName(newFqName) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt new file mode 100644 index 00000000000..bb42f9361e9 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/KotlinMoveDirectoryWithClassesHelper.kt @@ -0,0 +1,122 @@ +/* + * Copyright 2010-2015 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.moveFilesOrDirectories + +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiDirectory +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.refactoring.listeners.RefactoringElementListener +import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesHelper +import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil +import com.intellij.usageView.UsageInfo +import com.intellij.util.Function +import org.jetbrains.kotlin.idea.core.getPackage +import org.jetbrains.kotlin.idea.core.refactoring.invokeOnceOnCommandFinish +import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsProcessor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.JetFile +import java.util.ArrayList +import java.util.HashMap + +public class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() { + private class FileUsagesWrapper( + val psiFile: PsiFile, + val usages: List, + val moveDeclarationsProcessor: MoveKotlinTopLevelDeclarationsProcessor? + ) : UsageInfo(psiFile) + + private class MoveContext( + val newParent: PsiDirectory, + val internalUsages: MoveKotlinFileHandler.InternalUsagesWrapper, + val moveDeclarationsProcessor: MoveKotlinTopLevelDeclarationsProcessor? + ) + + private val fileHandler = MoveKotlinFileHandler() + + private var fileToMoveContext: MutableMap? = null + + private fun getOrCreateMoveContextMap(): MutableMap { + return fileToMoveContext + ?: HashMap().apply { + fileToMoveContext = this + invokeOnceOnCommandFinish { fileToMoveContext = null } + } + } + + override fun findUsages( + filesToMove: MutableCollection, + directoriesToMove: Array, + result: MutableCollection, + searchInComments: Boolean, + searchInNonJavaFiles: Boolean, + project: Project) { + filesToMove + .filterIsInstance() + .mapTo(result) { FileUsagesWrapper(it, fileHandler.findUsages(it, null, searchInComments, searchInNonJavaFiles), null) } + } + + override fun beforeMove(psiFile: PsiFile) { + + } + + // Actual move logic is implemented in postProcessUsages since usages are not available here + override fun move( + file: PsiFile, + moveDestination: PsiDirectory, + oldToNewElementsMapping: MutableMap, + movedFiles: MutableList, + listener: RefactoringElementListener? + ): Boolean { + if (file !is JetFile) return false + + val moveDeclarationsProcessor = fileHandler.initMoveProcessor(file, moveDestination) + val moveContextMap = getOrCreateMoveContextMap() + moveContextMap[file] = MoveContext(moveDestination, + fileHandler.findInternalUsages(file, moveDestination), + moveDeclarationsProcessor) + moveDestination.getPackage()?.let { newPackage -> file.packageDirective?.fqName = FqName(newPackage.qualifiedName) } + return true + } + + override fun afterMove(newElement: PsiElement) { + + } + + override fun postProcessUsages(usages: Array, newDirMapper: Function) { + val fileToMoveContext = fileToMoveContext ?: return + try { + val usagesToProcessAfterMove = ArrayList() + usages + .filterIsInstance() + .forEach body@ { + val file = it.psiFile + val moveContext = fileToMoveContext[file] ?: return@body + + MoveFilesOrDirectoriesUtil.doMoveFile(file, moveContext.newParent) + val movedFile = moveContext.newParent.findFile(file.name) ?: return@body + + usagesToProcessAfterMove += + FileUsagesWrapper(movedFile, it.usages + moveContext.internalUsages, moveContext.moveDeclarationsProcessor) + } + usagesToProcessAfterMove.forEach { fileHandler.retargetUsages(it.usages, it.moveDeclarationsProcessor!!) } + } + finally { + this.fileToMoveContext = null + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt index aaf5967b409..94e6b20a086 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveFilesOrDirectories/MoveKotlinFileHandler.kt @@ -26,22 +26,16 @@ import org.jetbrains.kotlin.idea.JetLanguage import org.jetbrains.kotlin.idea.codeInsight.shorten.runWithElementsToShortenIsEmptyIgnored import org.jetbrains.kotlin.idea.core.getPackage import org.jetbrains.kotlin.idea.core.packageMatchesDirectory -import org.jetbrains.kotlin.idea.refactoring.move.PackageNameInfo -import org.jetbrains.kotlin.idea.refactoring.move.getInternalReferencesToUpdateOnPackageNameChange -import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.DeferredJetFileKotlinMoveTarget -import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsOptions -import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsProcessor -import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.Mover -import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages -import org.jetbrains.kotlin.idea.refactoring.move.updatePackageDirective -import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.idea.refactoring.move.* +import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.* +import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.psi.JetFile import org.jetbrains.kotlin.psi.JetNamedDeclaration import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.util.* public class MoveKotlinFileHandler : MoveFileHandler() { - private class InternalUsagesWrapper(file: JetFile, val usages: List) : UsageInfo(file) + internal class InternalUsagesWrapper(file: JetFile, val usages: List) : UsageInfo(file) // This is special 'PsiElement' whose purpose is to wrap MoveKotlinTopLevelDeclarationsProcessor // so that it can be kept in the transition map @@ -52,33 +46,42 @@ public class MoveKotlinFileHandler : MoveFileHandler() { override fun toString() = "" } - private fun JetFile.getPackageNameInfo(newParent: PsiDirectory, clearUserData: Boolean): PackageNameInfo? { + private fun JetFile.getPackageNameInfo(newParent: PsiDirectory?, clearUserData: Boolean): PackageNameInfo? { val shouldUpdatePackageDirective = updatePackageDirective ?: packageMatchesDirectory() updatePackageDirective = if (clearUserData) null else shouldUpdatePackageDirective if (!shouldUpdatePackageDirective) return null - val newPackage = newParent.getPackage() ?: return null - val oldPackageName = getPackageFqName() - val newPackageName = FqName(newPackage.getQualifiedName()) - if (oldPackageName == newPackageName) return null + val oldPackageName = packageFqName + val newPackage = newParent?.getPackage() ?: return PackageNameInfo(oldPackageName, UNKNOWN_PACKAGE_FQ_NAME) + + val newPackageName = FqNameUnsafe(newPackage.qualifiedName) + if (oldPackageName.asString() == newPackageName.asString()) return null return PackageNameInfo(oldPackageName, newPackageName) } - private fun initMoveProcessor(psiFile: PsiFile, newParent: PsiDirectory): MoveKotlinTopLevelDeclarationsProcessor? { + fun initMoveProcessor(psiFile: PsiFile, newParent: PsiDirectory?): MoveKotlinTopLevelDeclarationsProcessor? { if (psiFile !is JetFile) return null val packageNameInfo = psiFile.getPackageNameInfo(newParent, false) ?: return null - val project = psiFile.getProject() + val project = psiFile.project + + val newPackageName = packageNameInfo.newPackageName + val moveTarget = when (newPackageName) { + UNKNOWN_PACKAGE_FQ_NAME -> EmptyKotlinMoveTarget + + else -> DeferredJetFileKotlinMoveTarget(project, newPackageName.toSafe()) { + MoveFilesOrDirectoriesUtil.doMoveFile(psiFile, newParent) + newParent?.findFile(psiFile.name) as? JetFile + } + } + val declarationMoveProcessor = MoveKotlinTopLevelDeclarationsProcessor( project, MoveKotlinTopLevelDeclarationsOptions( - elementsToMove = psiFile.getDeclarations().filterIsInstance(), - moveTarget = DeferredJetFileKotlinMoveTarget(project, packageNameInfo.newPackageName) { - MoveFilesOrDirectoriesUtil.doMoveFile(psiFile, newParent) - newParent.findFile(psiFile.getName()) as? JetFile - }, + elementsToMove = psiFile.declarations.filterIsInstance(), + moveTarget = moveTarget, updateInternalReferences = false ), Mover.Idle @@ -91,9 +94,15 @@ public class MoveKotlinFileHandler : MoveFileHandler() { return !JavaProjectRootsUtil.isOutsideJavaSourceRoot(element) } + fun findInternalUsages(file: JetFile, newParent: PsiDirectory): InternalUsagesWrapper { + val packageNameInfo = file.getPackageNameInfo(newParent, false) + val usages = packageNameInfo?.let { file.getInternalReferencesToUpdateOnPackageNameChange(it) } ?: emptyList() + return InternalUsagesWrapper(file, usages) + } + override fun findUsages( psiFile: PsiFile, - newParent: PsiDirectory, + newParent: PsiDirectory?, searchInComments: Boolean, searchInNonJavaFiles: Boolean ): List { @@ -101,10 +110,7 @@ public class MoveKotlinFileHandler : MoveFileHandler() { val usages = ArrayList() initMoveProcessor(psiFile, newParent)?.findUsages()?.let { usages += it } - val packageNameInfo = psiFile.getPackageNameInfo(newParent, false) - if (packageNameInfo != null) { - usages += InternalUsagesWrapper(psiFile, psiFile.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo)) - } + newParent?.let { usages += findInternalUsages(psiFile, it) } return usages } @@ -118,15 +124,20 @@ public class MoveKotlinFileHandler : MoveFileHandler() { if (file !is JetFile) return val newDirectory = file.parent ?: return val packageNameInfo = file.getPackageNameInfo(newDirectory, true) ?: return - file.packageDirective?.fqName = packageNameInfo.newPackageName + val newPackageName = packageNameInfo.newPackageName + assert(newPackageName.isSafe, newPackageName) + file.packageDirective?.fqName = newPackageName.toSafe() } override fun retargetUsages(usageInfos: List?, oldToNewMap: Map) { - postProcessMoveUsages(usageInfos?.firstIsInstanceOrNull()?.usages ?: emptyList()) val moveContext = oldToNewMap.keySet().firstIsInstanceOrNull() ?: return - val processor = moveContext.declarationMoveProcessor - processor.project.runWithElementsToShortenIsEmptyIgnored { - usageInfos?.let { processor.execute(it) } + retargetUsages(usageInfos, moveContext.declarationMoveProcessor) + } + + fun retargetUsages(usageInfos: List?, moveDeclarationsProcessor: MoveKotlinTopLevelDeclarationsProcessor) { + postProcessMoveUsages(usageInfos?.firstIsInstanceOrNull()?.usages ?: emptyList()) + moveDeclarationsProcessor.project.runWithElementsToShortenIsEmptyIgnored { + usageInfos?.let { moveDeclarationsProcessor.execute(it) } } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt index 6b86afe3f07..91d9f9148f5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/KotlinMoveTarget.kt @@ -23,7 +23,7 @@ import com.intellij.psi.PsiManager import com.intellij.refactoring.PackageWrapper import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetFile -import java.util.* +import java.util.HashMap public interface KotlinMoveTarget { val packageWrapper: PackageWrapper? @@ -34,6 +34,13 @@ public interface KotlinMoveTarget { fun verify(file: PsiFile): String? } +public object EmptyKotlinMoveTarget: KotlinMoveTarget { + override val packageWrapper: PackageWrapper? get() = null + override fun getOrCreateTargetPsi(originalPsi: PsiElement) = null + override fun getTargetPsiIfExists(originalPsi: PsiElement) = null + override fun verify(file: PsiFile) = null +} + public class JetFileKotlinMoveTarget(val targetFile: JetFile): KotlinMoveTarget { override val packageWrapper: PackageWrapper? = targetFile.getPackageFqName().asString().let { packageName -> PackageWrapper(PsiManager.getInstance(targetFile.getProject()), packageName) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt index af127ff00f2..0e32fc802f7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveTopLevelDeclarations/MoveKotlinTopLevelDeclarationsProcessor.kt @@ -184,6 +184,8 @@ public class MoveKotlinTopLevelDeclarationsProcessor( } fun collectConflictsInDeclarations() { + if (newPackageName == UNKNOWN_PACKAGE_FQ_NAME.asString()) return + val declarationToReferenceTargets = HashMap>() for (declaration in elementsToMove) { val referenceToContext = JetFileReferencesResolver.resolve(element = declaration, resolveQualifiers = false) @@ -251,7 +253,7 @@ public class MoveKotlinTopLevelDeclarationsProcessor( ?: throw AssertionError("Couldn't create Kotlin file for: ${declaration.javaClass}: ${declaration.getText()}") if (options.updateInternalReferences) { - val packageNameInfo = PackageNameInfo(file!!.getPackageFqName(), targetFile.getPackageFqName()) + val packageNameInfo = PackageNameInfo(file!!.getPackageFqName(), targetFile.getPackageFqName().toUnsafe()) val (usagesToProcessLater, usagesToProcessNow) = declaration .getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo) .partition { it is MoveRenameUsageInfoForExtension } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt index 989192a5554..ed22e10c1db 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt @@ -56,6 +56,7 @@ import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.BindingContext @@ -65,7 +66,9 @@ import java.util.ArrayList import java.util.Collections import java.util.Comparator -public class PackageNameInfo(val oldPackageName: FqName, val newPackageName: FqName) +val UNKNOWN_PACKAGE_FQ_NAME = FqNameUnsafe("org.jetbrains.kotlin.idea.refactoring.move.") + +public class PackageNameInfo(val oldPackageName: FqName, val newPackageName: FqNameUnsafe) public fun JetElement.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo: PackageNameInfo): List { val file = getContainingFile() as? JetFile ?: return listOf() @@ -113,7 +116,7 @@ public fun JetElement.getInternalReferencesToUpdateOnPackageNameChange(packageNa return when { isExtension, packageName == packageNameInfo.oldPackageName, - packageName == packageNameInfo.newPackageName, + packageName?.asString() == packageNameInfo.newPackageName.asString(), isImported(descriptor) -> { createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false) } diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/after/p1/M.kt b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p1/M.kt new file mode 100644 index 00000000000..3c69dd88067 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p1/M.kt @@ -0,0 +1,9 @@ +package p1 + +import p2.p.J +import p2.p.K + +public class M { + val j = J() + val k = K() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/JJ.java b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/JJ.java new file mode 100644 index 00000000000..03f5a790e2e --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/JJ.java @@ -0,0 +1,9 @@ +package p2; + +import p2.p.K; +import p1.M; + +public class JJ { + K k = new K(); + M m = new M(); +} diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/L.kt b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/L.kt new file mode 100644 index 00000000000..98811e1cb51 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/L.kt @@ -0,0 +1,9 @@ +package p2 + +import p1.M +import p2.p.K + +public class L { + private val k = K() + private val m = M() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/J.java b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/J.java new file mode 100644 index 00000000000..95a08234eeb --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/J.java @@ -0,0 +1,5 @@ +package p2.p; + +public class J { + K k = new K(); +} diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/K.kt b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/K.kt new file mode 100644 index 00000000000..e54063ab680 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/after/p2/p/K.kt @@ -0,0 +1,5 @@ +package p2.p + +public class K { + val j = J() +} diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/M.kt b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/M.kt new file mode 100644 index 00000000000..66a8664626d --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/M.kt @@ -0,0 +1,9 @@ +package p1 + +import p1.p.J +import p1.p.K + +public class M { + val j = J() + val k = K() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/J.java b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/J.java new file mode 100644 index 00000000000..8560850b26b --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/J.java @@ -0,0 +1,5 @@ +package p1.p; + +public class J { + K k = new K(); +} diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/K.kt b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/K.kt new file mode 100644 index 00000000000..a66e6c6a8e5 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p1/p/K.kt @@ -0,0 +1,5 @@ +package p1.p + +public class K { + val j = J() +} diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/JJ.java b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/JJ.java new file mode 100644 index 00000000000..18ce461dd21 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/JJ.java @@ -0,0 +1,9 @@ +package p2; + +import p1.p.K; +import p1.M; + +public class JJ { + K k = new K(); + M m = new M(); +} diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/L.kt b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/L.kt new file mode 100644 index 00000000000..74bbe084f00 --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/before/p2/L.kt @@ -0,0 +1,9 @@ +package p2 + +import p1.M +import p1.p.K + +public class L { + private val k = K() + private val m = M() +} \ No newline at end of file diff --git a/idea/testData/refactoring/move/kotlin/moveDirectory/moveDirectory.test b/idea/testData/refactoring/move/kotlin/moveDirectory/moveDirectory.test new file mode 100644 index 00000000000..db0f92879ba --- /dev/null +++ b/idea/testData/refactoring/move/kotlin/moveDirectory/moveDirectory.test @@ -0,0 +1,6 @@ +{ + "mainFile": "p1/M.kt", + "type": "MOVE_DIRECTORY_WITH_CLASSES", + "sourceDir": "p1/p", + "targetDir": "p2" +} diff --git a/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/moveOnlyFunctionToPackageUsedInJava/after/newPackage/fun.kt b/idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/moveOnlyFunctionToPackageUsedInJava/after/newPackage/foo.kt similarity index 100% rename from idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/moveOnlyFunctionToPackageUsedInJava/after/newPackage/fun.kt rename to idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/moveOnlyFunctionToPackageUsedInJava/after/newPackage/foo.kt diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractJetMoveTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractJetMoveTest.kt index b4e9cca6a67..4628cdd8114 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractJetMoveTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/AbstractJetMoveTest.kt @@ -30,6 +30,7 @@ import com.intellij.refactoring.PackageWrapper import com.intellij.refactoring.move.MoveHandler import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassToInnerProcessor import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor +import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesProcessor import com.intellij.refactoring.move.moveClassesOrPackages.MultipleRootsMoveDestination import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor import com.intellij.refactoring.move.moveInner.MoveInnerProcessor @@ -37,6 +38,7 @@ import com.intellij.refactoring.move.moveMembers.MockMoveMembersOptions import com.intellij.refactoring.move.moveMembers.MoveMembersProcessor import com.intellij.util.ActionRunner import org.jetbrains.kotlin.idea.core.refactoring.createKotlinFile +import org.jetbrains.kotlin.idea.core.refactoring.toPsiDirectory import org.jetbrains.kotlin.idea.jsonUtils.getNullableString import org.jetbrains.kotlin.idea.jsonUtils.getString import org.jetbrains.kotlin.idea.refactoring.move.changePackage.KotlinChangePackageRefactoring @@ -264,6 +266,15 @@ enum class MoveAction { override fun runRefactoring(rootDir: VirtualFile, mainFile: PsiFile, elementAtCaret: PsiElement?, config: JsonObject) { KotlinChangePackageRefactoring(mainFile as JetFile).run(FqName(config.getString("newPackageName"))) } + }, + + MOVE_DIRECTORY_WITH_CLASSES { + override fun runRefactoring(rootDir: VirtualFile, mainFile: PsiFile, elementAtCaret: PsiElement?, config: JsonObject) { + val project = mainFile.project + val sourceDir = rootDir.findFileByRelativePath(config.getString("sourceDir"))!!.toPsiDirectory(project)!! + val targetDir = rootDir.findFileByRelativePath(config.getString("targetDir"))!!.toPsiDirectory(project)!! + MoveDirectoryWithClassesProcessor(project, arrayOf(sourceDir), targetDir, true, true, true, {}).run() + } }; abstract fun runRefactoring(rootDir: VirtualFile, mainFile: PsiFile, elementAtCaret: PsiElement?, config: JsonObject) diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/JetMoveTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/JetMoveTestGenerated.java index fd95c3901cd..14e005c3043 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/JetMoveTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/move/JetMoveTestGenerated.java @@ -227,6 +227,12 @@ public class JetMoveTestGenerated extends AbstractJetMoveTest { doTest(fileName); } + @TestMetadata("kotlin/moveDirectory/moveDirectory.test") + public void testKotlin_moveDirectory_MoveDirectory() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveDirectory/moveDirectory.test"); + doTest(fileName); + } + @TestMetadata("kotlin/moveFile/addExtensionImport/addExtensionImport.test") public void testKotlin_moveFile_addExtensionImport_AddExtensionImport() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/addExtensionImport/addExtensionImport.test");