mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-14 08:31:29 +00:00
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-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-13174`](https://youtrack.jetbrains.com/issue/KT-13174) Move: Warn about accessibility conflicts due to moving to unrelated module
|
||||
|
||||
##### New features
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.changePackage
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
@@ -47,6 +48,8 @@ class KotlinChangePackageRefactoring(val file: KtFile) {
|
||||
|
||||
override val directory: PsiDirectory = file.containingDirectory!!
|
||||
|
||||
override val targetFile: VirtualFile? = directory.virtualFile
|
||||
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile
|
||||
|
||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
@@ -30,6 +31,8 @@ import java.util.*
|
||||
|
||||
interface KotlinMoveTarget {
|
||||
val targetContainerFqName: FqName?
|
||||
val targetFile: VirtualFile?
|
||||
|
||||
fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement?
|
||||
fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement?
|
||||
|
||||
@@ -43,6 +46,8 @@ interface KotlinDirectoryBasedMoveTarget : KotlinMoveTarget {
|
||||
|
||||
object EmptyKotlinMoveTarget: KotlinMoveTarget {
|
||||
override val targetContainerFqName = null
|
||||
override val targetFile = null
|
||||
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = null
|
||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||
override fun verify(file: PsiFile) = null
|
||||
@@ -51,6 +56,8 @@ object EmptyKotlinMoveTarget: KotlinMoveTarget {
|
||||
class KotlinMoveTargetForExistingElement(val targetElement: KtElement): KotlinMoveTarget {
|
||||
override val targetContainerFqName = targetElement.getContainingKtFile().packageFqName
|
||||
|
||||
override val targetFile: VirtualFile? = targetElement.getContainingKtFile().virtualFile
|
||||
|
||||
override fun getOrCreateTargetPsi(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
|
||||
?: 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 getTargetPsiIfExists(originalPsi: PsiElement) = targetClass.getCompanionObjects().firstOrNull()
|
||||
@@ -74,6 +83,7 @@ class KotlinMoveTargetForCompanion(val targetClass: KtClass): KotlinMoveTarget {
|
||||
class KotlinMoveTargetForDeferredFile(
|
||||
override val targetContainerFqName: FqName,
|
||||
override val directory: PsiDirectory?,
|
||||
override val targetFile: VirtualFile? = directory?.virtualFile,
|
||||
private val createFile: (KtFile) -> KtFile?
|
||||
): KotlinDirectoryBasedMoveTarget {
|
||||
private val createdFiles = HashMap<KtFile, KtFile?>()
|
||||
|
||||
@@ -90,7 +90,7 @@ class MoveDeclarationToSeparateFileIntention :
|
||||
}
|
||||
return
|
||||
}
|
||||
val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory) {
|
||||
val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory, null) {
|
||||
createKotlinFile(targetFileName, directory, packageName.asString())
|
||||
}
|
||||
val moveOptions = MoveDeclarationsDescriptor(
|
||||
|
||||
@@ -22,20 +22,16 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.move.MoveCallback
|
||||
import com.intellij.refactoring.move.MoveMultipleElementsViewDescriptor
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler
|
||||
import com.intellij.refactoring.rename.RenameUtil
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||
import com.intellij.refactoring.util.NonCodeUsageInfo
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
||||
import com.intellij.refactoring.util.TextOccurrencesUtil
|
||||
import com.intellij.refactoring.util.*
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.usageView.UsageViewBundle
|
||||
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.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.toLightElements
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
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.search.projectScope
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
||||
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.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
import java.util.*
|
||||
|
||||
@@ -253,6 +248,39 @@ class MoveKotlinDeclarationsProcessor(
|
||||
|
||||
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>) {
|
||||
val declarationToContainers = HashMap<KtNamedDeclaration, MutableSet<PsiElement>>()
|
||||
for (usage in usages) {
|
||||
@@ -319,6 +347,8 @@ class MoveKotlinDeclarationsProcessor(
|
||||
|
||||
usages += descriptor.delegate.findUsages(descriptor)
|
||||
collectUsages(kotlinToLightElements, usages)
|
||||
checkModuleConflictsInUsages(usages)
|
||||
checkModuleConflictsInDeclarations()
|
||||
checkVisibilityInUsages(usages)
|
||||
checkVisibilityInDeclarations()
|
||||
descriptor.delegate.collectConflicts(descriptor, usages, conflicts)
|
||||
|
||||
@@ -375,6 +375,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||
moveTarget = new KotlinMoveTargetForDeferredFile(
|
||||
targetPackageFqName,
|
||||
targetDir,
|
||||
null,
|
||||
new Function1<KtFile, KtFile>() {
|
||||
@Override
|
||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
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.event.DocumentAdapter;
|
||||
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.ui.Messages;
|
||||
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.EmptyRunnable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Pass;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.JavaRefactoringSettings;
|
||||
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.move.MoveCallback;
|
||||
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.MoveClassesOrPackagesUtil;
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.MultipleRootsMoveDestination;
|
||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesProcessor;
|
||||
import com.intellij.refactoring.ui.PackageNameReferenceEditorCombo;
|
||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||
@@ -59,8 +66,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType;
|
||||
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.KotlinRefactoringUtilKt;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
||||
@@ -103,6 +110,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
private KotlinMemberSelectionTable memberTable;
|
||||
|
||||
private final MoveCallback moveCallback;
|
||||
private final PsiDirectory initialTargetDirectory;
|
||||
|
||||
public MoveKotlinTopLevelDeclarationsDialog(
|
||||
@NotNull Project project,
|
||||
@@ -120,6 +128,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
List<KtFile> sourceFiles = getSourceFiles(elementsToMove);
|
||||
|
||||
this.moveCallback = moveCallback;
|
||||
this.initialTargetDirectory = targetDirectory;
|
||||
|
||||
init();
|
||||
|
||||
@@ -440,7 +449,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private MoveDestination selectPackageBasedMoveDestination(boolean askIfDoesNotExist) {
|
||||
private Pair<VirtualFile, ? extends MoveDestination> selectPackageBasedTargetDirAndDestination(boolean askIfDoesNotExist) {
|
||||
String packageName = getTargetPackage();
|
||||
|
||||
RecentsManager.getInstance(myProject).registerRecentEntry(RECENTS_KEY, packageName);
|
||||
@@ -451,7 +460,18 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
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) {
|
||||
@@ -508,8 +528,11 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
PsiDirectory sourceDirectory = getSourceDirectory(sourceFiles);
|
||||
|
||||
if (isMoveToPackage()) {
|
||||
final MoveDestination moveDestination = selectPackageBasedMoveDestination(true);
|
||||
if (moveDestination == null) return null;
|
||||
Pair<VirtualFile, ? extends MoveDestination> targetDirWithMoveDestination = selectPackageBasedTargetDirAndDestination(true);
|
||||
if (targetDirWithMoveDestination == null) return null;
|
||||
|
||||
VirtualFile targetDir = targetDirWithMoveDestination.getFirst();
|
||||
final MoveDestination moveDestination = targetDirWithMoveDestination.getSecond();
|
||||
|
||||
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||
if (targetFileName != null && !checkTargetFileName(targetFileName)) return null;
|
||||
@@ -555,6 +578,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
return new KotlinMoveTargetForDeferredFile(
|
||||
new FqName(getTargetPackage()),
|
||||
moveDestination.getTargetIfExists(sourceFiles.get(0)),
|
||||
targetDir,
|
||||
new Function1<KtFile, KtFile>() {
|
||||
@Override
|
||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
||||
@@ -610,6 +634,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
return new KotlinMoveTargetForDeferredFile(
|
||||
targetPackageFqName,
|
||||
psiDirectory,
|
||||
null,
|
||||
new Function1<KtFile, KtFile>() {
|
||||
@Override
|
||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
||||
@@ -705,8 +730,10 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
|
||||
if (isFullFileMove()) {
|
||||
if (isMoveToPackage()) {
|
||||
final MoveDestination moveDestination = selectPackageBasedMoveDestination(false);
|
||||
Pair<VirtualFile, ? extends MoveDestination> sourceRootWithMoveDestination = selectPackageBasedTargetDirAndDestination(false);
|
||||
//noinspection ConstantConditions
|
||||
final MoveDestination moveDestination = sourceRootWithMoveDestination.getSecond();
|
||||
|
||||
PsiDirectory targetDir = moveDestination.getTargetIfExists(sourceDirectory);
|
||||
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||
List<PsiFile> filesExistingInTargetDir = getFilesExistingInTargetDir(sourceFiles, targetFileName, targetDir);
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1,4 @@
|
||||
package a
|
||||
|
||||
val val1 = 0
|
||||
val val2 = val1
|
||||
@@ -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>
|
||||
@@ -0,0 +1,3 @@
|
||||
package b
|
||||
|
||||
class X
|
||||
@@ -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>
|
||||
@@ -0,0 +1,4 @@
|
||||
package a
|
||||
|
||||
val <caret>val1 = 0
|
||||
val val2 = val1
|
||||
@@ -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>
|
||||
@@ -0,0 +1,3 @@
|
||||
package b
|
||||
|
||||
class X
|
||||
@@ -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
|
||||
@@ -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.JsonParser
|
||||
import com.intellij.codeInsight.TargetElementUtilBase
|
||||
import com.intellij.ide.highlighter.ModuleFileType
|
||||
import com.intellij.openapi.editor.EditorFactory
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.module.StdModuleTypes
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException
|
||||
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.moveMembers.MockMoveMembersOptions
|
||||
import com.intellij.refactoring.move.moveMembers.MoveMembersProcessor
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.ActionRunner
|
||||
import org.jetbrains.kotlin.idea.jsonUtils.getNullableString
|
||||
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||
@@ -59,6 +64,8 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractMoveTest : KotlinMultiFileTestCase() {
|
||||
private var isMultiModule = false
|
||||
|
||||
protected fun doTest(path: String) {
|
||||
val config = JsonParser().parse(FileUtil.loadFile(File(path), true)) as JsonObject
|
||||
|
||||
@@ -73,6 +80,7 @@ abstract class AbstractMoveTest : KotlinMultiFileTestCase() {
|
||||
if (withRuntime) {
|
||||
ConfigLibraryUtil.configureKotlinRuntimeAndSdk(myModule, PluginTestCaseBase.mockJdk())
|
||||
}
|
||||
isMultiModule = config["isMultiModule"]?.asBoolean ?: false
|
||||
|
||||
doTest({ rootDir, rootAfter ->
|
||||
val mainFile = rootDir.findFileByRelativePath(mainFilePath)!!
|
||||
@@ -112,6 +120,27 @@ abstract class AbstractMoveTest : KotlinMultiFileTestCase() {
|
||||
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 {
|
||||
val testName = getTestName(lowercaseFirstLetter)
|
||||
return testName.substring(0, testName.lastIndexOf('_')).replace('_', '/')
|
||||
@@ -250,8 +279,16 @@ enum class MoveAction {
|
||||
val elementToMove = elementAtCaret!!.getNonStrictParentOfType<KtNamedDeclaration>()!!
|
||||
|
||||
val moveTarget = config.getNullableString("targetPackage")?.let { packageName ->
|
||||
val targetSourceRootPath = config["targetSourceRoot"]?.asString
|
||||
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))
|
||||
}
|
||||
} ?: config.getString("targetFile").let { filePath ->
|
||||
@@ -298,7 +335,7 @@ enum class MoveAction {
|
||||
val fileName = (delegate.newClassName ?: elementToMove.name!!) + ".kt"
|
||||
val targetPackageFqName = (mainFile as KtFile).packageFqName
|
||||
val targetDir = mainFile.containingDirectory!!
|
||||
KotlinMoveTargetForDeferredFile(targetPackageFqName, targetDir) {
|
||||
KotlinMoveTargetForDeferredFile(targetPackageFqName, targetDir, null) {
|
||||
createKotlinFile(fileName, targetDir, targetPackageFqName.asString())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,6 +437,12 @@ public class MoveTestGenerated extends AbstractMoveTest {
|
||||
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")
|
||||
public void testKotlin_moveTopLevelDeclarations_misc_selfReferences_SelfReferences() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test");
|
||||
|
||||
Reference in New Issue
Block a user