[kotlin] Move KotlinMoveTarget to common refactoring module

^KTIJ-23273 Also turns it into a sealed interface and make inheritors nested

GitOrigin-RevId: 1e773093d7ead4305763267a024f233e9d523865
This commit is contained in:
Bart van Helvert
2023-04-28 13:11:27 +00:00
committed by intellij-monorepo-bot
parent 3cc4406110
commit a0137aca0c
20 changed files with 199 additions and 167 deletions
@@ -9,6 +9,7 @@ import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.refactoring.CompositeRefactoringRunner
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement
@@ -43,7 +44,7 @@ abstract class MoveMemberOutOfObjectIntention(textGetter: () -> String) : SelfTa
val moveDescriptor = MoveDeclarationsDescriptor(
project,
MoveSource(element),
KotlinMoveTargetForExistingElement(destination),
KotlinMoveTarget.ExistingElement(destination),
MoveDeclarationsDelegate.NestedClass()
)
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.OuterInstanceReferenceUsageInfo
import org.jetbrains.kotlin.idea.refactoring.move.collectOuterInstanceReferences
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
@@ -382,7 +383,7 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
val moveDescriptor = MoveDeclarationsDescriptor(
project,
MoveSource(element),
KotlinMoveTargetForCompanion(containingClass),
KotlinMoveTarget.Companion(containingClass),
MoveDeclarationsDelegate.NestedClass(null, outerInstanceName),
moveCallback = MoveCallback { runTemplateForInstanceParam(movedClass!!, nameSuggestions, editor) }
)
@@ -22,8 +22,8 @@ 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.base.util.quoteIfNeeded
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.base.util.quoteIfNeeded
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix
import org.jetbrains.kotlin.idea.core.packageMatchesDirectoryOrImplicit
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.idea.core.util.toPsiDirectory
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.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
@@ -472,7 +471,7 @@ class CopyKotlinDeclarationsHandler : CopyHandlerDelegateBase() {
val conflictChecker = MoveConflictChecker(
sourceData.project,
sourceData.elementsToCopy,
KotlinDirectoryMoveTarget(FqName.ROOT, targetSourceRootPsi.virtualFile),
KotlinMoveTarget.Directory(FqName.ROOT, targetSourceRootPsi.virtualFile),
sourceData.originalFile
)
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.shorten.runRefactoringAndKeepDelayedRequests
import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.refactoring.cutPaste.MoveDeclarationsTransferableData.Companion.STUB_RENDERER
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.getSourceRoot
@@ -138,7 +139,7 @@ class MoveDeclarationsProcessor(
val declarationProcessor = MoveKotlinDeclarationsProcessor(
MoveDeclarationsDescriptor(
moveSource = MoveSource(stubDeclarations),
moveTarget = KotlinMoveTargetForExistingElement(targetPsiFile),
moveTarget = KotlinMoveTarget.ExistingElement(targetPsiFile),
delegate = MoveDeclarationsDelegate.TopLevel,
project = project
),
@@ -19,23 +19,25 @@ import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.actions.createKotlinFileFromTemplate
import org.jetbrains.kotlin.idea.base.psi.copied
import org.jetbrains.kotlin.idea.base.psi.replaced
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.core.quoteSegmentsIfNeeded
import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.refactoring.introduce.insertDeclaration
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
import org.jetbrains.kotlin.idea.refactoring.memberInfo.getChildrenToAnalyze
import org.jetbrains.kotlin.idea.refactoring.memberInfo.toJavaMemberInfo
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinMoveTargetForDeferredFile
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinMoveTargetForExistingElement
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveConflictChecker
import org.jetbrains.kotlin.idea.refactoring.pullUp.checkVisibilityInAbstractedMembers
import org.jetbrains.kotlin.idea.references.mainReference
@@ -55,6 +57,27 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import kotlin.collections.ArrayList
import kotlin.collections.Collection
import kotlin.collections.LinkedHashMap
import kotlin.collections.LinkedHashSet
import kotlin.collections.List
import kotlin.collections.Map
import kotlin.collections.any
import kotlin.collections.asSequence
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.firstOrNull
import kotlin.collections.flatMapTo
import kotlin.collections.isNotEmpty
import kotlin.collections.joinToString
import kotlin.collections.map
import kotlin.collections.mapNotNull
import kotlin.collections.mapTo
import kotlin.collections.plusAssign
import kotlin.collections.set
import kotlin.collections.sortedBy
import kotlin.collections.toTypedArray
data class ExtractSuperInfo(
val originalClass: KtClassOrObject,
@@ -136,9 +159,9 @@ class ExtractSuperRefactoring(
val moveTarget = if (targetParent is PsiDirectory) {
val targetPackage = targetParent.getPackage() ?: return conflicts
KotlinMoveTargetForDeferredFile(FqName(targetPackage.qualifiedName), targetParent.virtualFile)
KotlinMoveTarget.DeferredFile(FqName(targetPackage.qualifiedName), targetParent.virtualFile)
} else {
KotlinMoveTargetForExistingElement(targetParent as KtElement)
KotlinMoveTarget.ExistingElement(targetParent as KtElement)
}
val conflictChecker = MoveConflictChecker(
project,
@@ -4,16 +4,16 @@ package org.jetbrains.kotlin.idea.refactoring.move.changePackage
import com.intellij.openapi.application.runReadAction
import com.intellij.refactoring.RefactoringBundle
import org.jetbrains.kotlin.idea.base.util.quoteIfNeeded
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.base.util.quoteIfNeeded
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringSettings
import org.jetbrains.kotlin.idea.refactoring.move.ContainerChangeInfo
import org.jetbrains.kotlin.idea.refactoring.move.ContainerInfo
import org.jetbrains.kotlin.idea.refactoring.move.getInternalReferencesToUpdateOnPackageNameChange
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationsDelegate
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationsDescriptor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveSource
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
@@ -29,7 +29,7 @@ class KotlinChangePackageRefactoring(val file: KtFile) {
MoveDeclarationsDescriptor(
project = project,
moveSource = MoveSource(file),
moveTarget = KotlinDirectoryMoveTarget(newFqName, file.containingDirectory!!.virtualFile),
moveTarget = KotlinMoveTarget.Directory(newFqName, file.containingDirectory!!.virtualFile),
delegate = MoveDeclarationsDelegate.TopLevel,
searchInCommentsAndStrings = KotlinRefactoringSettings.instance.MOVE_SEARCH_IN_COMMENTS,
searchInNonCode = KotlinRefactoringSettings.instance.MOVE_SEARCH_FOR_TEXT,
@@ -13,8 +13,8 @@ import com.intellij.usageView.UsageInfo
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.base.util.projectScope
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.createMoveUsageInfoIfPossible
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirectoryMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.analyzeConflictsInFile
import org.jetbrains.kotlin.idea.stubindex.KotlinExactPackagesIndex
import org.jetbrains.kotlin.lexer.KtTokens
@@ -38,7 +38,7 @@ class KotlinAwareDelegatingMoveDestination(
if (targetPackage == null || targetDirectory == null) return
val project = targetDirectory.project
val moveTarget = KotlinDirectoryMoveTarget(FqName(targetPackage.qualifiedName), targetDirectory.virtualFile)
val moveTarget = KotlinMoveTarget.Directory(FqName(targetPackage.qualifiedName), targetDirectory.virtualFile)
val directoriesToMove = elements.flatMapTo(LinkedHashSet<PsiDirectory>()) {
(it as? PsiPackage)?.directories?.toList() ?: emptyList()
}
@@ -20,9 +20,10 @@ import kotlinx.coroutines.withTimeoutOrNull
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
import org.jetbrains.kotlin.idea.refactoring.showWithTransaction
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
@@ -98,7 +99,7 @@ class ExtractDeclarationFromCurrentFileIntention : SelfTargetingRangeIntention<K
return
}
val moveTarget = KotlinMoveTargetForDeferredFile(packageName, directory.virtualFile) {
val moveTarget = KotlinMoveTarget.DeferredFile(packageName, directory.virtualFile) {
createKotlinFile(targetFileName, directory, packageName.asString())
}
@@ -1,103 +0,0 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.base.psi.getOrCreateCompanionObject
import org.jetbrains.kotlin.idea.base.util.getModule
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
interface KotlinMoveTarget {
val targetContainerFqName: FqName?
val targetFileOrDir: VirtualFile?
fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement
fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement?
/**
* Check possible errors and return corresponding message, or null if no errors are detected.
* <code>null</code> means no additional verification is needed.
*/
@NlsContexts.DialogMessage
fun verify(file: PsiFile): String? = null
}
object EmptyKotlinMoveTarget : KotlinMoveTarget {
override val targetContainerFqName: FqName? = null
override val targetFileOrDir: VirtualFile? = null
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement = throw UnsupportedOperationException()
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
}
class KotlinMoveTargetForExistingElement(val targetElement: KtElement) : KotlinMoveTarget {
override val targetContainerFqName = targetElement.containingKtFile.packageFqName
override val targetFileOrDir: VirtualFile = targetElement.containingKtFile.virtualFile
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetElement
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetElement
}
class KotlinMoveTargetForCompanion(val targetClass: KtClass) : KotlinMoveTarget {
override val targetContainerFqName = targetClass.companionObjects.firstOrNull()?.fqName
?: targetClass.fqName!!.child(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
override val targetFileOrDir: VirtualFile = targetClass.containingKtFile.virtualFile
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetClass.getOrCreateCompanionObject()
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetClass.companionObjects.firstOrNull()
}
/**
* Assumes that a target of move is another file (existent or not).
* @param targetDir directory where a target file exists or to be created, used for various checks
* @param targetFileProvider is called to get a target file (new or existing). Original file is available as an argument.
* Result of the call is cached.
*/
class KotlinMoveTargetForDeferredFile(
targetPackageFqName: FqName,
targetDir: VirtualFile?,
private val targetFileProvider: (KtFile) -> KtFile = { it }
) : KotlinMoveTarget {
override val targetFileOrDir: VirtualFile? = targetDir
override val targetContainerFqName: FqName = targetPackageFqName
private val createdFiles = HashMap<KtFile, KtFile>()
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement {
val file = originalPsi.containingFile ?: error("PSI element in not contained in any file: $originalPsi")
val originalFile = file as KtFile
return createdFiles.getOrPut(originalFile) { targetFileProvider(originalFile) }
}
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
}
class KotlinDirectoryMoveTarget(
targetPackageFqName: FqName,
override val targetFileOrDir: VirtualFile
) : KotlinMoveTarget {
override val targetContainerFqName = targetPackageFqName
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtFile {
val file = originalPsi.containingFile ?: error("PSI element in not contained in any file: $originalPsi")
return file as KtFile
}
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
}
fun KotlinMoveTarget.getTargetModule(project: Project) = targetFileOrDir?.getModule(project)
@@ -55,7 +55,7 @@ sealed class MoveDeclarationsDelegate {
) : MoveDeclarationsDelegate() {
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
val originalInfo = ContainerInfo.Class(originalDeclaration.containingClassOrObject!!.fqName!!)
val movingToClass = (moveTarget as? KotlinMoveTargetForExistingElement)?.targetElement is KtClassOrObject
val movingToClass = (moveTarget as? KotlinMoveTarget.ExistingElement)?.targetElement is KtClassOrObject
val targetContainerFqName = moveTarget.targetContainerFqName
val newInfo = when {
targetContainerFqName == null -> ContainerInfo.UnknownPackage
@@ -75,8 +75,8 @@ sealed class MoveDeclarationsDelegate {
companionDescriptor: ClassDescriptor
): Boolean {
return when (val moveTarget = moveDescriptor.moveTarget) {
is KotlinMoveTargetForCompanion -> true
is KotlinMoveTargetForExistingElement -> {
is KotlinMoveTarget.Companion -> true
is KotlinMoveTarget.ExistingElement -> {
val targetClass = moveTarget.targetElement as? KtClassOrObject ?: return false
val targetClassDescriptor = targetClass.unsafeResolveToDescriptor() as ClassDescriptor
val companionClassDescriptor = companionDescriptor.containingDeclaration as? ClassDescriptor ?: return false
@@ -122,7 +122,7 @@ sealed class MoveDeclarationsDelegate {
newClassName?.let { setName(it) }
if (this is KtClass) {
if ((descriptor.moveTarget as? KotlinMoveTargetForExistingElement)?.targetElement !is KtClassOrObject) {
if ((descriptor.moveTarget as? KotlinMoveTarget.ExistingElement)?.targetElement !is KtClassOrObject) {
if (hasModifier(KtTokens.INNER_KEYWORD)) removeModifier(KtTokens.INNER_KEYWORD)
if (hasModifier(KtTokens.PROTECTED_KEYWORD)) removeModifier(KtTokens.PROTECTED_KEYWORD)
}
@@ -186,8 +186,8 @@ class MoveKotlinDeclarationsProcessor(
val javaScope = projectScope.restrictByFileType(JavaFileType.INSTANCE)
val currentFile = ktDeclaration.containingKtFile
val newFile = when (moveTarget) {
is KotlinMoveTargetForExistingElement -> moveTarget.targetElement as? KtFile ?: return null
is KotlinMoveTargetForDeferredFile -> return javaScope
is KotlinMoveTarget.ExistingElement -> moveTarget.targetElement as? KtFile ?: return null
is KotlinMoveTarget.DeferredFile -> return javaScope
else -> return null
}
val currentFacade = currentFile.findFacadeClass()
@@ -55,7 +55,9 @@ import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.core.util.toPsiDirectory
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.refactoring.getUsageContext
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveUsage
import org.jetbrains.kotlin.idea.refactoring.move.getTargetModule
import org.jetbrains.kotlin.idea.refactoring.pullUp.renderForConflicts
import org.jetbrains.kotlin.idea.resolve.languageVersionSettings
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
@@ -114,7 +116,7 @@ class MoveConflictChecker(
private fun KotlinMoveTarget.getContainerDescriptor(): DeclarationDescriptor? {
return when (this) {
is KotlinMoveTargetForExistingElement -> when (val targetElement = targetElement) {
is KotlinMoveTarget.ExistingElement -> when (val targetElement = targetElement) {
is KtNamedDeclaration -> resolutionFacade.resolveToDescriptor(targetElement)
is KtFile -> {
@@ -129,7 +131,7 @@ class MoveConflictChecker(
else -> null
}
is KotlinDirectoryMoveTarget, is KotlinMoveTargetForDeferredFile -> {
is KotlinMoveTarget.Directory, is KotlinMoveTarget.DeferredFile -> {
val packageFqName = targetContainerFqName ?: return null
val targetModuleDescriptor = targetFileOrDir?.let { getModuleDescriptor(it) ?: return null }
?: resolutionFacade.moduleDescriptor
@@ -399,7 +401,7 @@ class MoveConflictChecker(
if (referencedDescriptor is DeclarationDescriptorWithVisibility
&& referencedDescriptor.visibility == DescriptorVisibilities.PUBLIC
&& moveTarget is KotlinMoveTargetForExistingElement
&& moveTarget is KotlinMoveTarget.ExistingElement
&& moveTarget.targetElement.parentsWithSelf.filterIsInstance<KtClassOrObject>().all { it.isPublic }
) continue
@@ -796,8 +798,8 @@ class MoveConflictChecker(
return KotlinJavaPsiFacade.getInstance(project).findPackage(fqName.asString(), GlobalSearchScope.moduleScope(module))
}
return (this as? KotlinDirectoryMoveTarget)?.targetFileOrDir?.toPsiDirectory(project)?.getPackage()
?: (this as? KotlinMoveTargetForDeferredFile)?.targetFileOrDir?.toPsiDirectory(project)?.getPackage()
return (this as? KotlinMoveTarget.Directory)?.targetFileOrDir?.toPsiDirectory(project)?.getPackage()
?: (this as? KotlinMoveTarget.DeferredFile)?.targetFileOrDir?.toPsiDirectory(project)?.getPackage()
?: tryGetPackageFromTargetContainer()
}
@@ -9,6 +9,7 @@ import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.move.MoveCallback
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.statistics.KotlinMoveRefactoringFUSCollector.MoveRefactoringDestination
import org.jetbrains.kotlin.idea.statistics.KotlinMoveRefactoringFUSCollector.MovedEntity
@@ -52,7 +53,7 @@ internal class MoveKotlinNestedClassesModel(
@Throws(ConfigurationException::class)
override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
val elementsToMove = selectedElementsToMove
val target = KotlinMoveTargetForExistingElement(getCheckedTargetClass())
val target = KotlinMoveTarget.ExistingElement(getCheckedTargetClass())
val delegate = MoveDeclarationsDelegate.NestedClass()
val descriptor = MoveDeclarationsDescriptor(
project,
@@ -17,12 +17,13 @@ import com.intellij.refactoring.PackageWrapper
import com.intellij.refactoring.util.RefactoringMessageUtil
import com.intellij.util.CommonJavaRefactoringUtil
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.idea.base.util.module
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.base.fe10.codeInsight.newDeclaration.Fe10KotlinNameSuggester
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.base.util.module
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.getTargetPackageFqName
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.roots.getSuitableDestinationSourceRoots
@@ -171,14 +172,14 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
val targetFileName = suggestedName + "." + KotlinFileType.EXTENSION
val target = KotlinMoveTargetForDeferredFile(
val target = KotlinMoveTarget.DeferredFile(
targetPackageFqName,
target.virtualFile
) { createKotlinFile(targetFileName, target, targetPackageFqName.asString()) }
target to MoveRefactoringDestination.FILE
} else {
KotlinMoveTargetForExistingElement(target as KtElement) to MoveRefactoringDestination.DECLARATION
KotlinMoveTarget.ExistingElement(target as KtElement) to MoveRefactoringDestination.DECLARATION
}
}
@@ -22,11 +22,8 @@ import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.core.util.toPsiDirectory
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.idea.refactoring.getOrCreateKotlinFile
import org.jetbrains.kotlin.idea.refactoring.move.KotlinAwareMoveFilesOrDirectoriesProcessor
import org.jetbrains.kotlin.idea.refactoring.move.MoveToKotlinFileProcessor
import org.jetbrains.kotlin.idea.refactoring.move.mapWithReadActionInProcess
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.refactoring.move.updatePackageDirective
import org.jetbrains.kotlin.idea.statistics.KotlinMoveRefactoringFUSCollector.MoveRefactoringDestination
import org.jetbrains.kotlin.idea.statistics.KotlinMoveRefactoringFUSCollector.MovedEntity
import org.jetbrains.kotlin.idea.util.collectAllExpectAndActualDeclaration
@@ -108,7 +105,7 @@ internal class MoveKotlinTopLevelDeclarationsModel(
if (singleSourceFileMode) {
val singeTargetFile = filesExistingInTargetDir.single() as? KtFile
if (singeTargetFile != null) {
return KotlinMoveTargetForExistingElement(singeTargetFile)
return KotlinMoveTarget.ExistingElement(singeTargetFile)
}
} else {
val filePathsToReport = filesExistingInTargetDir.joinToString(
@@ -135,7 +132,7 @@ internal class MoveKotlinTopLevelDeclarationsModel(
targetDirectory = null
}
return KotlinMoveTargetForDeferredFile(
return KotlinMoveTarget.DeferredFile(
FqName(targetPackage),
targetDirectory?.virtualFile
) {
@@ -159,7 +156,7 @@ internal class MoveKotlinTopLevelDeclarationsModel(
if (sourceFiles.singleOrNull() == it) {
throw ConfigurationException(KotlinBundle.message("text.cannot.move.to.original.file"))
}
return KotlinMoveTargetForExistingElement(it)
return KotlinMoveTarget.ExistingElement(it)
}
val targetDirectoryPath = targetFile.toPath().parent
@@ -183,7 +180,7 @@ internal class MoveKotlinTopLevelDeclarationsModel(
KotlinBundle.message("text.cannot.find.package.corresponding.to.0", targetDirectoryPath)
)
return KotlinMoveTargetForDeferredFile(targetPackageFqName, psiDirectory.virtualFile) {
return KotlinMoveTarget.DeferredFile(targetPackageFqName, psiDirectory.virtualFile) {
getOrCreateKotlinFile(targetFile.name, psiDirectory, targetPackageFqName.asString())
}
}
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.idea.base.util.quoteIfNeeded
import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.refactoring.invokeOnceOnCommandFinish
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirectoryMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.analyzeConflictsInFile
import org.jetbrains.kotlin.name.FqName
@@ -78,7 +78,7 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
conflicts: MultiMap<PsiElement, String>
) {
val psiPackage = directory?.getPackage() ?: return
val moveTarget = KotlinDirectoryMoveTarget(FqName(psiPackage.qualifiedName), directory.virtualFile)
val moveTarget = KotlinMoveTarget.Directory(FqName(psiPackage.qualifiedName), directory.virtualFile)
for ((index, usageInfo) in infos.withIndex()) {
if (usageInfo !is FileUsagesWrapper) continue
@@ -16,11 +16,11 @@ import org.jetbrains.kotlin.idea.base.util.quoteIfNeeded
import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix
import org.jetbrains.kotlin.idea.core.packageMatchesDirectoryOrImplicit
import org.jetbrains.kotlin.idea.refactoring.hasIdentifiersOnly
import org.jetbrains.kotlin.idea.refactoring.move.ContainerChangeInfo
import org.jetbrains.kotlin.idea.refactoring.move.ContainerInfo
import org.jetbrains.kotlin.idea.refactoring.move.allElementsToMove
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.refactoring.move.updatePackageDirective
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationsDelegate
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationsDescriptor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveSource
import org.jetbrains.kotlin.idea.roots.isOutsideKotlinAwareSourceRoot
import org.jetbrains.kotlin.psi.KtFile
@@ -69,12 +69,12 @@ class MoveKotlinFileHandler : MoveFileHandler() {
val project = psiFile.project
val moveTarget = when (val newPackage = packageNameInfo.newContainer) {
ContainerInfo.UnknownPackage -> EmptyKotlinMoveTarget
ContainerInfo.UnknownPackage -> KotlinMoveTarget.Empty
else -> if (newParent == null) {
return null
} else {
KotlinMoveTargetForDeferredFile(newPackage.fqName!!, newParent.virtualFile) {
KotlinMoveTarget.DeferredFile(newPackage.fqName!!, newParent.virtualFile) {
MoveFilesOrDirectoriesUtil.doMoveFile(psiFile, newParent)
val file = newParent.findFile(psiFile.name) ?: error("Lost file after move")
file as KtFile
@@ -17,13 +17,15 @@ import com.intellij.usageView.UsageViewDescriptor
import com.intellij.util.IncorrectOperationException
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.DescriptorVisibilityUtils
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.base.util.projectScope
import org.jetbrains.kotlin.idea.caches.resolve.*
import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinMoveTargetForExistingElement
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveConflictChecker
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.Mover
import org.jetbrains.kotlin.idea.references.mainReference
@@ -70,7 +72,7 @@ class MoveKotlinMethodProcessor(
ContainerInfo.Class(targetClassOrObject.fqName!!)
)
val conflictChecker =
MoveConflictChecker(myProject, listOf(method), KotlinMoveTargetForExistingElement(targetClassOrObject), method)
MoveConflictChecker(myProject, listOf(method), KotlinMoveTarget.ExistingElement(targetClassOrObject), method)
val searchScope = myProject.projectScope()
val internalUsages = mutableSetOf<UsageInfo>()
val methodCallUsages = mutableSetOf<UsageInfo>()
@@ -28,7 +28,10 @@ import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringSettings
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
import org.jetbrains.kotlin.idea.refactoring.move.changePackage.KotlinChangePackageRefactoring
import org.jetbrains.kotlin.idea.refactoring.move.moveClassesOrPackages.KotlinAwareDelegatingMoveDestination
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationsDelegate
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationsDescriptor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveSource
import org.jetbrains.kotlin.idea.refactoring.move.moveMethod.MoveKotlinMethodProcessor
import org.jetbrains.kotlin.idea.refactoring.runRefactoringTest
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
@@ -229,11 +232,11 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
} else {
destDirIfAny?.virtualFile
}
KotlinMoveTargetForDeferredFile(FqName(packageName), targetDir) {
KotlinMoveTarget.DeferredFile(FqName(packageName), targetDir) {
createKotlinFile(guessNewFileName(elementsToMove)!!, moveDestination.getTargetDirectory(mainFile))
}
} ?: config.getString("targetFile").let { filePath ->
KotlinMoveTargetForExistingElement(
KotlinMoveTarget.ExistingElement(
PsiManager.getInstance(project).findFile(rootDir.findFileByRelativePath(filePath)!!) as KtFile
)
}
@@ -291,12 +294,12 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
)
val moveTarget =
if (targetClass != null) {
KotlinMoveTargetForExistingElement(targetClass)
KotlinMoveTarget.ExistingElement(targetClass)
} else {
val fileName = (delegate.newClassName ?: elementToMove.name!!) + ".kt"
val targetPackageFqName = (mainFile as KtFile).packageFqName
val targetDir = mainFile.containingDirectory!!
KotlinMoveTargetForDeferredFile(targetPackageFqName, targetDir.virtualFile) {
KotlinMoveTarget.DeferredFile(targetPackageFqName, targetDir.virtualFile) {
createKotlinFile(fileName, targetDir, targetPackageFqName.asString())
}
}
@@ -0,0 +1,103 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.idea.refactoring.move
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.base.psi.getOrCreateCompanionObject
import org.jetbrains.kotlin.idea.base.util.getModule
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
fun KotlinMoveTarget.getTargetModule(project: Project) = targetFileOrDir?.getModule(project)
sealed interface KotlinMoveTarget {
val targetContainerFqName: FqName?
val targetFileOrDir: VirtualFile?
fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement
fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement?
/**
* Check possible errors and return corresponding message, or null if no errors are detected.
* <code>null</code> means no additional verification is needed.
*/
@NlsContexts.DialogMessage
fun verify(file: PsiFile): String? = null
object Empty : KotlinMoveTarget {
override val targetContainerFqName: FqName? = null
override val targetFileOrDir: VirtualFile? = null
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement = throw UnsupportedOperationException()
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
}
class ExistingElement(val targetElement: KtElement) : KotlinMoveTarget {
override val targetContainerFqName = targetElement.containingKtFile.packageFqName
override val targetFileOrDir: VirtualFile = targetElement.containingKtFile.virtualFile
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetElement
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetElement
}
class Companion(val targetClass: KtClass) : KotlinMoveTarget {
override val targetContainerFqName =
targetClass.companionObjects.firstOrNull()?.fqName ?: targetClass.fqName?.child(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
override val targetFileOrDir: VirtualFile = targetClass.containingKtFile.virtualFile
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetClass.getOrCreateCompanionObject()
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetClass.companionObjects.firstOrNull()
}
/**
* Assumes that a target of move is another file (existent or not).
* @param targetDir directory where a target file exists or to be created, used for various checks
* @param targetFileProvider is called to get a target file (new or existing). Original file is available as an argument.
* Result of the call is cached.
*/
class DeferredFile(
targetPackageFqName: FqName,
targetDir: VirtualFile?,
private val targetFileProvider: (KtFile) -> KtFile = { it }
) : KotlinMoveTarget {
override val targetFileOrDir: VirtualFile? = targetDir
override val targetContainerFqName: FqName = targetPackageFqName
private val createdFiles = HashMap<KtFile, KtFile>()
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement {
val file = originalPsi.containingFile ?: error("PSI element in not contained in any file: $originalPsi")
val originalFile = file as KtFile
return createdFiles.getOrPut(originalFile) { targetFileProvider(originalFile) }
}
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
}
class Directory(targetPackageFqName: FqName, override val targetFileOrDir: VirtualFile) : KotlinMoveTarget {
override val targetContainerFqName = targetPackageFqName
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtFile {
val file = originalPsi.containingFile ?: error("PSI element in not contained in any file: $originalPsi")
return file as KtFile
}
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
}
}