[kotlin] Move Mover to common refactoring module

^KTIJ-23273 Also moves `deleteSingle` extension function.

GitOrigin-RevId: c64aef7886c2921eb9d22d1b6cd86d4598e521b3
This commit is contained in:
Bart van Helvert
2023-04-28 13:11:41 +00:00
committed by intellij-monorepo-bot
parent 179f71a4f4
commit 2c989a2303
11 changed files with 65 additions and 48 deletions
@@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.base.psi
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.lexer.KtTokens
@@ -27,6 +28,10 @@ inline fun <reified T : PsiElement> PsiElement.replaced(newElement: T): T {
}
}
fun PsiElement.deleteSingle() {
CodeEditUtil.removeChild(parent?.node ?: return, node ?: return)
}
fun KtBlockStringTemplateEntry.dropCurlyBracketsIfPossible(): KtStringTemplateEntryWithExpression {
return if (canDropCurlyBrackets()) dropCurlyBrackets() else this
}
@@ -307,6 +307,10 @@ private fun deleteElementWithDelimiters(element: PsiElement) {
parent.deleteChildRange(from, to)
}
@Deprecated(
"Use 'org.jetbrains.kotlin.idea.base.psi.KotlinPsiModificationUtils' instead",
ReplaceWith("this.deleteSingle()", "org.jetbrains.kotlin.idea.base.psi.deleteSingle")
)
fun PsiElement.deleteSingle() {
CodeEditUtil.removeChild(parent?.node ?: return, node ?: return)
}
@@ -11,10 +11,10 @@ import org.jetbrains.kotlin.idea.refactoring.CompositeRefactoringRunner
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveSource
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMover
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.Mover
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@@ -71,7 +71,7 @@ abstract class MoveMemberOutOfObjectIntention(textGetter: () -> String) : SelfTa
val conflicts = MultiMap<PsiElement, String>().apply { addConflicts(element, this) }
project.checkConflictsInteractively(conflicts) {
runWriteAction {
Mover.Default(element, destination)
KotlinMover.Default(element, destination)
deleteClassOrObjectIfEmpty()
}
}
@@ -52,7 +52,6 @@ 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.Mover
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
@@ -312,7 +311,7 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
removeModifiers(element)
val newDeclaration = Mover.Default(element, companionObject)
val newDeclaration = KotlinMover.Default(element, companionObject)
progressIndicator.checkCanceled()
for ((index, usage) in externalUsages.withIndex()) {
progressIndicator.checkCanceled()
@@ -375,9 +374,9 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
if (traverseOuterInstanceReferences(element, true)) getNameSuggestionsForOuterInstance(element) else emptyList()
val outerInstanceName = nameSuggestions.firstOrNull()
var movedClass: KtClassOrObject? = null
val mover = object : Mover {
val mover = object : KotlinMover {
override fun invoke(originalElement: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
return Mover.Default(originalElement, targetContainer).apply { movedClass = this as KtClassOrObject }
return KotlinMover.Default(originalElement, targetContainer).apply { movedClass = this as KtClassOrObject }
}
}
val moveDescriptor = MoveDeclarationsDescriptor(
@@ -20,10 +20,10 @@ 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.KotlinMoveSource
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMover
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.Mover
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.getSourceRoot
import org.jetbrains.kotlin.psi.*
@@ -131,7 +131,7 @@ class MoveDeclarationsProcessor(
psiDocumentManager.commitDocument(sourceDocument)
}
val mover = object : Mover {
val mover = object : KotlinMover {
override fun invoke(declaration: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
val index = stubDeclarations.indexOf(declaration)
assert(index >= 0)
@@ -12,7 +12,6 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.move.MoveCallback
@@ -36,56 +35,26 @@ import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.idea.base.psi.kotlinFqName
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.base.searching.usages.KotlinFindUsagesHandlerFactory
import org.jetbrains.kotlin.idea.base.util.module
import org.jetbrains.kotlin.idea.base.util.projectScope
import org.jetbrains.kotlin.idea.base.util.quoteIfNeeded
import org.jetbrains.kotlin.idea.base.util.restrictByFileType
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToBeShortenedDescendantsToWaitingSet
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.core.deleteSingle
import org.jetbrains.kotlin.idea.refactoring.broadcastRefactoringExit
import org.jetbrains.kotlin.idea.refactoring.move.*
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinClassHandler
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.utils.ifEmpty
import org.jetbrains.kotlin.utils.keysToMap
import kotlin.math.max
import kotlin.math.min
interface Mover : (KtNamedDeclaration, KtElement) -> KtNamedDeclaration {
object Default : Mover {
override fun invoke(originalElement: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
return when (targetContainer) {
is KtFile -> {
val declarationContainer: KtElement =
if (targetContainer.isScript()) targetContainer.script!!.blockExpression else targetContainer
declarationContainer.add(originalElement) as KtNamedDeclaration
}
is KtClassOrObject -> targetContainer.addDeclaration(originalElement)
else -> error("Unexpected element: ${targetContainer.getElementTextWithContext()}")
}.apply {
val container = originalElement.containingClassOrObject
if (container is KtObjectDeclaration &&
container.isCompanion() &&
container.declarations.singleOrNull() == originalElement &&
KotlinFindUsagesHandlerFactory(container.project).createFindUsagesHandler(container, false)
.findReferencesToHighlight(container, LocalSearchScope(container.containingFile)).isEmpty()
) {
container.deleteSingle()
} else {
originalElement.deleteSingle()
}
}
}
}
}
class MoveDeclarationsDescriptor @JvmOverloads constructor(
val project: Project,
val moveSource: KotlinMoveSource,
@@ -122,7 +91,7 @@ private object ElementHashingStrategy : HashingStrategy<PsiElement> {
class MoveKotlinDeclarationsProcessor(
val descriptor: MoveDeclarationsDescriptor,
val mover: Mover = Mover.Default,
val mover: KotlinMover = KotlinMover.Default,
private val throwOnConflicts: Boolean = false
) : BaseRefactoringProcessor(descriptor.project) {
companion object {
@@ -11,6 +11,7 @@ import com.intellij.refactoring.move.MoveCallback
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveSource
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMover
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.statistics.KotlinMoveRefactoringFUSCollector.MoveRefactoringDestination
import org.jetbrains.kotlin.idea.statistics.KotlinMoveRefactoringFUSCollector.MovedEntity
@@ -68,7 +69,7 @@ internal class MoveKotlinNestedClassesModel(
openInEditor = openInEditorCheckBox
)
val processor = MoveKotlinDeclarationsProcessor(descriptor, Mover.Default, throwOnConflicts)
val processor = MoveKotlinDeclarationsProcessor(descriptor, KotlinMover.Default, throwOnConflicts)
return ModelResultWithFUSData(
processor,
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveSource
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.KotlinMover
import org.jetbrains.kotlin.idea.refactoring.move.getTargetPackageFqName
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.roots.getSuitableDestinationSourceRoots
@@ -206,7 +207,7 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
openInEditor = isOpenInEditor
)
val processor = MoveKotlinDeclarationsProcessor(moveDescriptor, Mover.Default, throwOnConflicts)
val processor = MoveKotlinDeclarationsProcessor(moveDescriptor, KotlinMover.Default, throwOnConflicts)
return ModelResultWithFUSData(
processor = processor,
@@ -323,6 +323,6 @@ internal class MoveKotlinTopLevelDeclarationsModel(
analyzeConflicts = true,
searchReferences = isSearchReferences
)
return MoveKotlinDeclarationsProcessor(options, Mover.Default, throwOnConflicts)
return MoveKotlinDeclarationsProcessor(options, KotlinMover.Default, throwOnConflicts)
}
}
@@ -27,7 +27,6 @@ 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.MoveConflictChecker
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.Mover
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.languageVersionSettings
import org.jetbrains.kotlin.idea.util.getFactoryForImplicitReceiverWithSubtypeOf
@@ -268,7 +267,7 @@ class MoveKotlinMethodProcessor(
changeMethodSignature()
markInternalUsages(oldInternalUsages)
val movedMethod = Mover.Default(method, targetClassOrObject)
val movedMethod = KotlinMover.Default(method, targetClassOrObject)
val oldToNewMethodMap = mapOf<PsiElement, PsiElement>(method to movedMethod)
newInternalUsages += restoreInternalUsages(movedMethod, oldToNewMethodMap)
@@ -0,0 +1,39 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.refactoring.move
import com.intellij.psi.search.LocalSearchScope
import org.jetbrains.kotlin.idea.base.psi.deleteSingle
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
interface KotlinMover : (KtNamedDeclaration, KtElement) -> KtNamedDeclaration {
object Default : KotlinMover {
override fun invoke(originalElement: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
return when (targetContainer) {
is KtFile -> {
val declarationContainer: KtElement =
if (targetContainer.isScript()) targetContainer.script!!.blockExpression else targetContainer
declarationContainer.add(originalElement) as KtNamedDeclaration
}
is KtClassOrObject -> targetContainer.addDeclaration(originalElement)
else -> throw KotlinExceptionWithAttachments("Unexpected element")
.withAttachment("context", targetContainer.getElementTextWithContext())
}.apply {
val container = originalElement.containingClassOrObject
if (container is KtObjectDeclaration &&
container.isCompanion() &&
container.declarations.singleOrNull() == originalElement &&
KotlinMoveRefactoringSupport.getInstance()
.findReferencesToHighlight(container, LocalSearchScope(container.containingFile))
.isEmpty()
) {
container.deleteSingle()
} else {
originalElement.deleteSingle()
}
}
}
}
}