Move: Warn about accessibility conflicts due to moving to unrelated module
#KT-13174 Fixed
This commit is contained in:
@@ -264,6 +264,7 @@ Using 'this' as function argument in constructor of non-final class
|
|||||||
- [`KT-13254`](https://youtrack.jetbrains.com/issue/KT-13254) Rename: Conflict detection for type parameters
|
- [`KT-13254`](https://youtrack.jetbrains.com/issue/KT-13254) Rename: Conflict detection for type parameters
|
||||||
- [`KT-13282`](https://youtrack.jetbrains.com/issue/KT-13282), [`KT-13283`](https://youtrack.jetbrains.com/issue/KT-13283) Rename: Fix name quoting for automatic renamers
|
- [`KT-13282`](https://youtrack.jetbrains.com/issue/KT-13282), [`KT-13283`](https://youtrack.jetbrains.com/issue/KT-13283) Rename: Fix name quoting for automatic renamers
|
||||||
- [`KT-13239`](https://youtrack.jetbrains.com/issue/KT-13239) Rename: Warn about function name conflicts
|
- [`KT-13239`](https://youtrack.jetbrains.com/issue/KT-13239) Rename: Warn about function name conflicts
|
||||||
|
- [`KT-13174`](https://youtrack.jetbrains.com/issue/KT-13174) Move: Warn about accessibility conflicts due to moving to unrelated module
|
||||||
|
|
||||||
##### New features
|
##### New features
|
||||||
|
|
||||||
|
|||||||
+3
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.refactoring.move.changePackage
|
package org.jetbrains.kotlin.idea.refactoring.move.changePackage
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.PsiDirectory
|
import com.intellij.psi.PsiDirectory
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
@@ -47,6 +48,8 @@ class KotlinChangePackageRefactoring(val file: KtFile) {
|
|||||||
|
|
||||||
override val directory: PsiDirectory = file.containingDirectory!!
|
override val directory: PsiDirectory = file.containingDirectory!!
|
||||||
|
|
||||||
|
override val targetFile: VirtualFile? = directory.virtualFile
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile
|
||||||
|
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||||
|
|||||||
+10
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.PsiDirectory
|
import com.intellij.psi.PsiDirectory
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
@@ -30,6 +31,8 @@ import java.util.*
|
|||||||
|
|
||||||
interface KotlinMoveTarget {
|
interface KotlinMoveTarget {
|
||||||
val targetContainerFqName: FqName?
|
val targetContainerFqName: FqName?
|
||||||
|
val targetFile: VirtualFile?
|
||||||
|
|
||||||
fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement?
|
fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement?
|
||||||
fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement?
|
fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement?
|
||||||
|
|
||||||
@@ -43,6 +46,8 @@ interface KotlinDirectoryBasedMoveTarget : KotlinMoveTarget {
|
|||||||
|
|
||||||
object EmptyKotlinMoveTarget: KotlinMoveTarget {
|
object EmptyKotlinMoveTarget: KotlinMoveTarget {
|
||||||
override val targetContainerFqName = null
|
override val targetContainerFqName = null
|
||||||
|
override val targetFile = null
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = null
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = null
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||||
override fun verify(file: PsiFile) = null
|
override fun verify(file: PsiFile) = null
|
||||||
@@ -51,6 +56,8 @@ object EmptyKotlinMoveTarget: KotlinMoveTarget {
|
|||||||
class KotlinMoveTargetForExistingElement(val targetElement: KtElement): KotlinMoveTarget {
|
class KotlinMoveTargetForExistingElement(val targetElement: KtElement): KotlinMoveTarget {
|
||||||
override val targetContainerFqName = targetElement.getContainingKtFile().packageFqName
|
override val targetContainerFqName = targetElement.getContainingKtFile().packageFqName
|
||||||
|
|
||||||
|
override val targetFile: VirtualFile? = targetElement.getContainingKtFile().virtualFile
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetElement
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetElement
|
||||||
|
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetElement
|
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetElement
|
||||||
@@ -63,6 +70,8 @@ class KotlinMoveTargetForCompanion(val targetClass: KtClass): KotlinMoveTarget {
|
|||||||
override val targetContainerFqName = targetClass.getCompanionObjects().firstOrNull()?.fqName
|
override val targetContainerFqName = targetClass.getCompanionObjects().firstOrNull()?.fqName
|
||||||
?: targetClass.fqName!!.child(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
|
?: targetClass.fqName!!.child(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
|
||||||
|
|
||||||
|
override val targetFile: VirtualFile? = targetClass.getContainingKtFile().virtualFile
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetClass.getOrCreateCompanionObject()
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetClass.getOrCreateCompanionObject()
|
||||||
|
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetClass.getCompanionObjects().firstOrNull()
|
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetClass.getCompanionObjects().firstOrNull()
|
||||||
@@ -74,6 +83,7 @@ class KotlinMoveTargetForCompanion(val targetClass: KtClass): KotlinMoveTarget {
|
|||||||
class KotlinMoveTargetForDeferredFile(
|
class KotlinMoveTargetForDeferredFile(
|
||||||
override val targetContainerFqName: FqName,
|
override val targetContainerFqName: FqName,
|
||||||
override val directory: PsiDirectory?,
|
override val directory: PsiDirectory?,
|
||||||
|
override val targetFile: VirtualFile? = directory?.virtualFile,
|
||||||
private val createFile: (KtFile) -> KtFile?
|
private val createFile: (KtFile) -> KtFile?
|
||||||
): KotlinDirectoryBasedMoveTarget {
|
): KotlinDirectoryBasedMoveTarget {
|
||||||
private val createdFiles = HashMap<KtFile, KtFile?>()
|
private val createdFiles = HashMap<KtFile, KtFile?>()
|
||||||
|
|||||||
+1
-1
@@ -90,7 +90,7 @@ class MoveDeclarationToSeparateFileIntention :
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory) {
|
val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory, null) {
|
||||||
createKotlinFile(targetFileName, directory, packageName.asString())
|
createKotlinFile(targetFileName, directory, packageName.asString())
|
||||||
}
|
}
|
||||||
val moveOptions = MoveDeclarationsDescriptor(
|
val moveOptions = MoveDeclarationsDescriptor(
|
||||||
|
|||||||
+42
-12
@@ -22,20 +22,16 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.openapi.roots.ModuleRootManager
|
import com.intellij.openapi.roots.ModuleRootManager
|
||||||
import com.intellij.openapi.util.Ref
|
import com.intellij.openapi.util.Ref
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.PsiMember
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.PsiNamedElement
|
|
||||||
import com.intellij.psi.PsiReference
|
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
import com.intellij.refactoring.BaseRefactoringProcessor
|
import com.intellij.refactoring.BaseRefactoringProcessor
|
||||||
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
import com.intellij.refactoring.move.MoveCallback
|
import com.intellij.refactoring.move.MoveCallback
|
||||||
import com.intellij.refactoring.move.MoveMultipleElementsViewDescriptor
|
import com.intellij.refactoring.move.MoveMultipleElementsViewDescriptor
|
||||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler
|
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler
|
||||||
import com.intellij.refactoring.rename.RenameUtil
|
import com.intellij.refactoring.rename.RenameUtil
|
||||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
import com.intellij.refactoring.util.*
|
||||||
import com.intellij.refactoring.util.NonCodeUsageInfo
|
|
||||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
|
||||||
import com.intellij.refactoring.util.TextOccurrencesUtil
|
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import com.intellij.usageView.UsageViewBundle
|
import com.intellij.usageView.UsageViewBundle
|
||||||
import com.intellij.usageView.UsageViewDescriptor
|
import com.intellij.usageView.UsageViewDescriptor
|
||||||
@@ -48,6 +44,7 @@ import gnu.trove.TObjectHashingStrategy
|
|||||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||||
import org.jetbrains.kotlin.asJava.toLightElements
|
import org.jetbrains.kotlin.asJava.toLightElements
|
||||||
|
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||||
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||||
@@ -64,13 +61,11 @@ import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages
|
|||||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
|
||||||
import org.jetbrains.kotlin.idea.search.projectScope
|
import org.jetbrains.kotlin.idea.search.projectScope
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isInsideOf
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||||
|
import org.jetbrains.kotlin.utils.SmartSet
|
||||||
import org.jetbrains.kotlin.utils.keysToMap
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -253,6 +248,39 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
|
|
||||||
fun render(declaration: PsiElement) = RefactoringUIUtil.getDescription(declaration, false)
|
fun render(declaration: PsiElement) = RefactoringUIUtil.getDescription(declaration, false)
|
||||||
|
|
||||||
|
fun checkModuleConflictsInUsages(usages: List<UsageInfo>) {
|
||||||
|
val sourceRoot = descriptor.moveTarget.targetFile ?: return
|
||||||
|
RefactoringConflictsUtil.analyzeModuleConflicts(project, elementsToMove, usages.toTypedArray(), sourceRoot, conflicts)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkModuleConflictsInDeclarations() {
|
||||||
|
val sourceRoot = descriptor.moveTarget.targetFile ?: return
|
||||||
|
val targetModule = ModuleUtilCore.findModuleForFile(sourceRoot, project) ?: return
|
||||||
|
val resolveScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(targetModule)
|
||||||
|
for (declaration in elementsToMove) {
|
||||||
|
declaration.forEachDescendantOfType<KtReferenceExpression> { refExpr ->
|
||||||
|
refExpr.references
|
||||||
|
.forEach { ref ->
|
||||||
|
val target = ref.resolve() ?: return@forEach
|
||||||
|
if (target.isInsideOf(elementsToMove)) return@forEach
|
||||||
|
if (target in resolveScope) return@forEach
|
||||||
|
|
||||||
|
val superMethods = SmartSet.create<PsiMethod>()
|
||||||
|
target.toLightMethods().forEach { superMethods += it.findDeepestSuperMethods() }
|
||||||
|
if (superMethods.any { it in resolveScope }) return@forEach
|
||||||
|
|
||||||
|
val refContainer = ref.element.getStrictParentOfType<KtNamedDeclaration>() ?: return@forEach
|
||||||
|
val scopeDescription = RefactoringUIUtil.getDescription(refContainer, true)
|
||||||
|
val message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.in.module.2",
|
||||||
|
RefactoringUIUtil.getDescription(target, true),
|
||||||
|
scopeDescription,
|
||||||
|
CommonRefactoringUtil.htmlEmphasize(targetModule.name))
|
||||||
|
conflicts.putValue(target, CommonRefactoringUtil.capitalize(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun checkVisibilityInUsages(usages: List<UsageInfo>) {
|
fun checkVisibilityInUsages(usages: List<UsageInfo>) {
|
||||||
val declarationToContainers = HashMap<KtNamedDeclaration, MutableSet<PsiElement>>()
|
val declarationToContainers = HashMap<KtNamedDeclaration, MutableSet<PsiElement>>()
|
||||||
for (usage in usages) {
|
for (usage in usages) {
|
||||||
@@ -319,6 +347,8 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
|
|
||||||
usages += descriptor.delegate.findUsages(descriptor)
|
usages += descriptor.delegate.findUsages(descriptor)
|
||||||
collectUsages(kotlinToLightElements, usages)
|
collectUsages(kotlinToLightElements, usages)
|
||||||
|
checkModuleConflictsInUsages(usages)
|
||||||
|
checkModuleConflictsInDeclarations()
|
||||||
checkVisibilityInUsages(usages)
|
checkVisibilityInUsages(usages)
|
||||||
checkVisibilityInDeclarations()
|
checkVisibilityInDeclarations()
|
||||||
descriptor.delegate.collectConflicts(descriptor, usages, conflicts)
|
descriptor.delegate.collectConflicts(descriptor, usages, conflicts)
|
||||||
|
|||||||
+1
@@ -375,6 +375,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
moveTarget = new KotlinMoveTargetForDeferredFile(
|
moveTarget = new KotlinMoveTargetForDeferredFile(
|
||||||
targetPackageFqName,
|
targetPackageFqName,
|
||||||
targetDir,
|
targetDir,
|
||||||
|
null,
|
||||||
new Function1<KtFile, KtFile>() {
|
new Function1<KtFile, KtFile>() {
|
||||||
@Override
|
@Override
|
||||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
public KtFile invoke(@NotNull KtFile originalFile) {
|
||||||
|
|||||||
+33
-6
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
||||||
|
|
||||||
|
import com.intellij.ide.util.DirectoryChooser;
|
||||||
import com.intellij.openapi.editor.Document;
|
import com.intellij.openapi.editor.Document;
|
||||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||||
@@ -25,9 +26,12 @@ import com.intellij.openapi.project.Project;
|
|||||||
import com.intellij.openapi.roots.JavaProjectRootsUtil;
|
import com.intellij.openapi.roots.JavaProjectRootsUtil;
|
||||||
import com.intellij.openapi.ui.Messages;
|
import com.intellij.openapi.ui.Messages;
|
||||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||||
|
import com.intellij.openapi.util.Comparing;
|
||||||
import com.intellij.openapi.util.EmptyRunnable;
|
import com.intellij.openapi.util.EmptyRunnable;
|
||||||
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.openapi.util.Pass;
|
import com.intellij.openapi.util.Pass;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.refactoring.JavaRefactoringSettings;
|
import com.intellij.refactoring.JavaRefactoringSettings;
|
||||||
import com.intellij.refactoring.MoveDestination;
|
import com.intellij.refactoring.MoveDestination;
|
||||||
@@ -38,7 +42,10 @@ import com.intellij.refactoring.classMembers.MemberInfoChange;
|
|||||||
import com.intellij.refactoring.classMembers.MemberInfoChangeListener;
|
import com.intellij.refactoring.classMembers.MemberInfoChangeListener;
|
||||||
import com.intellij.refactoring.move.MoveCallback;
|
import com.intellij.refactoring.move.MoveCallback;
|
||||||
import com.intellij.refactoring.move.MoveHandler;
|
import com.intellij.refactoring.move.MoveHandler;
|
||||||
|
import com.intellij.refactoring.move.moveClassesOrPackages.AutocreatingSingleSourceRootMoveDestination;
|
||||||
import com.intellij.refactoring.move.moveClassesOrPackages.DestinationFolderComboBox;
|
import com.intellij.refactoring.move.moveClassesOrPackages.DestinationFolderComboBox;
|
||||||
|
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesUtil;
|
||||||
|
import com.intellij.refactoring.move.moveClassesOrPackages.MultipleRootsMoveDestination;
|
||||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor;
|
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor;
|
||||||
import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo;
|
import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo;
|
||||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||||
@@ -59,8 +66,8 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType;
|
import org.jetbrains.kotlin.idea.KotlinFileType;
|
||||||
import org.jetbrains.kotlin.idea.core.PackageUtilsKt;
|
import org.jetbrains.kotlin.idea.core.PackageUtilsKt;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtilKt;
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle;
|
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle;
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtilKt;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
||||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
||||||
@@ -103,6 +110,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
private KotlinMemberSelectionTable memberTable;
|
private KotlinMemberSelectionTable memberTable;
|
||||||
|
|
||||||
private final MoveCallback moveCallback;
|
private final MoveCallback moveCallback;
|
||||||
|
private final PsiDirectory initialTargetDirectory;
|
||||||
|
|
||||||
public MoveKotlinTopLevelDeclarationsDialog(
|
public MoveKotlinTopLevelDeclarationsDialog(
|
||||||
@NotNull Project project,
|
@NotNull Project project,
|
||||||
@@ -120,6 +128,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
List<KtFile> sourceFiles = getSourceFiles(elementsToMove);
|
List<KtFile> sourceFiles = getSourceFiles(elementsToMove);
|
||||||
|
|
||||||
this.moveCallback = moveCallback;
|
this.moveCallback = moveCallback;
|
||||||
|
this.initialTargetDirectory = targetDirectory;
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
@@ -440,7 +449,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MoveDestination selectPackageBasedMoveDestination(boolean askIfDoesNotExist) {
|
private Pair<VirtualFile, ? extends MoveDestination> selectPackageBasedTargetDirAndDestination(boolean askIfDoesNotExist) {
|
||||||
String packageName = getTargetPackage();
|
String packageName = getTargetPackage();
|
||||||
|
|
||||||
RecentsManager.getInstance(myProject).registerRecentEntry(RECENTS_KEY, packageName);
|
RecentsManager.getInstance(myProject).registerRecentEntry(RECENTS_KEY, packageName);
|
||||||
@@ -451,7 +460,18 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
if (ret != Messages.YES) return null;
|
if (ret != Messages.YES) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((DestinationFolderComboBox) destinationFolderCB).selectDirectory(targetPackage, false);
|
DirectoryChooser.ItemWrapper selectedItem = (DirectoryChooser.ItemWrapper)destinationFolderCB.getComboBox().getSelectedItem();
|
||||||
|
PsiDirectory selectedPsiDirectory = selectedItem.getDirectory();
|
||||||
|
if (selectedPsiDirectory == null) return Pair.create(null, new MultipleRootsMoveDestination(targetPackage));
|
||||||
|
|
||||||
|
VirtualFile targetDirectory = selectedPsiDirectory.getVirtualFile();
|
||||||
|
List<VirtualFile> sourceRoots = JavaProjectRootsUtil.getSuitableDestinationSourceRoots(getProject());
|
||||||
|
if (initialTargetDirectory != null && Comparing.equal(targetDirectory, initialTargetDirectory.getVirtualFile()) &&
|
||||||
|
sourceRoots.size() > 1) {
|
||||||
|
targetDirectory = MoveClassesOrPackagesUtil.chooseSourceRoot(targetPackage, sourceRoots, initialTargetDirectory);
|
||||||
|
}
|
||||||
|
if (targetDirectory == null) return null;
|
||||||
|
return Pair.create(targetDirectory, new AutocreatingSingleSourceRootMoveDestination(targetPackage, targetDirectory));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkTargetFileName(String fileName) {
|
private boolean checkTargetFileName(String fileName) {
|
||||||
@@ -508,8 +528,11 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
PsiDirectory sourceDirectory = getSourceDirectory(sourceFiles);
|
PsiDirectory sourceDirectory = getSourceDirectory(sourceFiles);
|
||||||
|
|
||||||
if (isMoveToPackage()) {
|
if (isMoveToPackage()) {
|
||||||
final MoveDestination moveDestination = selectPackageBasedMoveDestination(true);
|
Pair<VirtualFile, ? extends MoveDestination> targetDirWithMoveDestination = selectPackageBasedTargetDirAndDestination(true);
|
||||||
if (moveDestination == null) return null;
|
if (targetDirWithMoveDestination == null) return null;
|
||||||
|
|
||||||
|
VirtualFile targetDir = targetDirWithMoveDestination.getFirst();
|
||||||
|
final MoveDestination moveDestination = targetDirWithMoveDestination.getSecond();
|
||||||
|
|
||||||
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||||
if (targetFileName != null && !checkTargetFileName(targetFileName)) return null;
|
if (targetFileName != null && !checkTargetFileName(targetFileName)) return null;
|
||||||
@@ -555,6 +578,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
return new KotlinMoveTargetForDeferredFile(
|
return new KotlinMoveTargetForDeferredFile(
|
||||||
new FqName(getTargetPackage()),
|
new FqName(getTargetPackage()),
|
||||||
moveDestination.getTargetIfExists(sourceFiles.get(0)),
|
moveDestination.getTargetIfExists(sourceFiles.get(0)),
|
||||||
|
targetDir,
|
||||||
new Function1<KtFile, KtFile>() {
|
new Function1<KtFile, KtFile>() {
|
||||||
@Override
|
@Override
|
||||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
public KtFile invoke(@NotNull KtFile originalFile) {
|
||||||
@@ -610,6 +634,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
return new KotlinMoveTargetForDeferredFile(
|
return new KotlinMoveTargetForDeferredFile(
|
||||||
targetPackageFqName,
|
targetPackageFqName,
|
||||||
psiDirectory,
|
psiDirectory,
|
||||||
|
null,
|
||||||
new Function1<KtFile, KtFile>() {
|
new Function1<KtFile, KtFile>() {
|
||||||
@Override
|
@Override
|
||||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
public KtFile invoke(@NotNull KtFile originalFile) {
|
||||||
@@ -705,8 +730,10 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
if (isFullFileMove()) {
|
if (isFullFileMove()) {
|
||||||
if (isMoveToPackage()) {
|
if (isMoveToPackage()) {
|
||||||
final MoveDestination moveDestination = selectPackageBasedMoveDestination(false);
|
Pair<VirtualFile, ? extends MoveDestination> sourceRootWithMoveDestination = selectPackageBasedTargetDirAndDestination(false);
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
|
final MoveDestination moveDestination = sourceRootWithMoveDestination.getSecond();
|
||||||
|
|
||||||
PsiDirectory targetDir = moveDestination.getTargetIfExists(sourceDirectory);
|
PsiDirectory targetDir = moveDestination.getTargetIfExists(sourceDirectory);
|
||||||
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||||
List<PsiFile> filesExistingInTargetDir = getFilesExistingInTargetDir(sourceFiles, targetFileName, targetDir);
|
List<PsiFile> filesExistingInTargetDir = getFilesExistingInTargetDir(sourceFiles, targetFileName, targetDir);
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
val val1 = 0
|
||||||
|
val val2 = val1
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package b
|
||||||
|
|
||||||
|
class X
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
val <caret>val1 = 0
|
||||||
|
val val2 = val1
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
package b
|
||||||
|
|
||||||
|
class X
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
Property a.val1, referenced in file test.kt, will not be accessible from module A
|
||||||
|
Property a.val1, referenced in file test.kt, will not be accessible from module A
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"mainFile": "A/src/a/test.kt",
|
||||||
|
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
|
||||||
|
"targetPackage": "target",
|
||||||
|
"targetSourceRoot": "B/src",
|
||||||
|
"isMultiModule": "true",
|
||||||
|
"withRuntime": "true"
|
||||||
|
}
|
||||||
@@ -19,11 +19,15 @@ package org.jetbrains.kotlin.idea.refactoring.move
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import com.intellij.codeInsight.TargetElementUtilBase
|
import com.intellij.codeInsight.TargetElementUtilBase
|
||||||
|
import com.intellij.ide.highlighter.ModuleFileType
|
||||||
import com.intellij.openapi.editor.EditorFactory
|
import com.intellij.openapi.editor.EditorFactory
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
|
import com.intellij.openapi.module.StdModuleTypes
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.openapi.vfs.VfsUtil
|
import com.intellij.openapi.vfs.VfsUtil
|
||||||
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.openapi.vfs.VirtualFileVisitor
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException
|
import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException
|
||||||
import com.intellij.refactoring.PackageWrapper
|
import com.intellij.refactoring.PackageWrapper
|
||||||
@@ -36,6 +40,7 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectori
|
|||||||
import com.intellij.refactoring.move.moveInner.MoveInnerProcessor
|
import com.intellij.refactoring.move.moveInner.MoveInnerProcessor
|
||||||
import com.intellij.refactoring.move.moveMembers.MockMoveMembersOptions
|
import com.intellij.refactoring.move.moveMembers.MockMoveMembersOptions
|
||||||
import com.intellij.refactoring.move.moveMembers.MoveMembersProcessor
|
import com.intellij.refactoring.move.moveMembers.MoveMembersProcessor
|
||||||
|
import com.intellij.testFramework.PsiTestUtil
|
||||||
import com.intellij.util.ActionRunner
|
import com.intellij.util.ActionRunner
|
||||||
import org.jetbrains.kotlin.idea.jsonUtils.getNullableString
|
import org.jetbrains.kotlin.idea.jsonUtils.getNullableString
|
||||||
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||||
@@ -59,6 +64,8 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractMoveTest : KotlinMultiFileTestCase() {
|
abstract class AbstractMoveTest : KotlinMultiFileTestCase() {
|
||||||
|
private var isMultiModule = false
|
||||||
|
|
||||||
protected fun doTest(path: String) {
|
protected fun doTest(path: String) {
|
||||||
val config = JsonParser().parse(FileUtil.loadFile(File(path), true)) as JsonObject
|
val config = JsonParser().parse(FileUtil.loadFile(File(path), true)) as JsonObject
|
||||||
|
|
||||||
@@ -73,6 +80,7 @@ abstract class AbstractMoveTest : KotlinMultiFileTestCase() {
|
|||||||
if (withRuntime) {
|
if (withRuntime) {
|
||||||
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())
|
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())
|
||||||
}
|
}
|
||||||
|
isMultiModule = config["isMultiModule"]?.asBoolean ?: false
|
||||||
|
|
||||||
doTest({ rootDir, rootAfter ->
|
doTest({ rootDir, rootAfter ->
|
||||||
val mainFile = rootDir.findFileByRelativePath(mainFilePath)!!
|
val mainFile = rootDir.findFileByRelativePath(mainFilePath)!!
|
||||||
@@ -112,6 +120,27 @@ abstract class AbstractMoveTest : KotlinMultiFileTestCase() {
|
|||||||
getTestDirName(true))
|
getTestDirName(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun prepareProject(rootDir: VirtualFile) {
|
||||||
|
if (isMultiModule) {
|
||||||
|
VfsUtilCore.visitChildrenRecursively(
|
||||||
|
rootDir,
|
||||||
|
object : VirtualFileVisitor<Any>() {
|
||||||
|
override fun visitFile(file: VirtualFile): Boolean {
|
||||||
|
if (!file.isDirectory && file.name.endsWith(ModuleFileType.DOT_DEFAULT_EXTENSION)) {
|
||||||
|
createModule(File(file.path), StdModuleTypes.JAVA)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PsiTestUtil.addSourceContentToRoots(myModule, rootDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected fun getTestDirName(lowercaseFirstLetter : Boolean) : String {
|
protected fun getTestDirName(lowercaseFirstLetter : Boolean) : String {
|
||||||
val testName = getTestName(lowercaseFirstLetter)
|
val testName = getTestName(lowercaseFirstLetter)
|
||||||
return testName.substring(0, testName.lastIndexOf('_')).replace('_', '/')
|
return testName.substring(0, testName.lastIndexOf('_')).replace('_', '/')
|
||||||
@@ -250,8 +279,16 @@ enum class MoveAction {
|
|||||||
val elementToMove = elementAtCaret!!.getNonStrictParentOfType<KtNamedDeclaration>()!!
|
val elementToMove = elementAtCaret!!.getNonStrictParentOfType<KtNamedDeclaration>()!!
|
||||||
|
|
||||||
val moveTarget = config.getNullableString("targetPackage")?.let { packageName ->
|
val moveTarget = config.getNullableString("targetPackage")?.let { packageName ->
|
||||||
|
val targetSourceRootPath = config["targetSourceRoot"]?.asString
|
||||||
val moveDestination = MultipleRootsMoveDestination(PackageWrapper(mainFile.getManager(), packageName))
|
val moveDestination = MultipleRootsMoveDestination(PackageWrapper(mainFile.getManager(), packageName))
|
||||||
KotlinMoveTargetForDeferredFile(FqName(packageName), moveDestination.getTargetIfExists(mainFile)) {
|
val targetDir = moveDestination.getTargetIfExists(mainFile)
|
||||||
|
val targetSourceRoot = if (targetSourceRootPath != null) {
|
||||||
|
rootDir.findFileByRelativePath(targetSourceRootPath)!!
|
||||||
|
} else {
|
||||||
|
targetDir?.virtualFile
|
||||||
|
}
|
||||||
|
|
||||||
|
KotlinMoveTargetForDeferredFile(FqName(packageName), targetDir, targetSourceRoot) {
|
||||||
createKotlinFile(guessNewFileName(listOf(elementToMove))!!, moveDestination.getTargetDirectory(mainFile))
|
createKotlinFile(guessNewFileName(listOf(elementToMove))!!, moveDestination.getTargetDirectory(mainFile))
|
||||||
}
|
}
|
||||||
} ?: config.getString("targetFile").let { filePath ->
|
} ?: config.getString("targetFile").let { filePath ->
|
||||||
@@ -298,7 +335,7 @@ enum class MoveAction {
|
|||||||
val fileName = (delegate.newClassName ?: elementToMove.name!!) + ".kt"
|
val fileName = (delegate.newClassName ?: elementToMove.name!!) + ".kt"
|
||||||
val targetPackageFqName = (mainFile as KtFile).packageFqName
|
val targetPackageFqName = (mainFile as KtFile).packageFqName
|
||||||
val targetDir = mainFile.containingDirectory!!
|
val targetDir = mainFile.containingDirectory!!
|
||||||
KotlinMoveTargetForDeferredFile(targetPackageFqName, targetDir) {
|
KotlinMoveTargetForDeferredFile(targetPackageFqName, targetDir, null) {
|
||||||
createKotlinFile(fileName, targetDir, targetPackageFqName.asString())
|
createKotlinFile(fileName, targetDir, targetPackageFqName.asString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -437,6 +437,12 @@ public class MoveTestGenerated extends AbstractMoveTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/moveToUnrelatedModuleConflict/moveToUnrelatedModuleConflict.test")
|
||||||
|
public void testKotlin_moveTopLevelDeclarations_misc_moveToUnrelatedModuleConflict_MoveToUnrelatedModuleConflict() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/moveToUnrelatedModuleConflict/moveToUnrelatedModuleConflict.test");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test")
|
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test")
|
||||||
public void testKotlin_moveTopLevelDeclarations_misc_selfReferences_SelfReferences() throws Exception {
|
public void testKotlin_moveTopLevelDeclarations_misc_selfReferences_SelfReferences() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test");
|
||||||
|
|||||||
Reference in New Issue
Block a user