Copy: Report module accessibility conflicts
This commit is contained in:
@@ -116,6 +116,7 @@ import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixMultiFileTest
|
||||
import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.AbstractNameSuggestionProviderTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.copy.AbstractCopyTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.copy.AbstractMultiModuleCopyTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.inline.AbstractInlineTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.AbstractExtractionTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.AbstractMoveTest
|
||||
@@ -759,6 +760,10 @@ fun main(args: Array<String>) {
|
||||
model("refactoring/moveMultiModule", extension = "test", singleClass = true)
|
||||
}
|
||||
|
||||
testClass<AbstractMultiModuleCopyTest> {
|
||||
model("refactoring/copyMultiModule", extension = "test", singleClass = true)
|
||||
}
|
||||
|
||||
testClass<AbstractMultiFileIntentionTest> {
|
||||
model("multiFileIntentions", extension = "test", singleClass = true, filenameStartsLowerCase = true)
|
||||
}
|
||||
|
||||
@@ -22,10 +22,12 @@ import com.intellij.injected.editor.VirtualFileWindow
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.FileIndex
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFileSystemItem
|
||||
import org.jetbrains.kotlin.idea.KotlinModuleFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.JsProjectDetector
|
||||
import org.jetbrains.kotlin.idea.core.script.KotlinScriptConfigurationManager
|
||||
@@ -40,6 +42,11 @@ fun FileIndex.isInSourceContentWithoutInjected(file: VirtualFile): Boolean {
|
||||
return file !is VirtualFileWindow && isInSourceContent(file)
|
||||
}
|
||||
|
||||
fun VirtualFile.getSourceRoot(project: Project): VirtualFile? = ProjectRootManager.getInstance(project).fileIndex.getSourceRootForFile(this)
|
||||
|
||||
val PsiFileSystemItem.sourceRoot: VirtualFile?
|
||||
get() = virtualFile?.getSourceRoot(project)
|
||||
|
||||
object ProjectRootsUtil {
|
||||
@JvmStatic fun isInContent(project: Project, file: VirtualFile, includeProjectSource: Boolean,
|
||||
includeLibrarySource: Boolean, includeLibraryClasses: Boolean,
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.jetbrains.kotlin.idea.refactoring.copy
|
||||
|
||||
import com.intellij.ide.util.DirectoryChooser
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.JavaProjectRootsUtil
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.refactoring.HelpID
|
||||
@@ -39,6 +41,7 @@ import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.idea.core.getPackage
|
||||
import org.jetbrains.kotlin.idea.refactoring.Pass
|
||||
import org.jetbrains.kotlin.idea.refactoring.hasIdentifiersOnly
|
||||
import org.jetbrains.kotlin.idea.util.sourceRoot
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import java.awt.BorderLayout
|
||||
@@ -68,6 +71,9 @@ class CopyKotlinDeclarationDialog(
|
||||
var targetDirectory: MoveDestination? = null
|
||||
private set
|
||||
|
||||
val targetSourceRoot: VirtualFile?
|
||||
get() = ((destinationComboBox.comboBox.selectedItem as? DirectoryChooser.ItemWrapper)?.directory ?: originalFile).sourceRoot
|
||||
|
||||
init {
|
||||
informationLabel.text = RefactoringBundle.message("copy.class.copy.0.1", UsageViewUtil.getType(declaration), UsageViewUtil.getLongName(declaration))
|
||||
informationLabel.font = informationLabel.font.deriveFont(Font.BOLD)
|
||||
|
||||
+70
-39
@@ -22,10 +22,12 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesDialog
|
||||
import com.intellij.refactoring.copy.CopyHandlerDelegateBase
|
||||
@@ -33,14 +35,20 @@ import com.intellij.refactoring.rename.RenameProcessor
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
|
||||
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirectoryMoveTarget
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveConflictChecker
|
||||
import org.jetbrains.kotlin.idea.refactoring.toPsiDirectory
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.idea.util.sourceRoot
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -55,7 +63,7 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
|
||||
@set:TestOnly
|
||||
var Project.newName: String? by UserDataProperty(Key.create("NEW_NAME"))
|
||||
|
||||
private fun PsiElement.getElementsToCopy(): List<PsiNamedElement> {
|
||||
private fun PsiElement.getElementsToCopy(): List<KtElement> {
|
||||
val declarationOrFile = parentsWithSelf.firstOrNull { it is KtFile || (it is KtNamedDeclaration && it.parent is KtFile) }
|
||||
return when (declarationOrFile) {
|
||||
is KtFile -> declarationOrFile.declarations.filterIsInstance<KtNamedDeclaration>().ifEmpty { listOf(declarationOrFile) }
|
||||
@@ -147,15 +155,16 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
|
||||
|
||||
val project = initialTargetDirectory.project
|
||||
|
||||
if (ProjectRootManager.getInstance(project).fileIndex.getSourceRootForFile(initialTargetDirectory.virtualFile) == null) return
|
||||
|
||||
val commandName = "Copy Declarations"
|
||||
|
||||
var openInEditor = false
|
||||
var newName: String? = singleElementToCopy?.name ?: originalFile.name
|
||||
var targetDirWrapper: AutocreatingPsiDirectoryWrapper = initialTargetDirectory.toDirectoryWrapper()
|
||||
var targetSourceRoot: VirtualFile? = initialTargetDirectory.sourceRoot ?: return
|
||||
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode) {
|
||||
val isUnitTestMode = ApplicationManager.getApplication().isUnitTestMode
|
||||
|
||||
if (!isUnitTestMode) {
|
||||
if (singleElementToCopy != null && singleElementToCopy is KtNamedDeclaration) {
|
||||
val dialog = CopyKotlinDeclarationDialog(singleElementToCopy, initialTargetDirectory, project)
|
||||
dialog.title = commandName
|
||||
@@ -164,6 +173,7 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
|
||||
openInEditor = dialog.openInEditor
|
||||
newName = dialog.newName ?: singleElementToCopy.name
|
||||
targetDirWrapper = dialog.targetDirectory?.toDirectoryWrapper() ?: return
|
||||
targetSourceRoot = dialog.targetSourceRoot
|
||||
}
|
||||
else {
|
||||
val dialog = CopyFilesOrDirectoriesDialog(arrayOf(originalFile), initialTargetDirectory, project, false)
|
||||
@@ -171,6 +181,7 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
|
||||
openInEditor = dialog.openInEditor()
|
||||
newName = dialog.newName
|
||||
targetDirWrapper = dialog.targetDirectory?.toDirectoryWrapper() ?: return
|
||||
targetSourceRoot = dialog.targetDirectory?.sourceRoot
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -185,8 +196,8 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
|
||||
ContainerInfo.Package(originalFile.packageFqName),
|
||||
ContainerInfo.Package(FqName(targetPackageName))
|
||||
)
|
||||
elementsToCopy.flatMap { elementToCopy ->
|
||||
(elementToCopy as KtElement).getInternalReferencesToUpdateOnPackageNameChange(changeInfo).filter {
|
||||
elementsToCopy.flatMapTo(LinkedHashSet()) { elementToCopy ->
|
||||
elementToCopy.getInternalReferencesToUpdateOnPackageNameChange(changeInfo).filter {
|
||||
val referencedElement = (it as? MoveRenameUsageInfo)?.referencedElement
|
||||
referencedElement == null || !elementToCopy.isAncestor(referencedElement)
|
||||
}
|
||||
@@ -194,51 +205,71 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
|
||||
}
|
||||
markInternalUsages(internalUsages)
|
||||
|
||||
val restoredInternalUsages = ArrayList<UsageInfo>()
|
||||
fun doRefactor() {
|
||||
val restoredInternalUsages = ArrayList<UsageInfo>()
|
||||
|
||||
project.executeCommand(commandName) {
|
||||
try {
|
||||
val targetDirectory = runWriteAction { targetDirWrapper.getOrCreateDirectory(initialTargetDirectory) }
|
||||
val targetFileName = if (newName?.contains(".") ?: false) newName!! else newName + "." + originalFile.virtualFile.extension
|
||||
project.executeCommand(commandName) {
|
||||
try {
|
||||
val targetDirectory = runWriteAction { targetDirWrapper.getOrCreateDirectory(initialTargetDirectory) }
|
||||
val targetFileName = if (newName?.contains(".") ?: false) newName!! else newName + "." + originalFile.virtualFile.extension
|
||||
|
||||
val oldToNewElementsMapping = HashMap<PsiElement, PsiElement>()
|
||||
val oldToNewElementsMapping = HashMap<PsiElement, PsiElement>()
|
||||
|
||||
val targetFile: KtFile
|
||||
if (singleElementToCopy is KtFile) {
|
||||
targetFile = runWriteAction { targetDirectory.copyFileFrom(targetFileName, singleElementToCopy) as KtFile }
|
||||
}
|
||||
else {
|
||||
targetFile = getOrCreateTargetFile(originalFile, targetDirectory, targetFileName, commandName) ?: return@executeCommand
|
||||
runWriteAction {
|
||||
val newElements = elementsToCopy.map { targetFile.add(it.copy()) as KtNamedDeclaration }
|
||||
elementsToCopy.zip(newElements).toMap(oldToNewElementsMapping)
|
||||
}
|
||||
}
|
||||
|
||||
val targetFile: KtFile
|
||||
if (singleElementToCopy is KtFile) {
|
||||
targetFile = runWriteAction { targetDirectory.copyFileFrom(targetFileName, singleElementToCopy) as KtFile }
|
||||
}
|
||||
else {
|
||||
targetFile = getOrCreateTargetFile(originalFile, targetDirectory, targetFileName, commandName) ?: return@executeCommand
|
||||
runWriteAction {
|
||||
val newElements = elementsToCopy.map { targetFile.add(it.copy()) as KtNamedDeclaration }
|
||||
elementsToCopy.zip(newElements).toMap(oldToNewElementsMapping)
|
||||
}
|
||||
}
|
||||
for (newElement in oldToNewElementsMapping.values) {
|
||||
restoredInternalUsages += restoreInternalUsages(newElement as KtElement, oldToNewElementsMapping, true)
|
||||
postProcessMoveUsages(restoredInternalUsages, oldToNewElementsMapping)
|
||||
}
|
||||
|
||||
runWriteAction {
|
||||
for (newElement in oldToNewElementsMapping.values) {
|
||||
restoredInternalUsages += restoreInternalUsages(newElement as KtElement, oldToNewElementsMapping, true)
|
||||
postProcessMoveUsages(restoredInternalUsages, oldToNewElementsMapping)
|
||||
performDelayedRefactoringRequests(project)
|
||||
}
|
||||
|
||||
performDelayedRefactoringRequests(project)
|
||||
}
|
||||
oldToNewElementsMapping.values.singleOrNull()?.let {
|
||||
RenameProcessor(project, it, newName!!.quoteIfNeeded(), false, false).run()
|
||||
}
|
||||
|
||||
oldToNewElementsMapping.values.singleOrNull()?.let {
|
||||
RenameProcessor(project, it, newName!!.quoteIfNeeded(), false, false).run()
|
||||
if (openInEditor) {
|
||||
EditorHelper.openFilesInEditor(arrayOf(targetFile))
|
||||
}
|
||||
}
|
||||
|
||||
if (openInEditor) {
|
||||
EditorHelper.openFilesInEditor(arrayOf(targetFile))
|
||||
catch (e: IncorrectOperationException) {
|
||||
Messages.showMessageDialog(project, e.message, RefactoringBundle.message("error.title"), Messages.getErrorIcon())
|
||||
}
|
||||
finally {
|
||||
cleanUpInternalUsages(internalUsages + restoredInternalUsages)
|
||||
}
|
||||
}
|
||||
catch (e: IncorrectOperationException) {
|
||||
Messages.showMessageDialog(project, e.message, RefactoringBundle.message("error.title"), Messages.getErrorIcon())
|
||||
}
|
||||
finally {
|
||||
cleanUpInternalUsages(internalUsages + restoredInternalUsages)
|
||||
}
|
||||
}
|
||||
|
||||
val conflicts = MultiMap<PsiElement, String>()
|
||||
|
||||
if (!(isUnitTestMode && BaseRefactoringProcessor.ConflictsInTestsException.isTestIgnore())) {
|
||||
val targetSourceRootPsi = targetSourceRoot?.toPsiDirectory(project)
|
||||
if (targetSourceRootPsi != null) {
|
||||
val conflictChecker = MoveConflictChecker(
|
||||
project,
|
||||
elementsToCopy,
|
||||
KotlinDirectoryMoveTarget(FqName.ROOT, targetSourceRootPsi),
|
||||
originalFile
|
||||
)
|
||||
conflictChecker.checkModuleConflictsInDeclarations(internalUsages, conflicts)
|
||||
conflictChecker.checkVisibilityInDeclarations(conflicts)
|
||||
}
|
||||
}
|
||||
|
||||
project.checkConflictsInteractively(conflicts, onAccept = ::doRefactor)
|
||||
}
|
||||
|
||||
override fun doClone(element: PsiElement) {
|
||||
|
||||
+2
-2
@@ -219,7 +219,7 @@ class MoveConflictChecker(
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkModuleConflictsInDeclarations(
|
||||
fun checkModuleConflictsInDeclarations(
|
||||
internalUsages: MutableSet<UsageInfo>,
|
||||
conflicts: MultiMap<PsiElement, String>
|
||||
) {
|
||||
@@ -327,7 +327,7 @@ class MoveConflictChecker(
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkVisibilityInDeclarations(conflicts: MultiMap<PsiElement, String>) {
|
||||
fun checkVisibilityInDeclarations(conflicts: MultiMap<PsiElement, String>) {
|
||||
val targetContainer = moveTarget.getContainerDescriptor() ?: return
|
||||
|
||||
fun DeclarationDescriptor.targetAwareContainingDescriptor(): DeclarationDescriptor? {
|
||||
|
||||
+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>
|
||||
idea/testData/refactoring/copyMultiModule/internalReferencesToAnotherModule2/after/A/src/foo/test.kt
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
package foo
|
||||
|
||||
internal class A {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
|
||||
internal class B {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?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" />
|
||||
<orderEntry type="module" module-name="A" />
|
||||
</component>
|
||||
</module>
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package bar
|
||||
|
||||
import foo.B
|
||||
|
||||
internal class A {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
package bar
|
||||
Vendored
+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>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package foo
|
||||
|
||||
internal class <caret>A {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
|
||||
internal class B {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
<?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" />
|
||||
<orderEntry type="module" module-name="A" />
|
||||
</component>
|
||||
</module>
|
||||
+1
@@ -0,0 +1 @@
|
||||
package bar
|
||||
+1
@@ -0,0 +1 @@
|
||||
Class A uses class B which will be inaccessible after move
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"mainFile": "A/src/foo/test.kt",
|
||||
"targetDirectory": "B/src/bar"
|
||||
}
|
||||
+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>
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
package foo
|
||||
|
||||
class A {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
|
||||
class B {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
+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>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package bar
|
||||
|
||||
class A {
|
||||
val a: A = A()
|
||||
val b: foo.B = foo.B()
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
package bar
|
||||
+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>
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
package foo
|
||||
|
||||
class <caret>A {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
|
||||
class B {
|
||||
val a: A = A()
|
||||
val b: B = B()
|
||||
}
|
||||
+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>
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
package bar
|
||||
+1
@@ -0,0 +1 @@
|
||||
Class foo.B, referenced in property A.b, will not be accessible in module B
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"mainFile": "A/src/foo/test.kt",
|
||||
"targetDirectory": "B/src/bar"
|
||||
}
|
||||
@@ -29,21 +29,37 @@ import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||
import org.jetbrains.kotlin.idea.refactoring.AbstractMultifileRefactoringTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.copy.CopyKotlinDeclarationsHandler.Companion.newName
|
||||
import org.jetbrains.kotlin.idea.refactoring.runRefactoringTest
|
||||
import org.jetbrains.kotlin.idea.refactoring.toPsiDirectory
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
|
||||
abstract class AbstractCopyTest : AbstractMultifileRefactoringTest(), AbstractMultifileRefactoringTest.RefactoringAction {
|
||||
override fun runRefactoring(rootDir: VirtualFile, mainFile: PsiFile, elementsAtCaret: List<PsiElement>, config: JsonObject) {
|
||||
val elementsToCopy = elementsAtCaret.ifEmpty { listOf(mainFile) }.toTypedArray()
|
||||
assert(CopyHandler.canCopy(elementsToCopy))
|
||||
abstract class AbstractCopyTest : AbstractMultifileRefactoringTest() {
|
||||
companion object : RefactoringAction {
|
||||
fun runCopyRefactoring(path: String, config: JsonObject, rootDir: VirtualFile, project: Project) {
|
||||
runRefactoringTest(path, config, rootDir, project, this)
|
||||
}
|
||||
|
||||
val packageWrapper = PackageWrapper(mainFile.manager, config.getString("targetPackage"))
|
||||
project.newName = config.getNullableString("newName")
|
||||
val targetDirectory = runWriteAction { MultipleRootsMoveDestination(packageWrapper).getTargetDirectory(mainFile) }
|
||||
CopyHandler.doCopy(elementsToCopy, targetDirectory)
|
||||
override fun runRefactoring(rootDir: VirtualFile, mainFile: PsiFile, elementsAtCaret: List<PsiElement>, config: JsonObject) {
|
||||
val project = mainFile.project
|
||||
|
||||
val elementsToCopy = elementsAtCaret.ifEmpty { listOf(mainFile) }.toTypedArray()
|
||||
assert(CopyHandler.canCopy(elementsToCopy))
|
||||
|
||||
val targetDirectory = config.getNullableString("targetDirectory")?.let {
|
||||
rootDir.findFileByRelativePath(it)?.toPsiDirectory(project)
|
||||
}
|
||||
?: run {
|
||||
val packageWrapper = PackageWrapper(mainFile.manager, config.getString("targetPackage"))
|
||||
runWriteAction { MultipleRootsMoveDestination(packageWrapper).getTargetDirectory(mainFile) }
|
||||
}
|
||||
|
||||
project.newName = config.getNullableString("newName")
|
||||
|
||||
CopyHandler.doCopy(elementsToCopy, targetDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
override fun runRefactoring(path: String, config: JsonObject, rootDir: VirtualFile, project: Project) {
|
||||
runRefactoringTest(path, config, rootDir, project, this)
|
||||
runCopyRefactoring(path, config, rootDir, project)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.copy
|
||||
|
||||
import org.jetbrains.kotlin.idea.refactoring.rename.loadTestConfiguration
|
||||
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
|
||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractMultiModuleCopyTest : KotlinMultiFileTestCase() {
|
||||
override fun getTestRoot(): String = "/refactoring/copyMultiModule/"
|
||||
|
||||
override fun getTestDataPath(): String = PluginTestCaseBase.getTestDataPathBase()
|
||||
|
||||
fun doTest(path: String) {
|
||||
val config = loadTestConfiguration(File(path))
|
||||
|
||||
isMultiModule = true
|
||||
|
||||
doTestCommittingDocuments { rootDir, _ ->
|
||||
AbstractCopyTest.runCopyRefactoring(path, config, rootDir, project)
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.copy;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("idea/testData/refactoring/copyMultiModule")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class MultiModuleCopyTestGenerated extends AbstractMultiModuleCopyTest {
|
||||
public void testAllFilesPresentInCopyMultiModule() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/copyMultiModule"), Pattern.compile("^(.+)\\.test$"), TargetBackend.ANY);
|
||||
}
|
||||
|
||||
@TestMetadata("internalReferencesToAnotherModule2/internalReferencesToAnotherModule.test")
|
||||
public void testInternalReferencesToAnotherModule2_InternalReferencesToAnotherModule() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/copyMultiModule/internalReferencesToAnotherModule2/internalReferencesToAnotherModule.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("referencesToUnrelatedModule/referencesToUnrelatedModule.test")
|
||||
public void testReferencesToUnrelatedModule_ReferencesToUnrelatedModule() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/copyMultiModule/referencesToUnrelatedModule/referencesToUnrelatedModule.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user