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 com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
|
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.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.core.copied
|
import org.jetbrains.kotlin.idea.core.copied
|
||||||
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
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.name.isOneSegmentFQN
|
||||||
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
|
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
|
||||||
import org.jetbrains.kotlin.psi.*
|
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.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
|
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
@@ -130,7 +132,6 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
|||||||
enum class ShorteningMode {
|
enum class ShorteningMode {
|
||||||
NO_SHORTENING,
|
NO_SHORTENING,
|
||||||
DELAYED_SHORTENING,
|
DELAYED_SHORTENING,
|
||||||
DELAYED_SHORTENING_VIA_USER_DATA,
|
|
||||||
FORCED_SHORTENING
|
FORCED_SHORTENING
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +160,6 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
|
|||||||
if (needToShorten) {
|
if (needToShorten) {
|
||||||
when (shorteningMode) {
|
when (shorteningMode) {
|
||||||
ShorteningMode.FORCED_SHORTENING -> ShortenReferences.DEFAULT.process(newQualifiedElement)
|
ShorteningMode.FORCED_SHORTENING -> ShortenReferences.DEFAULT.process(newQualifiedElement)
|
||||||
ShorteningMode.DELAYED_SHORTENING_VIA_USER_DATA -> newQualifiedElement.isToBeShortened = true
|
|
||||||
else -> newQualifiedElement.addToShorteningWaitSet()
|
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.ide.util.EditorHelper
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.openapi.util.Ref
|
import com.intellij.openapi.util.Ref
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.PsiElement
|
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.MoveMultipleElementsViewDescriptor
|
||||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler
|
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler
|
||||||
import com.intellij.refactoring.rename.RenameUtil
|
import com.intellij.refactoring.rename.RenameUtil
|
||||||
|
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||||
import com.intellij.refactoring.util.NonCodeUsageInfo
|
import com.intellij.refactoring.util.NonCodeUsageInfo
|
||||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
import com.intellij.refactoring.util.RefactoringUIUtil
|
||||||
import com.intellij.refactoring.util.TextOccurrencesUtil
|
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.fqName.getKotlinFqName
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.*
|
import org.jetbrains.kotlin.idea.refactoring.move.*
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinClassHandler
|
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.idea.search.projectScope
|
||||||
import org.jetbrains.kotlin.psi.*
|
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.containingClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
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(
|
class MoveDeclarationsDescriptor(
|
||||||
val elementsToMove: Collection<KtNamedDeclaration>,
|
val elementsToMove: Collection<KtNamedDeclaration>,
|
||||||
val moveTarget: KotlinMoveTarget,
|
val moveTarget: KotlinMoveTarget,
|
||||||
@@ -122,12 +126,6 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
|
|
||||||
fun getConflictsAsUsages(): List<UsageInfo> = conflicts.entrySet().map { ConflictUsageInfo(it.key, it.value) }
|
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> {
|
public override fun findUsages(): Array<UsageInfo> {
|
||||||
if (elementsToMove.isEmpty()) return UsageInfo.EMPTY_ARRAY
|
if (elementsToMove.isEmpty()) return UsageInfo.EMPTY_ARRAY
|
||||||
|
|
||||||
@@ -194,12 +192,8 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
conflictChecker.checkAllConflicts(externalUsages, internalUsages, conflicts)
|
conflictChecker.checkAllConflicts(externalUsages, internalUsages, conflicts)
|
||||||
descriptor.delegate.collectConflicts(descriptor, internalUsages, conflicts)
|
descriptor.delegate.collectConflicts(descriptor, internalUsages, conflicts)
|
||||||
|
|
||||||
|
usages += internalUsages
|
||||||
usages += externalUsages
|
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)
|
descriptor.delegate.collectConflicts(descriptor, usagesToProcessBeforeMove, conflicts)
|
||||||
@@ -212,32 +206,25 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun performRefactoring(usages: Array<out UsageInfo>) {
|
override fun performRefactoring(usages: Array<out UsageInfo>) {
|
||||||
fun moveDeclaration(declaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): KtNamedDeclaration? {
|
fun moveDeclaration(declaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): KtNamedDeclaration {
|
||||||
val file = declaration.containingFile as? KtFile
|
|
||||||
assert(file != null) { "${declaration::class.java}: ${declaration.text}" }
|
|
||||||
|
|
||||||
val targetContainer = moveTarget.getOrCreateTargetPsi(declaration)
|
val targetContainer = moveTarget.getOrCreateTargetPsi(declaration)
|
||||||
?: throw AssertionError("Couldn't create Kotlin file for: ${declaration::class.java}: ${declaration.text}")
|
?: throw AssertionError("Couldn't create Kotlin file for: ${declaration::class.java}: ${declaration.text}")
|
||||||
|
|
||||||
descriptor.delegate.preprocessDeclaration(descriptor, declaration)
|
descriptor.delegate.preprocessDeclaration(descriptor, declaration)
|
||||||
val newElement = mover(declaration, targetContainer)
|
return mover(declaration, targetContainer).apply {
|
||||||
|
addToBeShortenedDescendantsToWaitingSet()
|
||||||
newElement.addToBeShortenedDescendantsToWaitingSet()
|
}
|
||||||
|
|
||||||
return newElement
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
try {
|
||||||
val usageList = usages.toList()
|
descriptor.delegate.preprocessUsages(project, descriptor, usageList)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
val oldToNewElementsMapping = THashMap<PsiElement, PsiElement>(
|
val oldToNewElementsMapping = THashMap<PsiElement, PsiElement>(
|
||||||
object: TObjectHashingStrategy<PsiElement> {
|
object: TObjectHashingStrategy<PsiElement> {
|
||||||
@@ -259,18 +246,17 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val newDeclarations = ArrayList<KtNamedDeclaration>()
|
||||||
|
|
||||||
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
|
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
|
||||||
for ((oldDeclaration, oldLightElements) in kotlinToLightElements) {
|
for ((oldDeclaration, oldLightElements) in kotlinToLightElements) {
|
||||||
val elementListener = transaction!!.getElementListener(oldDeclaration)
|
val elementListener = transaction!!.getElementListener(oldDeclaration)
|
||||||
|
|
||||||
val newDeclaration = moveDeclaration(oldDeclaration, descriptor.moveTarget)
|
val newDeclaration = moveDeclaration(oldDeclaration, descriptor.moveTarget)
|
||||||
if (newDeclaration == null) {
|
newDeclarations += newDeclaration
|
||||||
for (oldElement in oldLightElements) {
|
|
||||||
oldToNewElementsMapping[oldElement] = oldElement
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
|
oldToNewElementsMapping[oldDeclaration] = newDeclaration
|
||||||
oldToNewElementsMapping[sourceFile] = newDeclaration.containingKtFile
|
oldToNewElementsMapping[sourceFile] = newDeclaration.containingKtFile
|
||||||
|
|
||||||
elementListener.elementMoved(newDeclaration)
|
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) {
|
catch (e: IncorrectOperationException) {
|
||||||
nonCodeUsages = null
|
nonCodeUsages = null
|
||||||
RefactoringUIUtil.processIncorrectOperation(myProject, e)
|
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() {
|
override fun performPsiSpoilingRefactoring() {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.ui.DialogWrapper
|
|||||||
import com.intellij.openapi.util.Comparing
|
import com.intellij.openapi.util.Comparing
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference
|
||||||
import com.intellij.refactoring.RefactoringBundle
|
import com.intellij.refactoring.RefactoringBundle
|
||||||
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
|
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
|
||||||
import com.intellij.refactoring.move.MoveCallback
|
import com.intellij.refactoring.move.MoveCallback
|
||||||
@@ -123,11 +124,9 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
val descriptor = bindingContext[BindingContext.REFERENCE_TARGET, refExpr]?.getImportableDescriptor() ?: return null
|
val descriptor = bindingContext[BindingContext.REFERENCE_TARGET, refExpr]?.getImportableDescriptor() ?: return null
|
||||||
val containingDescriptor = descriptor.containingDeclaration ?: 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 callableKind = (descriptor as? CallableMemberDescriptor)?.kind
|
||||||
val containingDeclarationForNonRealMember = if (callableKind != CallableMemberDescriptor.Kind.DECLARATION) {
|
if (callableKind != null && callableKind != CallableMemberDescriptor.Kind.DECLARATION) return null
|
||||||
DescriptorToSourceUtilsIde.getAnyDeclaration(project, containingDescriptor) as? KtClassOrObject
|
|
||||||
} else null
|
|
||||||
|
|
||||||
// Special case for enum entry superclass references (they have empty text and don't need to be processed by the refactoring)
|
// 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
|
if (refExpr.textRange.isEmpty) return null
|
||||||
@@ -156,13 +155,13 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val fqName = DescriptorUtils.getFqName(descriptor).let {
|
if (declaration is KtObjectDeclaration
|
||||||
if (DescriptorUtils.isCompanionObject(descriptor)
|
&& declaration.isCompanion()
|
||||||
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null) {
|
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null) {
|
||||||
it.parent()
|
declaration = declaration.containingClassOrObject ?: declaration
|
||||||
}
|
|
||||||
else it
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val fqName = DescriptorUtils.getFqName(descriptor)
|
||||||
if (!fqName.isSafe) return null
|
if (!fqName.isSafe) return null
|
||||||
|
|
||||||
val (oldContainer, newContainer) = containerChangeInfo
|
val (oldContainer, newContainer) = containerChangeInfo
|
||||||
@@ -178,30 +177,10 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
}
|
}
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
|
|
||||||
fun doCreateUsageInfo(refExpr: KtSimpleNameExpression): UsageInfo? {
|
if (isExtension || containerFqName != null || isImported(descriptor)) return {
|
||||||
// Check container instead of declaration itself as the latter may be not real (e.g. fake override)
|
createMoveUsageInfoIfPossible(it.mainReference, declaration, false, this@lazilyProcessInternalReferencesToUpdateOnPackageNameChange)
|
||||||
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 ::doCreateUsageInfo
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,49 +195,52 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
|
|
||||||
class ImplicitCompanionAsDispatchReceiverUsageInfo(callee: KtSimpleNameExpression) : UsageInfo(callee)
|
class ImplicitCompanionAsDispatchReceiverUsageInfo(callee: KtSimpleNameExpression) : UsageInfo(callee)
|
||||||
|
|
||||||
|
interface InternableUsage {
|
||||||
|
val scope: PsiElement?
|
||||||
|
|
||||||
|
fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo?
|
||||||
|
}
|
||||||
|
|
||||||
class UnqualifiableMoveRenameUsageInfo(
|
class UnqualifiableMoveRenameUsageInfo(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
reference: PsiReference,
|
reference: PsiReference,
|
||||||
startOffset: Int,
|
|
||||||
endOffset: Int,
|
|
||||||
referencedElement: PsiElement,
|
referencedElement: PsiElement,
|
||||||
val originalFile: PsiFile,
|
val originalFile: PsiFile,
|
||||||
val addImportToOriginalFile: Boolean
|
val addImportToOriginalFile: Boolean,
|
||||||
): MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
|
override val scope: PsiElement?
|
||||||
|
): MoveRenameUsageInfo(element, reference, reference.rangeInElement.startOffset, reference.rangeInElement.endOffset, referencedElement, false), InternableUsage {
|
||||||
class MoveRenameSelfUsageInfo(ref: KtSimpleNameReference, refTarget: PsiElement, val newFqName: FqName):
|
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
||||||
MoveRenameUsageInfo(ref.element, ref, ref.rangeInElement.startOffset, ref.rangeInElement.endOffset, refTarget, false) {
|
return UnqualifiableMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, originalFile, addImportToOriginalFile, scope)
|
||||||
override fun getReference() = super.getReference() as? KtSimpleNameReference
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class QualifiableMoveRenameUsageInfo(
|
class QualifiableMoveRenameUsageInfo(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
reference: PsiReference,
|
reference: PsiReference,
|
||||||
startOffset: Int,
|
|
||||||
endOffset: Int,
|
|
||||||
referencedElement: PsiElement,
|
referencedElement: PsiElement,
|
||||||
val newFqName: FqName?
|
override val scope: PsiElement?
|
||||||
): MoveRenameUsageInfo(element, reference, startOffset, endOffset, referencedElement, false)
|
): 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(
|
fun createMoveUsageInfoIfPossible(
|
||||||
reference: PsiReference,
|
reference: PsiReference,
|
||||||
referencedElement: PsiElement,
|
referencedElement: PsiElement,
|
||||||
addImportToOriginalFile: Boolean,
|
addImportToOriginalFile: Boolean,
|
||||||
newFqName: FqName?
|
scope: PsiElement?
|
||||||
): UsageInfo? {
|
): UsageInfo? {
|
||||||
val element = reference.element
|
val element = reference.element
|
||||||
if (element.getStrictParentOfType<KtSuperExpression>() != null) return null
|
if (element.getStrictParentOfType<KtSuperExpression>() != null) return null
|
||||||
|
|
||||||
val range = reference.rangeInElement!!
|
|
||||||
val startOffset = range.startOffset
|
|
||||||
val endOffset = range.endOffset
|
|
||||||
|
|
||||||
return when (getReferenceKind(reference, referencedElement)) {
|
return when (getReferenceKind(reference, referencedElement)) {
|
||||||
ReferenceKind.QUALIFIABLE -> QualifiableMoveRenameUsageInfo(
|
ReferenceKind.QUALIFIABLE -> QualifiableMoveRenameUsageInfo(
|
||||||
element, reference, startOffset, endOffset, referencedElement, newFqName
|
element, reference, referencedElement, scope
|
||||||
)
|
)
|
||||||
ReferenceKind.UNQUALIFIABLE -> UnqualifiableMoveRenameUsageInfo(
|
ReferenceKind.UNQUALIFIABLE -> UnqualifiableMoveRenameUsageInfo(
|
||||||
element, reference, startOffset, endOffset, referencedElement, element.containingFile!!, addImportToOriginalFile
|
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, scope
|
||||||
)
|
)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -332,6 +314,48 @@ private fun updateJavaReference(reference: PsiReferenceExpression, oldElement: P
|
|||||||
return false
|
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
|
* Perform usage postprocessing and return non-code usages
|
||||||
*/
|
*/
|
||||||
@@ -339,9 +363,7 @@ fun postProcessMoveUsages(usages: Collection<UsageInfo>,
|
|||||||
oldToNewElementsMapping: Map<PsiElement, PsiElement> = Collections.emptyMap(),
|
oldToNewElementsMapping: Map<PsiElement, PsiElement> = Collections.emptyMap(),
|
||||||
shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING
|
shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING
|
||||||
): List<NonCodeUsageInfo> {
|
): List<NonCodeUsageInfo> {
|
||||||
fun counterpart(e: PsiElement) = oldToNewElementsMapping[e] ?: e
|
val sortedUsages = usages.sortedWith(
|
||||||
|
|
||||||
val sortedUsages = usages.sortedWith(
|
|
||||||
Comparator<UsageInfo> { o1, o2 ->
|
Comparator<UsageInfo> { o1, o2 ->
|
||||||
val file1 = o1.virtualFile
|
val file1 = o1.virtualFile
|
||||||
val file2 = o2.virtualFile
|
val file2 = o2.virtualFile
|
||||||
@@ -362,45 +384,7 @@ fun postProcessMoveUsages(usages: Collection<UsageInfo>,
|
|||||||
val nonCodeUsages = ArrayList<NonCodeUsageInfo>()
|
val nonCodeUsages = ArrayList<NonCodeUsageInfo>()
|
||||||
|
|
||||||
usageLoop@ for (usage in sortedUsages) {
|
usageLoop@ for (usage in sortedUsages) {
|
||||||
when (usage) {
|
postProcessMoveUsage(usage, oldToNewElementsMapping, nonCodeUsages, shorteningMode)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nonCodeUsages
|
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);
|
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")
|
@TestMetadata("kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test")
|
||||||
public void testKotlin_moveTopLevelDeclarations_misc_selfReferences_SelfReferences() throws Exception {
|
public void testKotlin_moveTopLevelDeclarations_misc_selfReferences_SelfReferences() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/move/kotlin/moveTopLevelDeclarations/misc/selfReferences/selfReferences.test");
|
||||||
|
|||||||
Reference in New Issue
Block a user