Move: Process internal usages after all declarations are moved
This commit is contained in:
+4
-4
@@ -24,7 +24,6 @@ import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.isToBeShortened
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.copied
|
||||
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
||||
@@ -38,7 +37,10 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.isOneSegmentFQN
|
||||
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementOrCallableRef
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
@@ -130,7 +132,6 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
||||
enum class ShorteningMode {
|
||||
NO_SHORTENING,
|
||||
DELAYED_SHORTENING,
|
||||
DELAYED_SHORTENING_VIA_USER_DATA,
|
||||
FORCED_SHORTENING
|
||||
}
|
||||
|
||||
@@ -159,7 +160,6 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
||||
if (needToShorten) {
|
||||
when (shorteningMode) {
|
||||
ShorteningMode.FORCED_SHORTENING -> ShortenReferences.DEFAULT.process(newQualifiedElement)
|
||||
ShorteningMode.DELAYED_SHORTENING_VIA_USER_DATA -> newQualifiedElement.isToBeShortened = true
|
||||
else -> newQualifiedElement.addToShorteningWaitSet()
|
||||
}
|
||||
}
|
||||
|
||||
+46
-39
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||
|
||||
import com.intellij.ide.util.EditorHelper
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -29,6 +30,7 @@ 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
|
||||
@@ -47,9 +49,9 @@ import org.jetbrains.kotlin.idea.core.deleteSingle
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinClassHandler
|
||||
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.collectDescendantsOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
@@ -81,6 +83,8 @@ interface Mover : (KtNamedDeclaration, KtElement) -> KtNamedDeclaration {
|
||||
}
|
||||
}
|
||||
|
||||
internal var KtSimpleNameExpression.internalUsageInfo: UsageInfo? by CopyableUserDataProperty(Key.create("INTERNAL_USAGE_INFO"))
|
||||
|
||||
class MoveDeclarationsDescriptor(
|
||||
val elementsToMove: Collection<KtNamedDeclaration>,
|
||||
val moveTarget: KotlinMoveTarget,
|
||||
@@ -122,12 +126,6 @@ class MoveKotlinDeclarationsProcessor(
|
||||
|
||||
fun getConflictsAsUsages(): List<UsageInfo> = conflicts.entrySet().map { ConflictUsageInfo(it.key, it.value) }
|
||||
|
||||
class UsageToProcessBeforeMoveWrapper private constructor (element: PsiElement, val originalUsage: UsageInfo): UsageInfo(element) {
|
||||
companion object {
|
||||
fun create(originalUsage: UsageInfo) = originalUsage.element?.let { UsageToProcessBeforeMoveWrapper(it, originalUsage) }
|
||||
}
|
||||
}
|
||||
|
||||
public override fun findUsages(): Array<UsageInfo> {
|
||||
if (elementsToMove.isEmpty()) return UsageInfo.EMPTY_ARRAY
|
||||
|
||||
@@ -194,12 +192,8 @@ class MoveKotlinDeclarationsProcessor(
|
||||
conflictChecker.checkAllConflicts(externalUsages, internalUsages, conflicts)
|
||||
descriptor.delegate.collectConflicts(descriptor, internalUsages, conflicts)
|
||||
|
||||
usages += internalUsages
|
||||
usages += externalUsages
|
||||
|
||||
val (usagesToProcessLater, usagesToProcessEarly) = internalUsages.partition { it is UnqualifiableMoveRenameUsageInfo }
|
||||
usages += usagesToProcessLater
|
||||
usagesToProcessBeforeMove += usagesToProcessEarly
|
||||
usages += usagesToProcessBeforeMove.mapNotNull { UsageToProcessBeforeMoveWrapper.create(it) }
|
||||
}
|
||||
|
||||
descriptor.delegate.collectConflicts(descriptor, usagesToProcessBeforeMove, conflicts)
|
||||
@@ -212,32 +206,25 @@ class MoveKotlinDeclarationsProcessor(
|
||||
}
|
||||
|
||||
override fun performRefactoring(usages: Array<out UsageInfo>) {
|
||||
fun moveDeclaration(declaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): KtNamedDeclaration? {
|
||||
val file = declaration.containingFile as? KtFile
|
||||
assert(file != null) { "${declaration::class.java}: ${declaration.text}" }
|
||||
|
||||
fun moveDeclaration(declaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): KtNamedDeclaration {
|
||||
val targetContainer = moveTarget.getOrCreateTargetPsi(declaration)
|
||||
?: throw AssertionError("Couldn't create Kotlin file for: ${declaration::class.java}: ${declaration.text}")
|
||||
|
||||
descriptor.delegate.preprocessDeclaration(descriptor, declaration)
|
||||
val newElement = mover(declaration, targetContainer)
|
||||
|
||||
newElement.addToBeShortenedDescendantsToWaitingSet()
|
||||
|
||||
return newElement
|
||||
return mover(declaration, targetContainer).apply {
|
||||
addToBeShortenedDescendantsToWaitingSet()
|
||||
}
|
||||
}
|
||||
|
||||
val usageList = usages.toList()
|
||||
val (oldInternalUsages, externalUsages) = usageList.partition { (it as? InternableUsage)?.scope != null }
|
||||
val newInternalUsages = ArrayList<UsageInfo>()
|
||||
|
||||
oldInternalUsages.forEach { (it.element as? KtSimpleNameExpression)?.internalUsageInfo = it }
|
||||
|
||||
val usagesToProcess = ArrayList(externalUsages)
|
||||
|
||||
try {
|
||||
val usageList = usages.toList()
|
||||
|
||||
val (usagesToProcessBeforeMoveWrappers, usagesToProcessAfterMove) =
|
||||
usageList.partition { it is UsageToProcessBeforeMoveWrapper }
|
||||
val usagesToProcessBeforeMove = usagesToProcessBeforeMoveWrappers.map { (it as UsageToProcessBeforeMoveWrapper).originalUsage }
|
||||
|
||||
descriptor.delegate.preprocessUsages(project, descriptor, usagesToProcessBeforeMove)
|
||||
descriptor.delegate.preprocessUsages(project, descriptor, usagesToProcessAfterMove)
|
||||
|
||||
postProcessMoveUsages(usagesToProcessBeforeMove, shorteningMode = ShorteningMode.DELAYED_SHORTENING_VIA_USER_DATA)
|
||||
descriptor.delegate.preprocessUsages(project, descriptor, usageList)
|
||||
|
||||
val oldToNewElementsMapping = THashMap<PsiElement, PsiElement>(
|
||||
object: TObjectHashingStrategy<PsiElement> {
|
||||
@@ -259,18 +246,17 @@ class MoveKotlinDeclarationsProcessor(
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val newDeclarations = ArrayList<KtNamedDeclaration>()
|
||||
|
||||
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
|
||||
for ((oldDeclaration, oldLightElements) in kotlinToLightElements) {
|
||||
val elementListener = transaction!!.getElementListener(oldDeclaration)
|
||||
|
||||
val newDeclaration = moveDeclaration(oldDeclaration, descriptor.moveTarget)
|
||||
if (newDeclaration == null) {
|
||||
for (oldElement in oldLightElements) {
|
||||
oldToNewElementsMapping[oldElement] = oldElement
|
||||
}
|
||||
continue
|
||||
}
|
||||
newDeclarations += newDeclaration
|
||||
|
||||
oldToNewElementsMapping[oldDeclaration] = newDeclaration
|
||||
oldToNewElementsMapping[sourceFile] = newDeclaration.containingKtFile
|
||||
|
||||
elementListener.elementMoved(newDeclaration)
|
||||
@@ -288,12 +274,33 @@ class MoveKotlinDeclarationsProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
nonCodeUsages = postProcessMoveUsages(usagesToProcessAfterMove, oldToNewElementsMapping).toTypedArray()
|
||||
newDeclarations.forEach { newDeclaration ->
|
||||
newInternalUsages += newDeclaration.collectDescendantsOfType<KtSimpleNameExpression>().mapNotNull {
|
||||
val usageInfo = it.internalUsageInfo
|
||||
if (usageInfo?.element != null) return@mapNotNull usageInfo
|
||||
val referencedElement = (usageInfo as? MoveRenameUsageInfo)?.referencedElement ?: return@mapNotNull null
|
||||
val newReferencedElement = oldToNewElementsMapping[referencedElement] ?: referencedElement
|
||||
if (!newReferencedElement.isValid) return@mapNotNull null
|
||||
(usageInfo as? InternableUsage)?.refresh(it, newReferencedElement)
|
||||
}
|
||||
}
|
||||
|
||||
usagesToProcess += newInternalUsages
|
||||
|
||||
nonCodeUsages = postProcessMoveUsages(usagesToProcess, oldToNewElementsMapping).toTypedArray()
|
||||
}
|
||||
catch (e: IncorrectOperationException) {
|
||||
nonCodeUsages = null
|
||||
RefactoringUIUtil.processIncorrectOperation(myProject, e)
|
||||
}
|
||||
finally {
|
||||
(newInternalUsages + oldInternalUsages).forEach {
|
||||
val element = it.element as? KtSimpleNameExpression ?: return@forEach
|
||||
if (element.isValid) {
|
||||
element.internalUsageInfo = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun performPsiSpoilingRefactoring() {
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.openapi.util.Comparing
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
|
||||
import com.intellij.refactoring.move.MoveCallback
|
||||
@@ -123,11 +124,9 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
val descriptor = bindingContext[BindingContext.REFERENCE_TARGET, refExpr]?.getImportableDescriptor() ?: return null
|
||||
val containingDescriptor = descriptor.containingDeclaration ?: return null
|
||||
|
||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
|
||||
var declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
|
||||
val callableKind = (descriptor as? CallableMemberDescriptor)?.kind
|
||||
val containingDeclarationForNonRealMember = if (callableKind != CallableMemberDescriptor.Kind.DECLARATION) {
|
||||
DescriptorToSourceUtilsIde.getAnyDeclaration(project, containingDescriptor) as? KtClassOrObject
|
||||
} else null
|
||||
if (callableKind != null && callableKind != CallableMemberDescriptor.Kind.DECLARATION) return null
|
||||
|
||||
// Special case for enum entry superclass references (they have empty text and don't need to be processed by the refactoring)
|
||||
if (refExpr.textRange.isEmpty) return null
|
||||
@@ -156,13 +155,13 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
}
|
||||
}
|
||||
|
||||
val fqName = DescriptorUtils.getFqName(descriptor).let {
|
||||
if (DescriptorUtils.isCompanionObject(descriptor)
|
||||
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null) {
|
||||
it.parent()
|
||||
}
|
||||
else it
|
||||
if (declaration is KtObjectDeclaration
|
||||
&& declaration.isCompanion()
|
||||
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null) {
|
||||
declaration = declaration.containingClassOrObject ?: declaration
|
||||
}
|
||||
|
||||
val fqName = DescriptorUtils.getFqName(descriptor)
|
||||
if (!fqName.isSafe) return null
|
||||
|
||||
val (oldContainer, newContainer) = containerChangeInfo
|
||||
@@ -178,30 +177,10 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
}
|
||||
.firstOrNull()
|
||||
|
||||
fun doCreateUsageInfo(refExpr: KtSimpleNameExpression): UsageInfo? {
|
||||
// Check container instead of declaration itself as the latter may be not real (e.g. fake override)
|
||||
if (isAncestor(containingDeclarationForNonRealMember ?: declaration, false)) {
|
||||
if (descriptor.importableFqName == null) return null
|
||||
if (getReferenceKind(refExpr.mainReference, declaration) != ReferenceKind.QUALIFIABLE) return null
|
||||
if (containerFqName == null || newContainer is ContainerInfo.UnknownPackage) return null
|
||||
return fqName.asString().let {
|
||||
val prefix = containerFqName.asString()
|
||||
val prefixOffset = it.indexOf(prefix)
|
||||
val newFqName = if (prefix.isEmpty()) {
|
||||
val newContainerFqName = newContainer.fqName!!
|
||||
FqName(if (newContainerFqName.isRoot) it else "${newContainer.fqName!!.asString()}.$it")
|
||||
}
|
||||
else {
|
||||
FqName(it.replaceRange(prefixOffset..prefixOffset + prefix.length - 1, newContainer.fqName!!.asString()))
|
||||
}
|
||||
MoveRenameSelfUsageInfo(refExpr.mainReference, declaration, newFqName)
|
||||
}
|
||||
}
|
||||
|
||||
return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false, fqName.toSafe())
|
||||
if (isExtension || containerFqName != null || isImported(descriptor)) return {
|
||||
createMoveUsageInfoIfPossible(it.mainReference, declaration, false, this@lazilyProcessInternalReferencesToUpdateOnPackageNameChange)
|
||||
}
|
||||
|
||||
if (isExtension || containerFqName != null || isImported(descriptor)) return ::doCreateUsageInfo
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -216,49 +195,52 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
|
||||
class ImplicitCompanionAsDispatchReceiverUsageInfo(callee: KtSimpleNameExpression) : UsageInfo(callee)
|
||||
|
||||
interface InternableUsage {
|
||||
val scope: PsiElement?
|
||||
|
||||
fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo?
|
||||
}
|
||||
|
||||
class UnqualifiableMoveRenameUsageInfo(
|
||||
element: PsiElement,
|
||||
reference: PsiReference,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
referencedElement: PsiElement,
|
||||
val originalFile: PsiFile,
|
||||
val addImportToOriginalFile: Boolean
|
||||
): MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
|
||||
|
||||
class MoveRenameSelfUsageInfo(ref: KtSimpleNameReference, refTarget: PsiElement, val newFqName: FqName):
|
||||
MoveRenameUsageInfo(ref.element, ref, ref.rangeInElement.startOffset, ref.rangeInElement.endOffset, refTarget, false) {
|
||||
override fun getReference() = super.getReference() as? KtSimpleNameReference
|
||||
val addImportToOriginalFile: Boolean,
|
||||
override val scope: PsiElement?
|
||||
): MoveRenameUsageInfo(element, reference, reference.rangeInElement.startOffset, reference.rangeInElement.endOffset, referencedElement, false), InternableUsage {
|
||||
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
||||
return UnqualifiableMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, originalFile, addImportToOriginalFile, scope)
|
||||
}
|
||||
}
|
||||
|
||||
class QualifiableMoveRenameUsageInfo(
|
||||
element: PsiElement,
|
||||
reference: PsiReference,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
referencedElement: PsiElement,
|
||||
val newFqName: FqName?
|
||||
): MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
|
||||
override val scope: PsiElement?
|
||||
): MoveRenameUsageInfo(element, reference, reference.rangeInElement.startOffset, reference.rangeInElement.endOffset, referencedElement, false),
|
||||
InternableUsage {
|
||||
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
||||
return QualifiableMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, scope)
|
||||
}
|
||||
}
|
||||
|
||||
fun createMoveUsageInfoIfPossible(
|
||||
reference: PsiReference,
|
||||
referencedElement: PsiElement,
|
||||
addImportToOriginalFile: Boolean,
|
||||
newFqName: FqName?
|
||||
scope: PsiElement?
|
||||
): UsageInfo? {
|
||||
val element = reference.element
|
||||
if (element.getStrictParentOfType<KtSuperExpression>() != null) return null
|
||||
|
||||
val range = reference.rangeInElement!!
|
||||
val startOffset = range.startOffset
|
||||
val endOffset = range.endOffset
|
||||
|
||||
return when (getReferenceKind(reference, referencedElement)) {
|
||||
ReferenceKind.QUALIFIABLE -> QualifiableMoveRenameUsageInfo(
|
||||
element, reference, startOffset, endOffset, referencedElement, newFqName
|
||||
element, reference, referencedElement, scope
|
||||
)
|
||||
ReferenceKind.UNQUALIFIABLE -> UnqualifiableMoveRenameUsageInfo(
|
||||
element, reference, startOffset, endOffset, referencedElement, element.containingFile!!, addImportToOriginalFile
|
||||
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, scope
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
@@ -332,6 +314,48 @@ private fun updateJavaReference(reference: PsiReferenceExpression, oldElement: P
|
||||
return false
|
||||
}
|
||||
|
||||
private fun mapToNewOrThis(e: PsiElement, oldToNewElementsMapping: Map<PsiElement, PsiElement>) = oldToNewElementsMapping[e] ?: e
|
||||
|
||||
private fun postProcessMoveUsage(
|
||||
usage: UsageInfo,
|
||||
oldToNewElementsMapping: Map<PsiElement, PsiElement>,
|
||||
nonCodeUsages: ArrayList<NonCodeUsageInfo>,
|
||||
shorteningMode: ShorteningMode
|
||||
) {
|
||||
when (usage) {
|
||||
is NonCodeUsageInfo -> {
|
||||
nonCodeUsages.add(usage)
|
||||
}
|
||||
|
||||
is UnqualifiableMoveRenameUsageInfo -> {
|
||||
val file = with(usage) { if (addImportToOriginalFile) originalFile else mapToNewOrThis(originalFile, oldToNewElementsMapping) } as KtFile
|
||||
val declaration = mapToNewOrThis(usage.referencedElement!!, oldToNewElementsMapping)
|
||||
addDelayedImportRequest(declaration, file)
|
||||
}
|
||||
|
||||
is MoveRenameUsageInfo -> {
|
||||
val oldElement = usage.referencedElement!!
|
||||
val newElement = mapToNewOrThis(oldElement, oldToNewElementsMapping)
|
||||
val reference = usage.reference ?: (usage.element as? KtSimpleNameExpression)?.mainReference
|
||||
processReference(reference, newElement, shorteningMode, oldElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processReference(reference: PsiReference?, newElement: PsiElement, shorteningMode: ShorteningMode, oldElement: PsiElement) {
|
||||
try {
|
||||
when {
|
||||
reference is PsiMultiReference -> reference.references.forEach { processReference(it, newElement, shorteningMode, oldElement) }
|
||||
reference is KtSimpleNameReference -> reference.bindToElement(newElement, shorteningMode)
|
||||
reference is PsiReferenceExpression && updateJavaReference(reference, oldElement, newElement) -> return
|
||||
else -> reference?.bindToElement(newElement)
|
||||
}
|
||||
}
|
||||
catch (e: IncorrectOperationException) {
|
||||
// Suppress exception if bindToElement is not implemented
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform usage postprocessing and return non-code usages
|
||||
*/
|
||||
@@ -339,9 +363,7 @@ fun postProcessMoveUsages(usages: Collection<UsageInfo>,
|
||||
oldToNewElementsMapping: Map<PsiElement, PsiElement> = Collections.emptyMap(),
|
||||
shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING
|
||||
): List<NonCodeUsageInfo> {
|
||||
fun counterpart(e: PsiElement) = oldToNewElementsMapping[e] ?: e
|
||||
|
||||
val sortedUsages = usages.sortedWith(
|
||||
val sortedUsages = usages.sortedWith(
|
||||
Comparator<UsageInfo> { o1, o2 ->
|
||||
val file1 = o1.virtualFile
|
||||
val file2 = o2.virtualFile
|
||||
@@ -362,45 +384,7 @@ fun postProcessMoveUsages(usages: Collection<UsageInfo>,
|
||||
val nonCodeUsages = ArrayList<NonCodeUsageInfo>()
|
||||
|
||||
usageLoop@ for (usage in sortedUsages) {
|
||||
when (usage) {
|
||||
is NonCodeUsageInfo -> {
|
||||
nonCodeUsages.add(usage)
|
||||
}
|
||||
|
||||
is MoveRenameSelfUsageInfo -> {
|
||||
usage.reference?.bindToFqName(usage.newFqName, shorteningMode)
|
||||
}
|
||||
|
||||
is UnqualifiableMoveRenameUsageInfo -> {
|
||||
val file = with(usage) { if (addImportToOriginalFile) originalFile else counterpart(originalFile) } as KtFile
|
||||
val declaration = counterpart(usage.referencedElement!!)
|
||||
addDelayedImportRequest(declaration, file)
|
||||
}
|
||||
|
||||
is MoveRenameUsageInfo -> {
|
||||
val oldElement = usage.referencedElement!!
|
||||
val newElement = counterpart(oldElement)
|
||||
val reference = usage.reference ?: (usage.element as? KtSimpleNameExpression)?.mainReference
|
||||
try {
|
||||
when {
|
||||
reference is KtSimpleNameReference -> {
|
||||
val newFqName = (usage as? QualifiableMoveRenameUsageInfo)?.newFqName
|
||||
if (newFqName != null) {
|
||||
reference.bindToFqName(newFqName, shorteningMode)
|
||||
}
|
||||
else {
|
||||
reference.bindToElement(newElement, shorteningMode)
|
||||
}
|
||||
}
|
||||
reference is PsiReferenceExpression && updateJavaReference(reference, oldElement, newElement) -> continue@usageLoop
|
||||
else -> reference?.bindToElement(newElement)
|
||||
}
|
||||
}
|
||||
catch (e: IncorrectOperationException) {
|
||||
// Suppress exception if bindToElement is not implemented
|
||||
}
|
||||
}
|
||||
}
|
||||
postProcessMoveUsage(usage, oldToNewElementsMapping, nonCodeUsages, shorteningMode)
|
||||
}
|
||||
|
||||
return nonCodeUsages
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package pack
|
||||
|
||||
class C
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package pack2
|
||||
|
||||
import pack.C
|
||||
|
||||
class A {
|
||||
val a = A()
|
||||
val b = B()
|
||||
val c = C()
|
||||
}
|
||||
|
||||
class B {
|
||||
val a = A()
|
||||
val b = B()
|
||||
val c = C()
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package pack
|
||||
|
||||
class <caret>A {
|
||||
val a = A()
|
||||
val b = B()
|
||||
val c = C()
|
||||
}
|
||||
|
||||
class <caret>B {
|
||||
val a = A()
|
||||
val b = B()
|
||||
val c = C()
|
||||
}
|
||||
|
||||
class C
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mainFile": "pack/test.kt",
|
||||
"type": "MOVE_KOTLIN_TOP_LEVEL_DECLARATIONS",
|
||||
"targetPackage": "pack2"
|
||||
}
|
||||
@@ -534,6 +534,12 @@ public class MoveTestGenerated extends AbstractMoveTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/mutualDependency/mutualDependency.test")
|
||||
public void testKotlin_moveTopLevelDeclarations_misc_mutualDependency_MutualDependency() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/mutualDependency/mutualDependency.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