Move: Nested classes support
#KT-9027 In Progress
This commit is contained in:
@@ -330,7 +330,7 @@
|
||||
order="before moveJavaFileOrDir"/>
|
||||
<refactoring.moveHandler
|
||||
id="kotlin.moveTopLevelDeclarations"
|
||||
implementation="org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsHandler"
|
||||
implementation="org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsHandler"
|
||||
order="before kotlin.moveFilesOrDirectories"/>
|
||||
<moveFileHandler implementation="org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.MoveKotlinFileHandler" />
|
||||
<refactoring.moveDirectoryWithClassesHelper
|
||||
@@ -1059,7 +1059,7 @@
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveDeclarationToSeparateFileIntention</className>
|
||||
<className>org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationToSeparateFileIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
|
||||
import org.jetbrains.kotlin.idea.refactoring.checkConflictsInteractively
|
||||
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.PackageNameInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.ContainerChangeInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.ContainerInfo
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.lazilyProcessInternalReferencesToUpdateOnPackageNameChange
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
@@ -167,7 +168,7 @@ class KotlinInlineValHandler : InlineActionHandler() {
|
||||
val targetPackages = referenceExpressions.mapNotNullTo(LinkedHashSet()) { (it.containingFile as? KtFile)?.packageFqName }
|
||||
for (targetPackage in targetPackages) {
|
||||
if (targetPackage == file.packageFqName) continue
|
||||
val packageNameInfo = PackageNameInfo(file.packageFqName, targetPackage.toUnsafe())
|
||||
val packageNameInfo = ContainerChangeInfo(ContainerInfo.Package(file.packageFqName), ContainerInfo.Package(targetPackage))
|
||||
initializer.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(packageNameInfo) { expr, factory ->
|
||||
val infos = expr.internalUsageInfos
|
||||
?: LinkedHashMap<FqName, (KtSimpleNameExpression) -> UsageInfo?>()
|
||||
|
||||
+15
-15
@@ -16,47 +16,47 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move
|
||||
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.refactoring.move.moveInner.MoveInnerClassUsagesHandler
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.references.matchesTarget
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.PsiWhiteSpace
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import java.util.*
|
||||
|
||||
class MoveJavaInnerClassKotlinUsagesHandler: MoveInnerClassUsagesHandler {
|
||||
override fun correctInnerClassUsage(usage: UsageInfo, outerClass: PsiClass) {
|
||||
val innerCall = usage.element?.parent as? KtCallExpression ?: return
|
||||
|
||||
val receiver = (innerCall.parent as? KtQualifiedExpression)?.receiverExpression
|
||||
val outerClassRef = when (receiver) {
|
||||
val receiver = (innerCall.parent as? KtQualifiedExpression)?.receiverExpression ?: return
|
||||
val outerClassRefExpr = when (receiver) {
|
||||
is KtCallExpression -> receiver.calleeExpression
|
||||
is KtQualifiedExpression -> receiver.getQualifiedElementSelector()
|
||||
else -> null
|
||||
} as? KtSimpleNameExpression
|
||||
if (outerClassRef?.mainReference?.resolve() != outerClass) return
|
||||
|
||||
val outerCall = outerClassRef!!.parent as? KtCallExpression ?: return
|
||||
val outerClassRef = outerClassRefExpr?.mainReference ?: return
|
||||
if (!outerClassRef.matchesTarget(outerClass)) return
|
||||
|
||||
val psiFactory = KtPsiFactory(usage.project)
|
||||
|
||||
val argumentList = innerCall.valueArgumentList
|
||||
if (argumentList != null) {
|
||||
val newArguments = ArrayList<String>()
|
||||
newArguments.add(outerCall.text!!)
|
||||
newArguments.add(receiver.text!!)
|
||||
argumentList.arguments.mapTo(newArguments) { it.text!! }
|
||||
argumentList.replace(psiFactory.createCallArguments(newArguments.joinToString(prefix = "(", postfix = ")")))
|
||||
}
|
||||
else {
|
||||
innerCall.lambdaArguments.firstOrNull()?.let { lambdaArg ->
|
||||
val anchor = PsiTreeUtil.skipSiblingsBackward(lambdaArg, PsiWhiteSpace::class.java)
|
||||
innerCall.addAfter(psiFactory.createCallArguments("(${outerCall.text})"), anchor)
|
||||
innerCall.addAfter(psiFactory.createCallArguments("(${receiver.text})"), anchor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-11
@@ -18,14 +18,11 @@ package org.jetbrains.kotlin.idea.refactoring.move.changePackage
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.refactoring.PackageWrapper
|
||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.runWithElementsToShortenIsEmptyIgnored
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.PackageNameInfo
|
||||
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.moveTopLevelDeclarations.KotlinMoveTarget
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsOptions
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsProcessor
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.Mover
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.postProcessMoveUsages
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -39,26 +36,28 @@ class KotlinChangePackageRefactoring(val file: KtFile) {
|
||||
val packageDirective = file.packageDirective ?: return
|
||||
val currentFqName = packageDirective.fqName
|
||||
|
||||
val declarationProcessor = MoveKotlinTopLevelDeclarationsProcessor(
|
||||
val declarationProcessor = MoveKotlinDeclarationsProcessor(
|
||||
project,
|
||||
MoveKotlinTopLevelDeclarationsOptions(
|
||||
MoveDeclarationsDescriptor(
|
||||
elementsToMove = file.declarations.filterIsInstance<KtNamedDeclaration>(),
|
||||
moveTarget = object: KotlinMoveTarget {
|
||||
override val packageWrapper = PackageWrapper(file.manager, newFqName.asString())
|
||||
override val targetContainerFqName = newFqName
|
||||
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile
|
||||
|
||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||
|
||||
override fun verify(file: PsiFile) = null
|
||||
},
|
||||
delegate = MoveDeclarationsDelegate.TopLevel,
|
||||
updateInternalReferences = false
|
||||
),
|
||||
Mover.Idle // we don't need to move any declarations physically
|
||||
)
|
||||
|
||||
val declarationUsages = declarationProcessor.findUsages().toList()
|
||||
val internalUsages = file.getInternalReferencesToUpdateOnPackageNameChange(PackageNameInfo(currentFqName, newFqName.toUnsafe()))
|
||||
val changeInfo = ContainerChangeInfo(ContainerInfo.Package(currentFqName), ContainerInfo.Package(newFqName))
|
||||
val internalUsages = file.getInternalReferencesToUpdateOnPackageNameChange(changeInfo)
|
||||
|
||||
project.executeWriteCommand("Change file's package to '${newFqName.asString()}'") {
|
||||
packageDirective.fqName = newFqName
|
||||
|
||||
+15
-21
@@ -14,56 +14,50 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.refactoring.PackageWrapper
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||
import java.util.HashMap
|
||||
import java.util.*
|
||||
|
||||
interface KotlinMoveTarget {
|
||||
val packageWrapper: PackageWrapper?
|
||||
fun getOrCreateTargetPsi(originalPsi: PsiElement): PsiFile?
|
||||
fun getTargetPsiIfExists(originalPsi: PsiElement): PsiFile?
|
||||
val targetContainerFqName: FqName?
|
||||
fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement?
|
||||
fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement?
|
||||
|
||||
// Check possible errors and return corresponding message, or null if no errors are detected
|
||||
fun verify(file: PsiFile): String?
|
||||
}
|
||||
|
||||
object EmptyKotlinMoveTarget: KotlinMoveTarget {
|
||||
override val packageWrapper: PackageWrapper? get() = null
|
||||
override val targetContainerFqName = null
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = null
|
||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
||||
override fun verify(file: PsiFile) = null
|
||||
}
|
||||
|
||||
class KotlinMoveTargetForExistingFile(val targetFile: KtFile): KotlinMoveTarget {
|
||||
override val packageWrapper: PackageWrapper? = targetFile.packageFqName.asString().let { packageName ->
|
||||
PackageWrapper(PsiManager.getInstance(targetFile.project), packageName)
|
||||
}
|
||||
class KotlinMoveTargetForExistingElement(val targetElement: KtElement): KotlinMoveTarget {
|
||||
override val targetContainerFqName = targetElement.getContainingKtFile().packageFqName
|
||||
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetFile
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = targetElement
|
||||
|
||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetFile
|
||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = targetElement
|
||||
|
||||
// No additional verification is needed
|
||||
override fun verify(file: PsiFile): String? = null
|
||||
}
|
||||
|
||||
class KotlinMoveTargetForDeferredFile(
|
||||
project: Project,
|
||||
private val packageFqName: FqName,
|
||||
private val createFile: (KtFile) -> KtFile?): KotlinMoveTarget {
|
||||
override val targetContainerFqName: FqName,
|
||||
private val createFile: (KtFile) -> KtFile?
|
||||
): KotlinMoveTarget {
|
||||
private val createdFiles = HashMap<KtFile, KtFile?>()
|
||||
|
||||
override val packageWrapper: PackageWrapper = PackageWrapper(PsiManager.getInstance(project), packageFqName.asString())
|
||||
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement): PsiFile? {
|
||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement? {
|
||||
val originalFile = originalPsi.containingFile as? KtFile ?: return null
|
||||
return createdFiles.getOrPutNullable(originalFile) { createFile(originalFile) }
|
||||
}
|
||||
+6
-5
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||
|
||||
import com.intellij.codeInsight.intention.LowPriorityAction
|
||||
import com.intellij.codeInsight.navigation.NavigationUtil
|
||||
@@ -27,7 +27,7 @@ import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
|
||||
import org.jetbrains.kotlin.idea.quickfix.moveCaret
|
||||
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
@@ -86,12 +86,13 @@ class MoveDeclarationToSeparateFileIntention :
|
||||
}
|
||||
return
|
||||
}
|
||||
val moveTarget = KotlinMoveTargetForDeferredFile(project, packageName) {
|
||||
val moveTarget = KotlinMoveTargetForDeferredFile(packageName) {
|
||||
createKotlinFile(targetFileName, directory, packageName.asString())
|
||||
}
|
||||
val moveOptions = MoveKotlinTopLevelDeclarationsOptions(
|
||||
val moveOptions = MoveDeclarationsDescriptor(
|
||||
elementsToMove = listOf(element),
|
||||
moveTarget = moveTarget,
|
||||
delegate = MoveDeclarationsDelegate.TopLevel,
|
||||
searchInCommentsAndStrings = false,
|
||||
searchInNonCode = false,
|
||||
updateInternalReferences = true,
|
||||
@@ -102,6 +103,6 @@ class MoveDeclarationToSeparateFileIntention :
|
||||
FileEditorManager.getInstance(project).selectedTextEditor?.moveCaret(newDeclaration.startOffset + originalOffset)
|
||||
}
|
||||
)
|
||||
MoveKotlinTopLevelDeclarationsProcessor(project, moveOptions).run()
|
||||
MoveKotlinDeclarationsProcessor(project, moveOptions).run()
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.refactoring.move.moveInner.MoveInnerClassUsagesHandler
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.*
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
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.getQualifiedExpressionForSelector
|
||||
|
||||
sealed class MoveDeclarationsDelegate {
|
||||
abstract fun getOriginalContainerFqName(descriptor: MoveDeclarationsDescriptor, originalFile: KtFile): FqName
|
||||
abstract fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo
|
||||
abstract fun findUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo>
|
||||
abstract fun collectConflicts(usages: MutableList<UsageInfo>, conflicts: MultiMap<PsiElement, String>)
|
||||
abstract fun preprocessDeclaration(descriptor: MoveDeclarationsDescriptor, originalDeclaration: KtNamedDeclaration)
|
||||
abstract fun preprocessUsages(project: Project, usages: List<UsageInfo>)
|
||||
|
||||
object TopLevel : MoveDeclarationsDelegate() {
|
||||
override fun getOriginalContainerFqName(descriptor: MoveDeclarationsDescriptor, originalFile: KtFile) = originalFile.packageFqName
|
||||
|
||||
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
|
||||
return ContainerChangeInfo(ContainerInfo.Package(originalDeclaration.getContainingKtFile().packageFqName),
|
||||
ContainerInfo.Package(moveTarget.targetContainerFqName!!))
|
||||
}
|
||||
|
||||
override fun findUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo> = emptyList()
|
||||
|
||||
override fun collectConflicts(usages: MutableList<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
|
||||
|
||||
}
|
||||
|
||||
override fun preprocessDeclaration(descriptor: MoveDeclarationsDescriptor, originalDeclaration: KtNamedDeclaration) {
|
||||
|
||||
}
|
||||
|
||||
override fun preprocessUsages(project: Project, usages: List<UsageInfo>) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class NestedClass(
|
||||
val newClassName: String? = null,
|
||||
val outerInstanceParameterName: String? = null
|
||||
) : MoveDeclarationsDelegate() {
|
||||
override fun getOriginalContainerFqName(descriptor: MoveDeclarationsDescriptor, originalFile: KtFile): FqName {
|
||||
return descriptor.elementsToMove.first().containingClassOrObject!!.fqName!!
|
||||
}
|
||||
|
||||
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
|
||||
val originalInfo = ContainerInfo.Class(originalDeclaration.containingClassOrObject!!.fqName!!)
|
||||
val movingToClass = (moveTarget as? KotlinMoveTargetForExistingElement)?.targetElement is KtClassOrObject
|
||||
val newInfo = if (movingToClass) {
|
||||
ContainerInfo.Class(moveTarget.targetContainerFqName!!)
|
||||
} else {
|
||||
ContainerInfo.Package(moveTarget.targetContainerFqName!!)
|
||||
}
|
||||
return ContainerChangeInfo(originalInfo, newInfo)
|
||||
}
|
||||
|
||||
override fun findUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo> {
|
||||
val classToMove = descriptor.elementsToMove.singleOrNull() as? KtClass ?: return emptyList()
|
||||
return collectOuterInstanceReferences(classToMove)
|
||||
}
|
||||
|
||||
override fun collectConflicts(usages: MutableList<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
|
||||
val usageIterator = usages.iterator()
|
||||
while (usageIterator.hasNext()) {
|
||||
val usage = usageIterator.next();
|
||||
val element = usage.element ?: continue
|
||||
|
||||
if (usage is ImplicitCompanionAsDispatchReceiverUsageInfo) {
|
||||
conflicts.putValue(element, "Implicit companion object will be inaccessible: ${element.text}")
|
||||
usageIterator.remove()
|
||||
continue
|
||||
}
|
||||
|
||||
if (usage !is OuterInstanceReferenceUsageInfo) continue
|
||||
|
||||
if (usage.isIndirectOuter) {
|
||||
conflicts.putValue(element, "Indirect outer instances won't be extracted: ${element.text}")
|
||||
usageIterator.remove()
|
||||
}
|
||||
|
||||
if (usage !is OuterInstanceReferenceUsageInfo.ImplicitReceiver) continue
|
||||
|
||||
val fullCall = usage.callElement?.let { it.getQualifiedExpressionForSelector() ?: it } ?: continue
|
||||
when {
|
||||
fullCall is KtQualifiedExpression -> {
|
||||
conflicts.putValue(
|
||||
fullCall,
|
||||
"Qualified call won't be processed: ${fullCall.text}"
|
||||
)
|
||||
usageIterator.remove()
|
||||
}
|
||||
|
||||
usage.isDoubleReceiver -> {
|
||||
conflicts.putValue(
|
||||
fullCall,
|
||||
"Call with two implicit receivers won't be processed: ${fullCall.text}"
|
||||
)
|
||||
usageIterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun preprocessDeclaration(descriptor: MoveDeclarationsDescriptor, originalDeclaration: KtNamedDeclaration) {
|
||||
with(originalDeclaration) {
|
||||
newClassName?.let { setName(it) }
|
||||
|
||||
if (this is KtClass) {
|
||||
if ((descriptor.moveTarget as? KotlinMoveTargetForExistingElement)?.targetElement !is KtClassOrObject) {
|
||||
if (hasModifier(KtTokens.INNER_KEYWORD)) removeModifier(KtTokens.INNER_KEYWORD)
|
||||
if (hasModifier(KtTokens.PROTECTED_KEYWORD)) removeModifier(KtTokens.PROTECTED_KEYWORD)
|
||||
}
|
||||
|
||||
if (outerInstanceParameterName != null) {
|
||||
val type = (containingClassOrObject!!.resolveToDescriptor() as ClassDescriptor).defaultType
|
||||
val parameter = KtPsiFactory(project)
|
||||
.createParameter("private val $outerInstanceParameterName: ${IdeDescriptorRenderers.SOURCE_CODE.renderType(type)}")
|
||||
createPrimaryConstructorParameterListIfAbsent().addParameter(parameter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun preprocessUsages(project: Project, usages: List<UsageInfo>) {
|
||||
if (outerInstanceParameterName == null) return
|
||||
val psiFactory = KtPsiFactory(project)
|
||||
val newOuterInstanceRef = psiFactory.createExpression(outerInstanceParameterName)
|
||||
|
||||
for (usage in usages) {
|
||||
val referencedNestedClass = (usage as? MoveRenameUsageInfo)?.referencedElement?.unwrapped as? KtClassOrObject
|
||||
val outerClass = referencedNestedClass?.containingClassOrObject
|
||||
val lightOuterClass = outerClass?.toLightClass()
|
||||
if (lightOuterClass != null) {
|
||||
MoveInnerClassUsagesHandler.EP_NAME
|
||||
.forLanguage(usage.element!!.language)
|
||||
?.correctInnerClassUsage(usage, lightOuterClass)
|
||||
}
|
||||
|
||||
when (usage) {
|
||||
is OuterInstanceReferenceUsageInfo.ExplicitThis -> {
|
||||
usage.expression?.replace(newOuterInstanceRef)
|
||||
}
|
||||
is OuterInstanceReferenceUsageInfo.ImplicitReceiver -> {
|
||||
usage.callElement?.let { it.replace(psiFactory.createExpressionByPattern("$0.$1", outerInstanceParameterName, it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys
|
||||
@@ -32,11 +32,11 @@ import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackages
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import org.jetbrains.kotlin.idea.core.getPackage
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import java.util.*
|
||||
|
||||
class MoveKotlinTopLevelDeclarationsHandler : MoveHandlerDelegate() {
|
||||
class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
|
||||
private fun getSourceDirectories(elements: Array<out PsiElement>) = elements.mapTo(LinkedHashSet()) { it.containingFile?.parent }
|
||||
|
||||
private fun doMoveWithCheck(
|
||||
+71
-51
@@ -14,8 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations
|
||||
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.Ref
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
@@ -25,16 +26,17 @@ import com.intellij.refactoring.BaseRefactoringProcessor
|
||||
import com.intellij.refactoring.move.MoveCallback
|
||||
import com.intellij.refactoring.move.MoveMultipleElementsViewDescriptor
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassHandler
|
||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesUtil
|
||||
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
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.usageView.UsageViewBundle
|
||||
import com.intellij.usageView.UsageViewDescriptor
|
||||
import com.intellij.usageView.UsageViewUtil
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.VisibilityUtil
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import gnu.trove.THashMap
|
||||
@@ -54,9 +56,8 @@ 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.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isInsideOf
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isPrivate
|
||||
@@ -64,58 +65,64 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
import java.util.*
|
||||
|
||||
interface Mover: (KtNamedDeclaration, KtFile) -> KtNamedDeclaration {
|
||||
object Default: Mover {
|
||||
override fun invoke(originalElement: KtNamedDeclaration, targetFile: KtFile): KtNamedDeclaration {
|
||||
val newElement = targetFile.add(originalElement) as KtNamedDeclaration
|
||||
originalElement.deleteSingle()
|
||||
return newElement
|
||||
interface Mover: (KtNamedDeclaration, KtElement) -> KtNamedDeclaration {
|
||||
object Default : Mover {
|
||||
override fun invoke(originalElement: KtNamedDeclaration, targetContainer: KtElement): KtNamedDeclaration {
|
||||
return when (targetContainer) {
|
||||
is KtFile -> targetContainer.add(originalElement) as KtNamedDeclaration
|
||||
is KtClassOrObject -> targetContainer.addDeclaration(originalElement) as KtNamedDeclaration
|
||||
else -> error("Unexpected element: ${targetContainer.getElementTextWithContext()}")
|
||||
}.apply { originalElement.deleteSingle() }
|
||||
}
|
||||
}
|
||||
|
||||
object Idle: Mover {
|
||||
override fun invoke(originalElement: KtNamedDeclaration, targetFile: KtFile) = originalElement
|
||||
object Idle : Mover {
|
||||
override fun invoke(originalElement: KtNamedDeclaration, targetContainer: KtElement) = originalElement
|
||||
}
|
||||
}
|
||||
|
||||
class MoveKotlinTopLevelDeclarationsOptions(
|
||||
class MoveDeclarationsDescriptor(
|
||||
val elementsToMove: Collection<KtNamedDeclaration>,
|
||||
val moveTarget: KotlinMoveTarget,
|
||||
val delegate: MoveDeclarationsDelegate,
|
||||
val searchInCommentsAndStrings: Boolean = true,
|
||||
val searchInNonCode: Boolean = true,
|
||||
val updateInternalReferences: Boolean = true,
|
||||
val deleteSourceFiles: Boolean = false,
|
||||
val moveCallback: MoveCallback? = null
|
||||
val moveCallback: MoveCallback? = null,
|
||||
val openInEditor: Boolean = false
|
||||
)
|
||||
|
||||
class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
class MoveKotlinDeclarationsProcessor(
|
||||
val project: Project,
|
||||
val options: MoveKotlinTopLevelDeclarationsOptions,
|
||||
val descriptor: MoveDeclarationsDescriptor,
|
||||
val mover: Mover = Mover.Default) : BaseRefactoringProcessor(project) {
|
||||
companion object {
|
||||
private val REFACTORING_NAME: String = KotlinRefactoringBundle.message("refactoring.move.top.level.declarations")
|
||||
}
|
||||
|
||||
private var nonCodeUsages: Array<NonCodeUsageInfo>? = null
|
||||
private val elementsToMove = options.elementsToMove.filter { e -> e.containingFile != options.moveTarget.getTargetPsiIfExists(e) }
|
||||
private val elementsToMove = descriptor.elementsToMove.filter { e -> e.parent != descriptor.moveTarget.getTargetPsiIfExists(e) }
|
||||
private val kotlinToLightElementsBySourceFile = elementsToMove
|
||||
.groupBy { it.getContainingKtFile() }
|
||||
.mapValues { it.value.keysToMap { it.toLightElements() } }
|
||||
private val conflicts = MultiMap<PsiElement, String>()
|
||||
|
||||
override fun createUsageViewDescriptor(usages: Array<out UsageInfo>): UsageViewDescriptor {
|
||||
return MoveMultipleElementsViewDescriptor(
|
||||
elementsToMove.toTypedArray(),
|
||||
MoveClassesOrPackagesUtil.getPackageName(options.moveTarget.packageWrapper)
|
||||
)
|
||||
val targetContainerFqName = descriptor.moveTarget.targetContainerFqName?.let {
|
||||
if (it.isRoot) UsageViewBundle.message("default.package.presentable.name") else it.asString()
|
||||
}
|
||||
return MoveMultipleElementsViewDescriptor(elementsToMove.toTypedArray(), targetContainerFqName)
|
||||
}
|
||||
|
||||
private val usagesToProcessBeforeMove = SmartList<UsageInfo>()
|
||||
|
||||
public override fun findUsages(): Array<UsageInfo> {
|
||||
val newPackageName = options.moveTarget.packageWrapper?.qualifiedName ?: ""
|
||||
val newContainerName = descriptor.moveTarget.targetContainerFqName?.asString() ?: ""
|
||||
|
||||
fun collectUsages(kotlinToLightElements: Map<KtNamedDeclaration, List<PsiNamedElement>>, result: MutableList<UsageInfo>) {
|
||||
kotlinToLightElements.values.flatMap { it }.flatMapTo(result) { lightElement ->
|
||||
val newFqName = StringUtil.getQualifiedName(newPackageName, lightElement.name)
|
||||
val newFqName = StringUtil.getQualifiedName(newContainerName, lightElement.name)
|
||||
|
||||
val foundReferences = HashSet<PsiReference>()
|
||||
val projectScope = lightElement.project.projectScope()
|
||||
@@ -133,8 +140,8 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
TextOccurrencesUtil.findNonCodeUsages(
|
||||
lightElement,
|
||||
name,
|
||||
options.searchInCommentsAndStrings,
|
||||
options.searchInNonCode,
|
||||
descriptor.searchInCommentsAndStrings,
|
||||
descriptor.searchInNonCode,
|
||||
newFqName,
|
||||
results
|
||||
)
|
||||
@@ -169,8 +176,9 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
val container = element.getUsageContext()
|
||||
if (!declarationToContainers.getOrPut(declaration) { HashSet<PsiElement>() }.add(container)) continue
|
||||
|
||||
// todo: ok for now, will be replaced by proper visibility analysis
|
||||
val currentPackage = element.containingFile?.containingDirectory?.getPackage()
|
||||
if (currentPackage?.qualifiedName == newPackageName) continue
|
||||
if (currentPackage?.qualifiedName == newContainerName) continue
|
||||
|
||||
conflicts.putValue(
|
||||
declaration,
|
||||
@@ -184,7 +192,7 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
}
|
||||
|
||||
fun collectConflictsInDeclarations() {
|
||||
if (newPackageName == UNKNOWN_PACKAGE_FQ_NAME.asString()) return
|
||||
if (newContainerName == UNKNOWN_PACKAGE_FQ_NAME.asString()) return
|
||||
|
||||
val declarationToReferenceTargets = HashMap<KtNamedDeclaration, MutableSet<PsiElement>>()
|
||||
for (declaration in elementsToMove) {
|
||||
@@ -207,8 +215,9 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
|
||||
if (!declarationToReferenceTargets.getOrPut(declaration) { HashSet<PsiElement>() }.add(refTarget)) continue
|
||||
|
||||
// todo: ok for now, will be replaced by proper visibility analysis
|
||||
val currentPackage = declaration.containingFile?.containingDirectory?.getPackage()
|
||||
if (currentPackage?.qualifiedName == newPackageName) continue
|
||||
if (currentPackage?.qualifiedName == newContainerName) continue
|
||||
|
||||
conflicts.putValue(
|
||||
declaration,
|
||||
@@ -224,14 +233,29 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
|
||||
val usages = ArrayList<UsageInfo>()
|
||||
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
|
||||
// No need to find and process usages if package is not changed
|
||||
if (sourceFile.packageFqName.asString() == newPackageName) return UsageInfo.EMPTY_ARRAY
|
||||
kotlinToLightElements.keys.forEach {
|
||||
if (descriptor.updateInternalReferences) {
|
||||
val packageNameInfo = descriptor.delegate.getContainerChangeInfo(it, descriptor.moveTarget)
|
||||
val (usagesToProcessLater, usagesToProcessEarly) = it
|
||||
.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo)
|
||||
.partition { it is MoveRenameUsageInfoForExtension }
|
||||
usages.addAll(usagesToProcessLater)
|
||||
usagesToProcessBeforeMove.addAll(usagesToProcessEarly)
|
||||
}
|
||||
}
|
||||
|
||||
// No need to find and process usages if package is not changed
|
||||
val originalContainerName = descriptor.delegate.getOriginalContainerFqName(descriptor, sourceFile).asString()
|
||||
if (originalContainerName == newContainerName) return UsageInfo.EMPTY_ARRAY
|
||||
|
||||
usages += descriptor.delegate.findUsages(descriptor)
|
||||
collectUsages(kotlinToLightElements, usages)
|
||||
collectConflictsInUsages(usages)
|
||||
collectConflictsInDeclarations()
|
||||
descriptor.delegate.collectConflicts(usages, conflicts)
|
||||
}
|
||||
|
||||
descriptor.delegate.collectConflicts(usagesToProcessBeforeMove, conflicts)
|
||||
|
||||
return UsageViewUtil.removeDuplicatedUsages(usages.toTypedArray())
|
||||
}
|
||||
@@ -241,27 +265,15 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
}
|
||||
|
||||
override fun performRefactoring(usages: Array<out UsageInfo>) {
|
||||
fun moveDeclaration(
|
||||
declaration: KtNamedDeclaration,
|
||||
moveTarget: KotlinMoveTarget,
|
||||
usagesToProcessAfterMove: MutableList<UsageInfo>
|
||||
): KtNamedDeclaration? {
|
||||
fun moveDeclaration(declaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): KtNamedDeclaration? {
|
||||
val file = declaration.containingFile as? KtFile
|
||||
assert(file != null) { "${declaration.javaClass}: ${declaration.text}" }
|
||||
|
||||
val targetFile = moveTarget.getOrCreateTargetPsi(declaration) as? KtFile
|
||||
?: throw AssertionError("Couldn't create Kotlin file for: ${declaration.javaClass}: ${declaration.text}")
|
||||
val targetContainer = moveTarget.getOrCreateTargetPsi(declaration)
|
||||
?: throw AssertionError("Couldn't create Kotlin file for: ${declaration.javaClass}: ${declaration.text}")
|
||||
|
||||
if (options.updateInternalReferences) {
|
||||
val packageNameInfo = PackageNameInfo(file!!.packageFqName, targetFile.packageFqName.toUnsafe())
|
||||
val (usagesToProcessLater, usagesToProcessNow) = declaration
|
||||
.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo)
|
||||
.partition { it is MoveRenameUsageInfoForExtension }
|
||||
postProcessMoveUsages(usagesToProcessNow, shorteningMode = ShorteningMode.NO_SHORTENING)
|
||||
usagesToProcessAfterMove.addAll(usagesToProcessLater)
|
||||
}
|
||||
|
||||
val newElement = mover(declaration, targetFile)
|
||||
descriptor.delegate.preprocessDeclaration(descriptor, declaration)
|
||||
val newElement = mover(declaration, targetContainer)
|
||||
|
||||
newElement.addToShorteningWaitSet()
|
||||
|
||||
@@ -271,6 +283,10 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
try {
|
||||
val usageList = usages.toArrayList()
|
||||
|
||||
descriptor.delegate.preprocessUsages(project, usageList)
|
||||
|
||||
postProcessMoveUsages(usagesToProcessBeforeMove, shorteningMode = ShorteningMode.NO_SHORTENING)
|
||||
|
||||
val oldToNewElementsMapping = THashMap<PsiElement, PsiElement>(
|
||||
object: TObjectHashingStrategy<PsiElement> {
|
||||
override fun equals(e1: PsiElement?, e2: PsiElement?): Boolean {
|
||||
@@ -293,7 +309,7 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
)
|
||||
for ((sourceFile, kotlinToLightElements) in kotlinToLightElementsBySourceFile) {
|
||||
for ((oldDeclaration, oldLightElements) in kotlinToLightElements) {
|
||||
val newDeclaration = moveDeclaration(oldDeclaration, options.moveTarget, usageList)
|
||||
val newDeclaration = moveDeclaration(oldDeclaration, descriptor.moveTarget)
|
||||
if (newDeclaration == null) {
|
||||
for (oldElement in oldLightElements) {
|
||||
oldToNewElementsMapping[oldElement] = oldElement
|
||||
@@ -307,9 +323,13 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
for ((oldElement, newElement) in oldLightElements.asSequence().zip(newDeclaration.toLightElements().asSequence())) {
|
||||
oldToNewElementsMapping[oldElement] = newElement
|
||||
}
|
||||
|
||||
if (descriptor.openInEditor) {
|
||||
EditorHelper.openInEditor(newDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
if (options.deleteSourceFiles) {
|
||||
if (descriptor.deleteSourceFiles) {
|
||||
sourceFile.delete()
|
||||
}
|
||||
}
|
||||
@@ -324,7 +344,7 @@ class MoveKotlinTopLevelDeclarationsProcessor(
|
||||
|
||||
override fun performPsiSpoilingRefactoring() {
|
||||
nonCodeUsages?.let { nonCodeUsages -> RenameUtil.renameNonCodeUsages(myProject, nonCodeUsages) }
|
||||
options.moveCallback?.refactoringCompleted()
|
||||
descriptor.moveCallback?.refactoringCompleted()
|
||||
}
|
||||
|
||||
fun execute(usages: List<UsageInfo>) {
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui
|
||||
|
||||
import com.intellij.ide.util.DirectoryUtil
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog">
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.MoveKotlinTopLevelDeclarationsDialog">
|
||||
<grid id="1a398" binding="mainPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<xy x="10" y="10" width="472" height="414"/>
|
||||
+14
-8
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui;
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
@@ -69,7 +69,7 @@ import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.MoveUtilsKt;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*;
|
||||
import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
@@ -533,7 +533,6 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
}
|
||||
|
||||
return new KotlinMoveTargetForDeferredFile(
|
||||
myProject,
|
||||
new FqName(getTargetPackage()),
|
||||
new Function1<KtFile, KtFile>() {
|
||||
@Override
|
||||
@@ -556,7 +555,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new KotlinMoveTargetForExistingFile(jetFile);
|
||||
return new KotlinMoveTargetForExistingElement(jetFile);
|
||||
}
|
||||
|
||||
File targetDir = targetFile.getParentFile();
|
||||
@@ -570,7 +569,6 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
}
|
||||
|
||||
return new KotlinMoveTargetForDeferredFile(
|
||||
myProject,
|
||||
new FqName(psiPackage.getQualifiedName()),
|
||||
new Function1<KtFile, KtFile>() {
|
||||
@Override
|
||||
@@ -757,10 +755,18 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
deleteSourceFile = ret == Messages.YES;
|
||||
}
|
||||
|
||||
MoveKotlinTopLevelDeclarationsOptions options = new MoveKotlinTopLevelDeclarationsOptions(
|
||||
elementsToMove, target, isSearchInComments(), isSearchInNonJavaFiles(), true, deleteSourceFile, moveCallback
|
||||
MoveDeclarationsDescriptor options = new MoveDeclarationsDescriptor(
|
||||
elementsToMove,
|
||||
target,
|
||||
MoveDeclarationsDelegate.TopLevel.INSTANCE,
|
||||
isSearchInComments(),
|
||||
isSearchInNonJavaFiles(),
|
||||
true,
|
||||
deleteSourceFile,
|
||||
moveCallback,
|
||||
false
|
||||
);
|
||||
invokeRefactoring(new MoveKotlinTopLevelDeclarationsProcessor(myProject, options, Mover.Default.INSTANCE));
|
||||
invokeRefactoring(new MoveKotlinDeclarationsProcessor(myProject, options, Mover.Default.INSTANCE));
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.getMessage(), null, myProject);
|
||||
+3
-3
@@ -27,7 +27,7 @@ import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.util.Function
|
||||
import org.jetbrains.kotlin.idea.core.getPackage
|
||||
import org.jetbrains.kotlin.idea.refactoring.invokeOnceOnCommandFinish
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveKotlinTopLevelDeclarationsProcessor
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.ArrayList
|
||||
@@ -37,13 +37,13 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
||||
private class FileUsagesWrapper(
|
||||
val psiFile: PsiFile,
|
||||
val usages: List<UsageInfo>,
|
||||
val moveDeclarationsProcessor: MoveKotlinTopLevelDeclarationsProcessor?
|
||||
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
||||
) : UsageInfo(psiFile)
|
||||
|
||||
private class MoveContext(
|
||||
val newParent: PsiDirectory,
|
||||
val internalUsages: MoveKotlinFileHandler.InternalUsagesWrapper,
|
||||
val moveDeclarationsProcessor: MoveKotlinTopLevelDeclarationsProcessor?
|
||||
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
||||
)
|
||||
|
||||
private val fileHandler = MoveKotlinFileHandler()
|
||||
|
||||
+17
-17
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.idea.core.getPackage
|
||||
import org.jetbrains.kotlin.idea.core.packageMatchesDirectory
|
||||
import org.jetbrains.kotlin.idea.refactoring.hasIdentifiersOnly
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
@@ -42,48 +42,50 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
||||
// so that it can be kept in the transition map
|
||||
private class MoveContext(
|
||||
psiManager: PsiManager,
|
||||
val declarationMoveProcessor: MoveKotlinTopLevelDeclarationsProcessor
|
||||
val declarationMoveProcessor: MoveKotlinDeclarationsProcessor
|
||||
): LightElement(psiManager, KotlinLanguage.INSTANCE) {
|
||||
override fun toString() = ""
|
||||
}
|
||||
|
||||
private fun KtFile.getPackageNameInfo(newParent: PsiDirectory?, clearUserData: Boolean): PackageNameInfo? {
|
||||
private fun KtFile.getPackageNameInfo(newParent: PsiDirectory?, clearUserData: Boolean): ContainerChangeInfo? {
|
||||
val shouldUpdatePackageDirective = updatePackageDirective ?: packageMatchesDirectory()
|
||||
updatePackageDirective = if (clearUserData) null else shouldUpdatePackageDirective
|
||||
|
||||
if (!shouldUpdatePackageDirective) return null
|
||||
|
||||
val oldPackageName = packageFqName
|
||||
val newPackage = newParent?.getPackage() ?: return PackageNameInfo(oldPackageName, UNKNOWN_PACKAGE_FQ_NAME)
|
||||
val newPackage = newParent?.getPackage() ?: return ContainerChangeInfo(ContainerInfo.Package(oldPackageName),
|
||||
ContainerInfo.UnknownPackage)
|
||||
|
||||
val newPackageName = FqNameUnsafe(newPackage.qualifiedName)
|
||||
if (oldPackageName.asString() == newPackageName.asString()) return null
|
||||
if (newPackageName != UNKNOWN_PACKAGE_FQ_NAME && !newPackageName.hasIdentifiersOnly()) return null
|
||||
if (!newPackageName.hasIdentifiersOnly()) return null
|
||||
|
||||
return PackageNameInfo(oldPackageName, newPackageName)
|
||||
return ContainerChangeInfo(ContainerInfo.Package(oldPackageName), ContainerInfo.Package(newPackageName.toSafe()))
|
||||
}
|
||||
|
||||
fun initMoveProcessor(psiFile: PsiFile, newParent: PsiDirectory?): MoveKotlinTopLevelDeclarationsProcessor? {
|
||||
fun initMoveProcessor(psiFile: PsiFile, newParent: PsiDirectory?): MoveKotlinDeclarationsProcessor? {
|
||||
if (psiFile !is KtFile) return null
|
||||
val packageNameInfo = psiFile.getPackageNameInfo(newParent, false) ?: return null
|
||||
|
||||
val project = psiFile.project
|
||||
|
||||
val newPackageName = packageNameInfo.newPackageName
|
||||
val moveTarget = when (newPackageName) {
|
||||
UNKNOWN_PACKAGE_FQ_NAME -> EmptyKotlinMoveTarget
|
||||
val newPackage = packageNameInfo.newContainer
|
||||
val moveTarget = when (newPackage) {
|
||||
ContainerInfo.UnknownPackage -> EmptyKotlinMoveTarget
|
||||
|
||||
else -> KotlinMoveTargetForDeferredFile(project, newPackageName.toSafe()) {
|
||||
else -> KotlinMoveTargetForDeferredFile(newPackage.fqName!!) {
|
||||
MoveFilesOrDirectoriesUtil.doMoveFile(psiFile, newParent)
|
||||
newParent?.findFile(psiFile.name) as? KtFile
|
||||
}
|
||||
}
|
||||
|
||||
val declarationMoveProcessor = MoveKotlinTopLevelDeclarationsProcessor(
|
||||
val declarationMoveProcessor = MoveKotlinDeclarationsProcessor(
|
||||
project,
|
||||
MoveKotlinTopLevelDeclarationsOptions(
|
||||
MoveDeclarationsDescriptor(
|
||||
elementsToMove = psiFile.declarations.filterIsInstance<KtNamedDeclaration>(),
|
||||
moveTarget = moveTarget,
|
||||
delegate = MoveDeclarationsDelegate.TopLevel,
|
||||
updateInternalReferences = false
|
||||
),
|
||||
Mover.Idle
|
||||
@@ -126,9 +128,7 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
||||
if (file !is KtFile) return
|
||||
val newDirectory = file.parent ?: return
|
||||
val packageNameInfo = file.getPackageNameInfo(newDirectory, true) ?: return
|
||||
val newPackageName = packageNameInfo.newPackageName
|
||||
assert(newPackageName.isSafe) { newPackageName }
|
||||
file.packageDirective?.fqName = newPackageName.toSafe()
|
||||
file.packageDirective?.fqName = packageNameInfo.newContainer.fqName!!
|
||||
}
|
||||
|
||||
override fun retargetUsages(usageInfos: List<UsageInfo>?, oldToNewMap: Map<PsiElement, PsiElement>) {
|
||||
@@ -136,7 +136,7 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
||||
retargetUsages(usageInfos, moveContext.declarationMoveProcessor)
|
||||
}
|
||||
|
||||
fun retargetUsages(usageInfos: List<UsageInfo>?, moveDeclarationsProcessor: MoveKotlinTopLevelDeclarationsProcessor) {
|
||||
fun retargetUsages(usageInfos: List<UsageInfo>?, moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor) {
|
||||
postProcessMoveUsages(usageInfos?.firstIsInstanceOrNull<InternalUsagesWrapper>()?.usages ?: emptyList())
|
||||
moveDeclarationsProcessor.project.runWithElementsToShortenIsEmptyIgnored {
|
||||
usageInfos?.let { moveDeclarationsProcessor.execute(it) }
|
||||
|
||||
@@ -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.util.PsiTreeUtil
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.RefactoringSettings
|
||||
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
|
||||
@@ -36,17 +37,20 @@ import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||
import com.intellij.refactoring.util.NonCodeUsageInfo
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.codeInsight.KotlinFileReferencesResolver
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
|
||||
import org.jetbrains.kotlin.idea.refactoring.isInJavaSourceRoot
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesDialog
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
|
||||
@@ -60,22 +64,48 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
val UNKNOWN_PACKAGE_FQ_NAME = FqNameUnsafe("org.jetbrains.kotlin.idea.refactoring.move.<unknown-package>")
|
||||
|
||||
class PackageNameInfo(val oldPackageName: FqName, val newPackageName: FqNameUnsafe)
|
||||
sealed class ContainerInfo() {
|
||||
abstract val fqName: FqName?
|
||||
abstract fun matches(descriptor: DeclarationDescriptor): Boolean
|
||||
|
||||
fun KtElement.getInternalReferencesToUpdateOnPackageNameChange(packageNameInfo: PackageNameInfo): List<UsageInfo> {
|
||||
object UnknownPackage : ContainerInfo() {
|
||||
override val fqName = null
|
||||
override fun matches(descriptor: DeclarationDescriptor) = descriptor is PackageViewDescriptor
|
||||
}
|
||||
|
||||
class Package(override val fqName: FqName): ContainerInfo() {
|
||||
override fun matches(descriptor: DeclarationDescriptor): Boolean {
|
||||
return descriptor is PackageFragmentDescriptor && descriptor.fqName == fqName
|
||||
}
|
||||
}
|
||||
|
||||
class Class(override val fqName: FqName) : ContainerInfo() {
|
||||
override fun matches(descriptor: DeclarationDescriptor): Boolean {
|
||||
return descriptor is ClassDescriptor && descriptor.importableFqName == fqName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ContainerChangeInfo(val oldContainer: ContainerInfo, val newContainer: ContainerInfo)
|
||||
|
||||
fun KtElement.getInternalReferencesToUpdateOnPackageNameChange(containerChangeInfo: ContainerChangeInfo): List<UsageInfo> {
|
||||
val usages = ArrayList<UsageInfo>()
|
||||
lazilyProcessInternalReferencesToUpdateOnPackageNameChange(packageNameInfo) { expr, factory -> usages.addIfNotNull(factory(expr)) }
|
||||
lazilyProcessInternalReferencesToUpdateOnPackageNameChange(containerChangeInfo) { expr, factory -> usages.addIfNotNull(factory(expr)) }
|
||||
return usages
|
||||
}
|
||||
|
||||
fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
packageNameInfo: PackageNameInfo,
|
||||
containerChangeInfo: ContainerChangeInfo,
|
||||
body: (originalRefExpr: KtSimpleNameExpression, usageFactory: (KtSimpleNameExpression) -> UsageInfo?) -> Unit
|
||||
) {
|
||||
val file = containingFile as? KtFile ?: return
|
||||
@@ -99,46 +129,61 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: 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
|
||||
}
|
||||
if (refExpr.textRange.isEmpty) return null
|
||||
|
||||
if (descriptor is ClassDescriptor && descriptor.isInner && refExpr.parent is KtCallExpression) return null
|
||||
|
||||
val isCallable = descriptor is CallableDescriptor
|
||||
val isExtension = isCallable && declaration.isExtensionDeclaration()
|
||||
|
||||
if (isCallable && !isExtension) {
|
||||
if (isCallable) {
|
||||
val containingDescriptor = descriptor.containingDeclaration
|
||||
if (refExpr.getReceiverExpression() != null) {
|
||||
return fun(refExpr: KtSimpleNameExpression): UsageInfo? {
|
||||
val receiver = refExpr.getReceiverExpression() ?: return null
|
||||
val receiverRef = receiver.getQualifiedElementSelector() as? KtSimpleNameExpression ?: return null
|
||||
if (bindingContext[BindingContext.QUALIFIER, receiverRef] == null) return null
|
||||
return processReference(receiverRef, bindingContext)?.invoke(receiverRef)
|
||||
if (isExtension && containingDescriptor is ClassDescriptor) {
|
||||
val implicitClass = (refExpr.getResolvedCall(bindingContext)?.dispatchReceiver as? ImplicitClassReceiver)?.classDescriptor
|
||||
if (DescriptorUtils.isCompanionObject(implicitClass)) {
|
||||
return { ImplicitCompanionAsDispatchReceiverUsageInfo(it) }
|
||||
}
|
||||
return null
|
||||
}
|
||||
if (!isExtension) {
|
||||
if (refExpr.getReceiverExpression() != null) {
|
||||
return fun(refExpr: KtSimpleNameExpression): UsageInfo? {
|
||||
val receiver = refExpr.getReceiverExpression() ?: return null
|
||||
val receiverRef = receiver.getQualifiedElementSelector() as? KtSimpleNameExpression ?: return null
|
||||
if (bindingContext[BindingContext.QUALIFIER, receiverRef] == null) return null
|
||||
return processReference(receiverRef, bindingContext)?.invoke(receiverRef)
|
||||
}
|
||||
}
|
||||
if (!(containingDescriptor is PackageFragmentDescriptor
|
||||
|| containingDescriptor is ClassDescriptor && containingDescriptor.kind == ClassKind.OBJECT)) return null
|
||||
}
|
||||
if (containingDescriptor !is PackageFragmentDescriptor) return null
|
||||
}
|
||||
|
||||
val fqName = DescriptorUtils.getFqName(descriptor)
|
||||
if (!fqName.isSafe) return null
|
||||
|
||||
val packageName = DescriptorUtils.getParentOfType(descriptor, PackageFragmentDescriptor::class.java, false)?.let {
|
||||
DescriptorUtils.getFqName(it).toSafe()
|
||||
}
|
||||
val (oldContainer, newContainer) = containerChangeInfo
|
||||
|
||||
val oldPackageName = packageNameInfo.oldPackageName
|
||||
val newPackageName = packageNameInfo.newPackageName
|
||||
val containerFqName = descriptor
|
||||
.parents
|
||||
.mapNotNull {
|
||||
when {
|
||||
oldContainer.matches(it) -> oldContainer.fqName
|
||||
newContainer.matches(it) -> newContainer.fqName
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
.firstOrNull()
|
||||
|
||||
fun doCreateUsageInfo(refExpr: KtSimpleNameExpression): UsageInfo? {
|
||||
if (isAncestor(declaration, false)) {
|
||||
if (descriptor.importableFqName == null) return null
|
||||
if (descriptor is ClassDescriptor && descriptor.isInner && refExpr.parent is KtCallExpression) return null
|
||||
if (isUnqualifiedExtensionReference(refExpr.mainReference, declaration)) return null
|
||||
if (packageName == null || !newPackageName.isSafe) return null
|
||||
if (containerFqName == null || newContainer is ContainerInfo.UnknownPackage) return null
|
||||
return fqName.asString().let {
|
||||
val prefix = packageName.asString()
|
||||
val prefix = containerFqName.asString()
|
||||
val prefixOffset = it.indexOf(prefix)
|
||||
val newFqName = FqName(it.replaceRange(prefixOffset..prefixOffset + prefix.length - 1, newPackageName.asString()))
|
||||
val newFqName = FqName(it.replaceRange(prefixOffset..prefixOffset + prefix.length - 1, newContainer.fqName!!.asString()))
|
||||
MoveRenameSelfUsageInfo(refExpr.mainReference, declaration, newFqName)
|
||||
}
|
||||
}
|
||||
@@ -146,11 +191,8 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
return createMoveUsageInfoIfPossible(refExpr.mainReference, declaration, false)
|
||||
}
|
||||
|
||||
if (!isExtension &&
|
||||
packageName != oldPackageName &&
|
||||
packageName?.asString() != newPackageName.asString() &&
|
||||
!isImported(descriptor)) return null
|
||||
return ::doCreateUsageInfo
|
||||
if (isExtension || containerFqName != null || isImported(descriptor)) return ::doCreateUsageInfo
|
||||
return null
|
||||
}
|
||||
|
||||
val referenceToContext = KotlinFileReferencesResolver.resolve(file = file, elements = listOf(this))
|
||||
@@ -163,6 +205,8 @@ fun KtElement.lazilyProcessInternalReferencesToUpdateOnPackageNameChange(
|
||||
}
|
||||
}
|
||||
|
||||
class ImplicitCompanionAsDispatchReceiverUsageInfo(callee: KtSimpleNameExpression) : UsageInfo(callee)
|
||||
|
||||
class MoveRenameUsageInfoForExtension(
|
||||
element: PsiElement,
|
||||
reference: PsiReference,
|
||||
@@ -276,7 +320,7 @@ fun postProcessMoveUsages(usages: List<UsageInfo>,
|
||||
|
||||
val nonCodeUsages = ArrayList<NonCodeUsageInfo>()
|
||||
|
||||
for (usage in sortedUsages) {
|
||||
usageLoop@ for (usage in sortedUsages) {
|
||||
when (usage) {
|
||||
is NonCodeUsageInfo -> {
|
||||
nonCodeUsages.add(usage)
|
||||
@@ -295,21 +339,17 @@ fun postProcessMoveUsages(usages: List<UsageInfo>,
|
||||
is MoveRenameUsageInfo -> {
|
||||
val oldElement = usage.referencedElement!!
|
||||
val newElement = counterpart(oldElement)
|
||||
usage.reference?.let {
|
||||
try {
|
||||
if (it is KtSimpleNameReference) {
|
||||
it.bindToElement(newElement, shorteningMode)
|
||||
}
|
||||
else if (it is PsiReferenceExpression && updateJavaReference(it, oldElement, newElement)) {
|
||||
}
|
||||
else {
|
||||
it.bindToElement(newElement)
|
||||
}
|
||||
}
|
||||
catch (e: IncorrectOperationException) {
|
||||
// Suppress exception if bindToElement is not implemented
|
||||
val reference = usage.reference ?: (usage.element as? KtSimpleNameExpression)?.mainReference
|
||||
try {
|
||||
when {
|
||||
reference is KtSimpleNameReference -> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,3 +428,86 @@ fun moveFilesOrDirectories(
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class OuterInstanceReferenceUsageInfo(element: PsiElement, val isIndirectOuter: Boolean) : UsageInfo(element) {
|
||||
class ExplicitThis(
|
||||
expression: KtThisExpression,
|
||||
isIndirectOuter: Boolean
|
||||
) : OuterInstanceReferenceUsageInfo(expression, isIndirectOuter) {
|
||||
val expression: KtThisExpression?
|
||||
get() = element as? KtThisExpression
|
||||
}
|
||||
|
||||
class ImplicitReceiver(
|
||||
callElement: KtElement,
|
||||
isIndirectOuter: Boolean,
|
||||
val isDoubleReceiver: Boolean
|
||||
) : OuterInstanceReferenceUsageInfo(callElement, isIndirectOuter) {
|
||||
val callElement: KtElement?
|
||||
get() = element as? KtElement
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun traverseOuterInstanceReferences(innerClass: KtClass, stopAtFirst: Boolean, body: (OuterInstanceReferenceUsageInfo) -> Unit = {}): Boolean {
|
||||
if (!innerClass.isInner()) return false
|
||||
|
||||
val context = innerClass.analyzeFully()
|
||||
val innerClassDescriptor = innerClass.resolveToDescriptorIfAny() as? ClassDescriptor ?: return false
|
||||
val outerClassDescriptor = innerClassDescriptor.containingDeclaration as? ClassDescriptor ?: return false
|
||||
var found = false
|
||||
innerClass.accept(
|
||||
object : PsiRecursiveElementWalkingVisitor() {
|
||||
private fun getOuterInstanceReference(element: PsiElement): OuterInstanceReferenceUsageInfo? {
|
||||
return when (element) {
|
||||
is KtThisExpression -> {
|
||||
val descriptor = context[BindingContext.REFERENCE_TARGET, element.instanceReference]
|
||||
val isIndirect = when {
|
||||
descriptor == outerClassDescriptor -> false
|
||||
DescriptorUtils.isAncestor(descriptor, outerClassDescriptor, true) -> true
|
||||
else -> return null
|
||||
}
|
||||
OuterInstanceReferenceUsageInfo.ExplicitThis(element, isIndirect)
|
||||
}
|
||||
is KtSimpleNameExpression -> {
|
||||
val resolvedCall = element.getResolvedCall(context) ?: return null
|
||||
val dispatchReceiver = resolvedCall.dispatchReceiver as? ImplicitReceiver
|
||||
val extensionReceiver = resolvedCall.extensionReceiver as? ImplicitReceiver
|
||||
var isIndirect = false
|
||||
val isDoubleReceiver = when {
|
||||
dispatchReceiver?.declarationDescriptor == outerClassDescriptor -> extensionReceiver != null
|
||||
extensionReceiver?.declarationDescriptor == outerClassDescriptor -> dispatchReceiver != null
|
||||
else -> {
|
||||
isIndirect = true
|
||||
when {
|
||||
DescriptorUtils.isAncestor(dispatchReceiver?.declarationDescriptor, outerClassDescriptor, true) ->
|
||||
extensionReceiver != null
|
||||
DescriptorUtils.isAncestor(extensionReceiver?.declarationDescriptor, outerClassDescriptor, true) ->
|
||||
dispatchReceiver != null
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
}
|
||||
OuterInstanceReferenceUsageInfo.ImplicitReceiver(resolvedCall.call.callElement, isIndirect, isDoubleReceiver)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitElement(element: PsiElement) {
|
||||
getOuterInstanceReference(element)?.let {
|
||||
body(it)
|
||||
found = true
|
||||
if (stopAtFirst) stopWalking()
|
||||
return
|
||||
}
|
||||
super.visitElement(element)
|
||||
}
|
||||
}
|
||||
)
|
||||
return found
|
||||
}
|
||||
|
||||
fun collectOuterInstanceReferences(innerClass: KtClass): List<OuterInstanceReferenceUsageInfo> {
|
||||
return SmartList<OuterInstanceReferenceUsageInfo>().apply { traverseOuterInstanceReferences(innerClass, false) { add(it) } }
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"mainFile": "source/test.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveDeclarationToSeparateFileIntention"
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationToSeparateFileIntention"
|
||||
}
|
||||
idea/testData/multiFileIntentions/moveDeclarationToSeparateFile/moveClassToFile/moveClassToFile.test
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"mainFile": "source/test.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveDeclarationToSeparateFileIntention"
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationToSeparateFileIntention"
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"mainFile": "source/test.kt",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.refactoring.move.moveTopLevelDeclarations.MoveDeclarationToSeparateFileIntention",
|
||||
"intentionClass": "org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveDeclarationToSeparateFileIntention",
|
||||
"isApplicable": "false"
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package test
|
||||
|
||||
class A {
|
||||
inner class OuterOuterY
|
||||
|
||||
inner class B {
|
||||
inner class C {
|
||||
fun test() {
|
||||
OuterOuterY()
|
||||
this@A.OuterOuterY()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package test
|
||||
|
||||
class A {
|
||||
inner class OuterOuterY
|
||||
|
||||
inner class B {
|
||||
inner class <caret>C {
|
||||
fun test() {
|
||||
OuterOuterY()
|
||||
this@A.OuterOuterY()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
Indirect outer instances won't be extracted: OuterOuterY()
|
||||
Indirect outer instances won't be extracted: this@A
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"outerInstanceParameter": "a",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
package test
|
||||
|
||||
class C(private val b: A.B) {
|
||||
fun test() {
|
||||
A.X()
|
||||
|
||||
A.Companion.Y()
|
||||
A.foo(A.bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
b.OuterY()
|
||||
b.outerFoo(b.outerBar)
|
||||
|
||||
b.OuterY()
|
||||
b.outerFoo(b.outerBar)
|
||||
|
||||
A.O.Y()
|
||||
A.O.foo(A.O.bar)
|
||||
|
||||
with (A.O) {
|
||||
A.Companion.Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
inner class B {
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C(new A().new B());
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C(new A().new B());
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C(new A().new B());
|
||||
}
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.C
|
||||
|
||||
fun foo(): C {
|
||||
return C(A().B())
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.C
|
||||
|
||||
fun foo2(): C {
|
||||
return C(A().B())
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.B
|
||||
import test.C
|
||||
|
||||
fun foo2(): C {
|
||||
return C(A().B())
|
||||
}
|
||||
Vendored
+66
@@ -0,0 +1,66 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
inner class B {
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
inner class <caret>C {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
OuterY()
|
||||
outerFoo(outerBar)
|
||||
|
||||
this@B.OuterY()
|
||||
this@B.outerFoo(this@B.outerBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.B.C foo() {
|
||||
return new A().new B().new C();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.A.B.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new A().new B().new C();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.A.B;
|
||||
|
||||
class Test {
|
||||
B.C foo() {
|
||||
return new A().new B().new C();
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.B.C {
|
||||
return A().B().C()
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.B.C
|
||||
|
||||
fun foo2(): C {
|
||||
return A().B().C()
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.B
|
||||
|
||||
fun foo2(): B.C {
|
||||
return A().B().C()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"outerInstanceParameter": "b",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package test
|
||||
|
||||
class C {
|
||||
fun test() {
|
||||
A.X()
|
||||
|
||||
A.Companion.Y()
|
||||
A.foo(A.bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
A.O.Y()
|
||||
A.O.foo(A.O.bar)
|
||||
|
||||
with (A.O) {
|
||||
A.Companion.Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
class B {
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/move/kotlin/moveNestedClass/deepNonInnerToTopLevel/after/test2/usages.java
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C();
|
||||
}
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.C
|
||||
|
||||
fun foo(): C {
|
||||
return C()
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.C
|
||||
|
||||
fun foo(): C {
|
||||
return C()
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A.B
|
||||
import test.C
|
||||
|
||||
fun foo(): C {
|
||||
return C()
|
||||
}
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
class B {
|
||||
class <caret>C {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.B.C foo() {
|
||||
return new A.B.C();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.B.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.B;
|
||||
|
||||
class Test {
|
||||
B.C foo() {
|
||||
return new B.C();
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.B.C {
|
||||
return A.B.C()
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A.B.C
|
||||
|
||||
fun foo(): C {
|
||||
return C()
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A.B
|
||||
|
||||
fun foo(): B.C {
|
||||
return B.C()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package test
|
||||
|
||||
class B {
|
||||
fun test() {
|
||||
A.X()
|
||||
|
||||
A.Companion.Y()
|
||||
A.foo(A.bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
A.O.Y()
|
||||
A.O.foo(A.O.bar)
|
||||
|
||||
with (A.O) {
|
||||
A.Companion.Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/move/kotlin/moveNestedClass/innerToTopLevelNoThis/after/test2/usages2.java
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.B
|
||||
|
||||
fun foo(): B {
|
||||
return B()
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.B
|
||||
|
||||
fun foo2(): B {
|
||||
return B()
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
inner class <caret>B {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/move/kotlin/moveNestedClass/innerToTopLevelNoThis/before/test2/usages.java
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.A.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.B {
|
||||
return A().B()
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.B
|
||||
|
||||
fun foo2(): B {
|
||||
return A().B()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package test
|
||||
|
||||
class B(private val a: A) {
|
||||
fun test() {
|
||||
A.X()
|
||||
|
||||
A.Companion.Y()
|
||||
A.foo(A.bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
a.OuterY()
|
||||
a.outerFoo(a.outerBar)
|
||||
|
||||
a.OuterY()
|
||||
a.outerFoo(a.outerBar)
|
||||
|
||||
A.O.Y()
|
||||
A.O.foo(A.O.bar)
|
||||
|
||||
with (A.O) {
|
||||
A.Companion.Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new B(new A());
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new B(new A());
|
||||
}
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.B
|
||||
|
||||
fun foo(): B {
|
||||
return B(A())
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.B
|
||||
|
||||
fun foo2(): B {
|
||||
return B(A())
|
||||
}
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
inner class OuterY
|
||||
|
||||
fun outerFoo(n: Int) {}
|
||||
|
||||
val outerBar = 1
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
inner class <caret>B {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
OuterY()
|
||||
outerFoo(outerBar)
|
||||
|
||||
this@A.OuterY()
|
||||
this@A.outerFoo(this@A.outerBar)
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
import test.A.B;
|
||||
|
||||
class Test {
|
||||
B foo() {
|
||||
return new A().new B();
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.B {
|
||||
return A().B()
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.B
|
||||
|
||||
fun foo2(): B {
|
||||
return A().B()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"outerInstanceParameter": "a",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A() {
|
||||
fun X.bar() {}
|
||||
}
|
||||
|
||||
class X {
|
||||
fun Int.foo() {}
|
||||
|
||||
inner class Y {
|
||||
fun test() {
|
||||
1.foo()
|
||||
with(1) { foo() }
|
||||
with(A()) { bar() }
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A() {
|
||||
fun X.bar() {}
|
||||
}
|
||||
|
||||
class X {
|
||||
fun Int.foo() {}
|
||||
|
||||
inner class <caret>Y {
|
||||
fun test() {
|
||||
1.foo()
|
||||
with(1) { foo() }
|
||||
with(A()) { bar() }
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
Call with two implicit receivers won't be processed: bar()
|
||||
Call with two implicit receivers won't be processed: foo()
|
||||
Qualified call won't be processed: 1.foo()
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"outerInstanceParameter": "a",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class B {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class C {
|
||||
fun test() {
|
||||
B.X()
|
||||
|
||||
B.Companion.Y()
|
||||
B.foo(B.bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
B.O.Y()
|
||||
B.O.foo(B.O.bar)
|
||||
|
||||
with (B.O) {
|
||||
B.Companion.Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.C foo() {
|
||||
return new A.C();
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/move/kotlin/moveNestedClass/nonInnerToOuterClass1/after/test2/usages2.java
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C();
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/move/kotlin/moveNestedClass/nonInnerToOuterClass1/after/test2/usages3.java
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.C foo() {
|
||||
return new A.C();
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.C {
|
||||
return A.C()
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A.C
|
||||
|
||||
fun foo(): C {
|
||||
return C()
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
import test.A.B
|
||||
|
||||
fun foo(): A.C {
|
||||
return A.C()
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class B {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
class <caret>C {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/move/kotlin/moveNestedClass/nonInnerToOuterClass1/before/test2/usages.java
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.B.C foo() {
|
||||
return new A.B.C();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.B.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.B;
|
||||
|
||||
class Test {
|
||||
B.C foo() {
|
||||
return new B.C();
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A
|
||||
|
||||
fun foo(): A.B.C {
|
||||
return A.B.C()
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A.B.C
|
||||
|
||||
fun foo(): C {
|
||||
return C()
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test2
|
||||
|
||||
import test.A.B
|
||||
|
||||
fun foo(): B.C {
|
||||
return B.C()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"mainFile": "test.kt",
|
||||
"type": "MOVE_KOTLIN_NESTED_CLASS",
|
||||
"targetClass": "test.A",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package test
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
|
||||
|
||||
class A {
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
object O {
|
||||
class Y
|
||||
|
||||
fun foo(n: Int) {}
|
||||
|
||||
val bar = 1
|
||||
|
||||
fun Int.extFoo(n: Int) {}
|
||||
|
||||
val Int.extBar: Int get() = 1
|
||||
}
|
||||
|
||||
class B {
|
||||
}
|
||||
|
||||
class C {
|
||||
fun test() {
|
||||
X()
|
||||
|
||||
Y()
|
||||
foo(bar)
|
||||
//1.extFoo(1.extBar) // conflict
|
||||
|
||||
O.Y()
|
||||
O.foo(O.bar)
|
||||
|
||||
with (O) {
|
||||
Y()
|
||||
foo(bar)
|
||||
1.extFoo(1.extBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A;
|
||||
|
||||
class Test {
|
||||
A.C foo() {
|
||||
return new A.C();
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/move/kotlin/moveNestedClass/nonInnerToOuterClass2/after/test2/usages2.java
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
package test2;
|
||||
|
||||
import test.A.C;
|
||||
|
||||
class Test {
|
||||
C foo() {
|
||||
return new C();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user