Move: Force package name change when moving Java files
Package statement in Java file is updated too late when moving the entire containing directory, so we force it with intercepting MoveFileHandler implementation
This commit is contained in:
@@ -368,6 +368,9 @@
|
||||
implementation="org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsHandler"
|
||||
order="first,before kotlin.moveFilesOrDirectories"/>
|
||||
<moveFileHandler implementation="org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinFileHandler" />
|
||||
<moveFileHandler
|
||||
implementation="org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.FqNameFixingMoveJavaFileHandler"
|
||||
order="before java" />
|
||||
<refactoring.moveDirectoryWithClassesHelper
|
||||
implementation="org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.KotlinMoveDirectoryWithClassesHelper"
|
||||
order="first" />
|
||||
|
||||
+14
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.Ref
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import com.intellij.refactoring.move.MoveCallback
|
||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor
|
||||
import com.intellij.usageView.UsageInfo
|
||||
@@ -82,6 +83,17 @@ class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor (
|
||||
sourceFile.name = temporaryName
|
||||
}
|
||||
|
||||
private fun markShouldFixFqName(value: Boolean) {
|
||||
fun PsiElement.doMark(value: Boolean) {
|
||||
when (this) {
|
||||
is PsiJavaFile -> shouldFixFqName = value
|
||||
is PsiDirectory -> children.forEach { it.doMark(value) }
|
||||
}
|
||||
}
|
||||
|
||||
elementsToMove.forEach { it.doMark(value) }
|
||||
}
|
||||
|
||||
override fun performRefactoring(usages: Array<UsageInfo>) {
|
||||
val needTemporaryRename = targetFileName != null && targetDirectory.findFile(targetFileName) != null
|
||||
if (needTemporaryRename) {
|
||||
@@ -89,9 +101,11 @@ class MoveFilesWithDeclarationsProcessor @JvmOverloads constructor (
|
||||
}
|
||||
|
||||
try {
|
||||
markShouldFixFqName(true)
|
||||
super.performRefactoring(usages)
|
||||
}
|
||||
finally {
|
||||
markShouldFixFqName(false)
|
||||
if (needTemporaryRename) {
|
||||
(elementsToMove.single() as PsiFile).name = targetFileName!!
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.moveFilesOrDirectories
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.FileTypeUtils
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveJavaFileHandler
|
||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
|
||||
internal var PsiJavaFile.shouldFixFqName: Boolean by NotNullableUserDataProperty(Key.create("SHOULD_FIX_FQ_NAME"), false)
|
||||
|
||||
class FqNameFixingMoveJavaFileHandler : MoveFileHandler() {
|
||||
private val delegate = MoveJavaFileHandler()
|
||||
|
||||
override fun canProcessElement(element: PsiFile) =
|
||||
delegate.canProcessElement(element)
|
||||
|
||||
override fun findUsages(psiFile: PsiFile, newParent: PsiDirectory?, searchInComments: Boolean, searchInNonJavaFiles: Boolean) =
|
||||
delegate.findUsages(psiFile, newParent, searchInComments, searchInNonJavaFiles)
|
||||
|
||||
override fun prepareMovedFile(file: PsiFile, moveDestination: PsiDirectory, oldToNewMap: MutableMap<PsiElement, PsiElement>) {
|
||||
delegate.prepareMovedFile(file, moveDestination, oldToNewMap)
|
||||
if (file is PsiJavaFile && file.shouldFixFqName) {
|
||||
val newPackage = JavaDirectoryService.getInstance().getPackage(moveDestination) ?: return
|
||||
if (!FileTypeUtils.isInServerPageFile(file) && !PsiUtil.isModuleFile(file)) {
|
||||
file.packageName = newPackage.qualifiedName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateMovedFile(file: PsiFile) =
|
||||
delegate.updateMovedFile(file)
|
||||
|
||||
override fun retargetUsages(usageInfos: MutableList<UsageInfo>, oldToNewMap: MutableMap<PsiElement, PsiElement>) =
|
||||
delegate.retargetUsages(usageInfos, oldToNewMap)
|
||||
}
|
||||
+4
-4
@@ -123,16 +123,16 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
||||
}
|
||||
|
||||
override fun prepareMovedFile(file: PsiFile, moveDestination: PsiDirectory, oldToNewMap: MutableMap<PsiElement, PsiElement>) {
|
||||
if (file !is KtFile) return
|
||||
val moveProcessor = initMoveProcessor(file, moveDestination) ?: return
|
||||
val moveContext = MoveContext(file, moveProcessor)
|
||||
oldToNewMap[moveContext] = moveContext
|
||||
val packageNameInfo = file.getPackageNameInfo(moveDestination, true) ?: return
|
||||
file.packageDirective?.fqName = packageNameInfo.newContainer.fqName!!.quoteIfNeeded()
|
||||
}
|
||||
|
||||
override fun updateMovedFile(file: PsiFile) {
|
||||
if (file !is KtFile) return
|
||||
val newDirectory = file.parent ?: return
|
||||
val packageNameInfo = file.getPackageNameInfo(newDirectory, true) ?: return
|
||||
file.packageDirective?.fqName = packageNameInfo.newContainer.fqName!!.quoteIfNeeded()
|
||||
|
||||
}
|
||||
|
||||
override fun retargetUsages(usageInfos: List<UsageInfo>?, oldToNewMap: Map<PsiElement, PsiElement>) {
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package test;
|
||||
|
||||
public class Bar {
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test.pack
|
||||
|
||||
import test2.pack.A
|
||||
import test2.pack.J
|
||||
|
||||
class Foo {
|
||||
val a = A()
|
||||
val j = J()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package test2
|
||||
|
||||
import test.pack.Foo
|
||||
|
||||
val foo = Foo()
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package test2.pack;
|
||||
|
||||
import test.*;
|
||||
import test.pack.Foo;
|
||||
|
||||
public class J {
|
||||
A a = new A();
|
||||
B b = new B();
|
||||
C c = new C();
|
||||
Foo foo = new Foo();
|
||||
Bar bar = new Bar();
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package test2.pack
|
||||
|
||||
import test.Bar
|
||||
import test.pack.Foo
|
||||
|
||||
class A {
|
||||
val b = B()
|
||||
}
|
||||
|
||||
class B {
|
||||
val a = A()
|
||||
}
|
||||
|
||||
class C {
|
||||
internal val foo = Foo()
|
||||
internal val bar = Bar()
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package test;
|
||||
|
||||
public class Bar {
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package test.pack
|
||||
|
||||
class Foo {
|
||||
val a = A()
|
||||
val j = J()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package test
|
||||
|
||||
import test.pack.Foo
|
||||
|
||||
val foo = Foo()
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package test.pack;
|
||||
|
||||
import test.*;
|
||||
|
||||
public class J {
|
||||
A a = new A();
|
||||
B b = new B();
|
||||
C c = new C();
|
||||
Foo foo = new Foo();
|
||||
Bar bar = new Bar();
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package test.pack
|
||||
|
||||
import test.Bar
|
||||
|
||||
class A {
|
||||
val b = B()
|
||||
}
|
||||
|
||||
class B {
|
||||
val a = A()
|
||||
}
|
||||
|
||||
class C {
|
||||
internal val foo = Foo()
|
||||
internal val bar = Bar()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"filesToMove": ["test/FooUsage.kt", "test/pack"],
|
||||
"type": "MOVE_FILES_WITH_DECLARATIONS",
|
||||
"targetDirectory": "test2"
|
||||
}
|
||||
@@ -271,16 +271,17 @@ enum class MoveAction {
|
||||
MOVE_FILES_WITH_DECLARATIONS {
|
||||
override fun runRefactoring(rootDir: VirtualFile, mainFile: PsiFile, elementsAtCaret: List<PsiElement>, config: JsonObject) {
|
||||
val project = mainFile.project
|
||||
val psiFilesToMove = config.getAsJsonArray("filesToMove").map {
|
||||
rootDir.findFileByRelativePath(it.asString)!!.toPsiFile(project) as KtFile
|
||||
val elementsToMove = config.getAsJsonArray("filesToMove").map {
|
||||
val virtualFile = rootDir.findFileByRelativePath(it.asString)!!
|
||||
if (virtualFile.isDirectory) virtualFile.toPsiDirectory(project)!! else virtualFile.toPsiFile(project)!!
|
||||
}
|
||||
val targetDirPath = config.getString("targetDirectory")
|
||||
val targetDir = rootDir.findFileByRelativePath(targetDirPath)!!.toPsiDirectory(project)!!
|
||||
MoveFilesWithDeclarationsProcessor(
|
||||
project,
|
||||
psiFilesToMove,
|
||||
elementsToMove,
|
||||
targetDir,
|
||||
psiFilesToMove.singleOrNull()?.name,
|
||||
(elementsToMove.singleOrNull() as? KtFile)?.name,
|
||||
searchInComments = true,
|
||||
searchInNonJavaFiles = true,
|
||||
moveCallback = null
|
||||
|
||||
@@ -258,6 +258,12 @@ public class MoveTestGenerated extends AbstractMoveTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir.test")
|
||||
public void testKotlin_moveFile_moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir_MoveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir/moveFileAndDirWithJavaFileReferringToPackageFragementWithUnmatchedDir.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlin/moveFile/moveFileToFile/moveFileToFile.test")
|
||||
public void testKotlin_moveFile_moveFileToFile_MoveFileToFile() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveFile/moveFileToFile/moveFileToFile.test");
|
||||
|
||||
Reference in New Issue
Block a user