Clean up move refactoring
This commit is contained in:
@@ -49,10 +49,10 @@ abstract class MoveMemberOutOfObjectIntention(text: String) : SelfTargetingRange
|
|||||||
|
|
||||||
if (element is KtClassOrObject) {
|
if (element is KtClassOrObject) {
|
||||||
val moveDescriptor = MoveDeclarationsDescriptor(
|
val moveDescriptor = MoveDeclarationsDescriptor(
|
||||||
project,
|
project,
|
||||||
MoveSource(element),
|
MoveSource(element),
|
||||||
KotlinMoveTargetForExistingElement(destination),
|
KotlinMoveTargetForExistingElement(destination),
|
||||||
MoveDeclarationsDelegate.NestedClass()
|
MoveDeclarationsDelegate.NestedClass()
|
||||||
)
|
)
|
||||||
object : CompositeRefactoringRunner(project, MoveKotlinDeclarationsProcessor.REFACTORING_ID) {
|
object : CompositeRefactoringRunner(project, MoveKotlinDeclarationsProcessor.REFACTORING_ID) {
|
||||||
override fun runRefactoring() = MoveKotlinDeclarationsProcessor(moveDescriptor).run()
|
override fun runRefactoring() = MoveKotlinDeclarationsProcessor(moveDescriptor).run()
|
||||||
|
|||||||
+3
-14
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move
|
||||||
@@ -28,7 +17,7 @@ sealed class AutocreatingPsiDirectoryWrapper {
|
|||||||
|
|
||||||
class ByMoveDestination(private val moveDestination: MoveDestination) : AutocreatingPsiDirectoryWrapper() {
|
class ByMoveDestination(private val moveDestination: MoveDestination) : AutocreatingPsiDirectoryWrapper() {
|
||||||
override fun getPackageName() = moveDestination.targetPackage.qualifiedName
|
override fun getPackageName() = moveDestination.targetPackage.qualifiedName
|
||||||
override fun getOrCreateDirectory(source: PsiDirectory) = moveDestination.getTargetDirectory(source)
|
override fun getOrCreateDirectory(source: PsiDirectory): PsiDirectory = moveDestination.getTargetDirectory(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun getPackageName(): String
|
abstract fun getPackageName(): String
|
||||||
|
|||||||
+9
-21
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move
|
||||||
@@ -26,7 +15,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
|
|||||||
import org.jetbrains.kotlin.psi.KtValueArgumentList
|
import org.jetbrains.kotlin.psi.KtValueArgumentList
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
||||||
|
|
||||||
class MoveJavaInnerClassKotlinUsagesHandler: MoveInnerClassUsagesHandler {
|
class MoveJavaInnerClassKotlinUsagesHandler : MoveInnerClassUsagesHandler {
|
||||||
override fun correctInnerClassUsage(usage: UsageInfo, outerClass: PsiClass) {
|
override fun correctInnerClassUsage(usage: UsageInfo, outerClass: PsiClass) {
|
||||||
val innerCall = usage.element?.parent as? KtCallExpression ?: return
|
val innerCall = usage.element?.parent as? KtCallExpression ?: return
|
||||||
val receiverExpression = innerCall.getQualifiedExpressionForSelector()?.receiverExpression
|
val receiverExpression = innerCall.getQualifiedExpressionForSelector()?.receiverExpression
|
||||||
@@ -35,13 +24,12 @@ class MoveJavaInnerClassKotlinUsagesHandler: MoveInnerClassUsagesHandler {
|
|||||||
|
|
||||||
val argumentToAdd = psiFactory.createArgument(receiverExpression ?: psiFactory.createExpression("this"))
|
val argumentToAdd = psiFactory.createArgument(receiverExpression ?: psiFactory.createExpression("this"))
|
||||||
|
|
||||||
val argumentList =
|
val argumentList = innerCall.valueArgumentList
|
||||||
innerCall.valueArgumentList
|
?: (innerCall.lambdaArguments.firstOrNull()?.let { lambdaArg ->
|
||||||
?: (innerCall.lambdaArguments.firstOrNull()?.let { lambdaArg ->
|
val anchor = PsiTreeUtil.skipSiblingsBackward(lambdaArg, PsiWhiteSpace::class.java)
|
||||||
val anchor = PsiTreeUtil.skipSiblingsBackward(lambdaArg, PsiWhiteSpace::class.java)
|
innerCall.addAfter(psiFactory.createCallArguments("()"), anchor)
|
||||||
innerCall.addAfter(psiFactory.createCallArguments("()"), anchor)
|
} as KtValueArgumentList?)
|
||||||
} as KtValueArgumentList?)
|
?: return
|
||||||
?: return
|
|
||||||
|
|
||||||
argumentList.addArgumentAfter(argumentToAdd, null)
|
argumentList.addArgumentAfter(argumentToAdd, null)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-16
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.moveClassesOrPackages
|
package org.jetbrains.kotlin.idea.refactoring.move.moveClassesOrPackages
|
||||||
@@ -24,9 +13,9 @@ import com.intellij.refactoring.move.MoveCallback
|
|||||||
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesToNewDirectoryDialog
|
import com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesToNewDirectoryDialog
|
||||||
|
|
||||||
class KotlinAwareMoveClassesOrPackagesToNewDirectoryDialog(
|
class KotlinAwareMoveClassesOrPackagesToNewDirectoryDialog(
|
||||||
directory: PsiDirectory,
|
directory: PsiDirectory,
|
||||||
elementsToMove: Array<out PsiElement>,
|
elementsToMove: Array<out PsiElement>,
|
||||||
moveCallback: MoveCallback?
|
moveCallback: MoveCallback?
|
||||||
) : MoveClassesOrPackagesToNewDirectoryDialog(directory, elementsToMove, moveCallback) {
|
) : MoveClassesOrPackagesToNewDirectoryDialog(directory, elementsToMove, moveCallback) {
|
||||||
override fun createDestination(aPackage: PsiPackage, directory: PsiDirectory): MoveDestination? {
|
override fun createDestination(aPackage: PsiPackage, directory: PsiDirectory): MoveDestination? {
|
||||||
val delegate = super.createDestination(aPackage, directory) ?: return null
|
val delegate = super.createDestination(aPackage, directory) ?: return null
|
||||||
|
|||||||
+34
-38
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
@@ -45,8 +34,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
|||||||
private const val TIMEOUT_FOR_IMPORT_OPTIMIZING_MS: Long = 700L
|
private const val TIMEOUT_FOR_IMPORT_OPTIMIZING_MS: Long = 700L
|
||||||
|
|
||||||
class ExtractDeclarationFromCurrentFileIntention :
|
class ExtractDeclarationFromCurrentFileIntention :
|
||||||
SelfTargetingRangeIntention<KtClassOrObject>(KtClassOrObject::class.java, "Extract declaration from current file"),
|
SelfTargetingRangeIntention<KtClassOrObject>(KtClassOrObject::class.java, "Extract declaration from current file"),
|
||||||
LowPriorityAction {
|
LowPriorityAction {
|
||||||
override fun applicabilityRange(element: KtClassOrObject): TextRange? {
|
override fun applicabilityRange(element: KtClassOrObject): TextRange? {
|
||||||
if (element.name == null) return null
|
if (element.name == null) return null
|
||||||
if (element.parent !is KtFile) return null
|
if (element.parent !is KtFile) return null
|
||||||
@@ -89,17 +78,24 @@ class ExtractDeclarationFromCurrentFileIntention :
|
|||||||
// If automatic move is not possible, fall back to full-fledged Move Declarations refactoring
|
// If automatic move is not possible, fall back to full-fledged Move Declarations refactoring
|
||||||
ApplicationManager.getApplication().invokeLater {
|
ApplicationManager.getApplication().invokeLater {
|
||||||
MoveKotlinTopLevelDeclarationsDialog(
|
MoveKotlinTopLevelDeclarationsDialog(
|
||||||
project,
|
project,
|
||||||
setOf(element),
|
setOf(element),
|
||||||
packageName.asString(),
|
packageName.asString(),
|
||||||
directory,
|
directory,
|
||||||
targetFile as? KtFile,
|
targetFile as? KtFile,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
MoveCallback {
|
MoveCallback {
|
||||||
runBlocking { withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { OptimizeImportsProcessor(project, file).run() } }
|
runBlocking {
|
||||||
|
withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) {
|
||||||
|
OptimizeImportsProcessor(
|
||||||
|
project,
|
||||||
|
file
|
||||||
|
).run()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -108,19 +104,19 @@ class ExtractDeclarationFromCurrentFileIntention :
|
|||||||
createKotlinFile(targetFileName, directory, packageName.asString())
|
createKotlinFile(targetFileName, directory, packageName.asString())
|
||||||
}
|
}
|
||||||
val descriptor = MoveDeclarationsDescriptor(
|
val descriptor = MoveDeclarationsDescriptor(
|
||||||
project = project,
|
project = project,
|
||||||
moveSource = MoveSource(element),
|
moveSource = MoveSource(element),
|
||||||
moveTarget = moveTarget,
|
moveTarget = moveTarget,
|
||||||
delegate = MoveDeclarationsDelegate.TopLevel,
|
delegate = MoveDeclarationsDelegate.TopLevel,
|
||||||
searchInCommentsAndStrings = false,
|
searchInCommentsAndStrings = false,
|
||||||
searchInNonCode = false,
|
searchInNonCode = false,
|
||||||
moveCallback = MoveCallback {
|
moveCallback = MoveCallback {
|
||||||
val newFile = directory.findFile(targetFileName) as KtFile
|
val newFile = directory.findFile(targetFileName) as KtFile
|
||||||
val newDeclaration = newFile.declarations.first()
|
val newDeclaration = newFile.declarations.first()
|
||||||
NavigationUtil.activateFileWithPsiElement(newFile)
|
NavigationUtil.activateFileWithPsiElement(newFile)
|
||||||
FileEditorManager.getInstance(project).selectedTextEditor?.moveCaret(newDeclaration.startOffset + originalOffset)
|
FileEditorManager.getInstance(project).selectedTextEditor?.moveCaret(newDeclaration.startOffset + originalOffset)
|
||||||
runBlocking { withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { OptimizeImportsProcessor(project, file).run() } }
|
runBlocking { withTimeoutOrNull(TIMEOUT_FOR_IMPORT_OPTIMIZING_MS) { OptimizeImportsProcessor(project, file).run() } }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
MoveKotlinDeclarationsProcessor(descriptor).run()
|
MoveKotlinDeclarationsProcessor(descriptor).run()
|
||||||
|
|||||||
+25
-46
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
@@ -32,49 +21,40 @@ import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.allElem
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.shouldFixFqName
|
import org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories.shouldFixFqName
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
class KotlinAwareMoveFilesOrDirectoriesProcessor @JvmOverloads constructor (
|
class KotlinAwareMoveFilesOrDirectoriesProcessor @JvmOverloads constructor(
|
||||||
project: Project,
|
project: Project,
|
||||||
private val elementsToMove: List<PsiElement>,
|
private val elementsToMove: List<PsiElement>,
|
||||||
private val targetDirectory: PsiDirectory,
|
private val targetDirectory: PsiDirectory,
|
||||||
private val searchReferences: Boolean,
|
private val searchReferences: Boolean,
|
||||||
searchInComments: Boolean,
|
searchInComments: Boolean,
|
||||||
searchInNonJavaFiles: Boolean,
|
searchInNonJavaFiles: Boolean,
|
||||||
moveCallback: MoveCallback?,
|
moveCallback: MoveCallback?,
|
||||||
prepareSuccessfulCallback: Runnable = EmptyRunnable.INSTANCE
|
prepareSuccessfulCallback: Runnable = EmptyRunnable.INSTANCE
|
||||||
) : MoveFilesOrDirectoriesProcessor(project,
|
) : MoveFilesOrDirectoriesProcessor(
|
||||||
elementsToMove.toTypedArray<PsiElement>(),
|
project,
|
||||||
targetDirectory,
|
elementsToMove.toTypedArray(),
|
||||||
true,
|
targetDirectory,
|
||||||
searchInComments,
|
true,
|
||||||
searchInNonJavaFiles,
|
searchInComments,
|
||||||
moveCallback,
|
searchInNonJavaFiles,
|
||||||
prepareSuccessfulCallback) {
|
moveCallback,
|
||||||
|
prepareSuccessfulCallback
|
||||||
|
) {
|
||||||
override fun createUsageViewDescriptor(usages: Array<out UsageInfo>): UsageViewDescriptor {
|
override fun createUsageViewDescriptor(usages: Array<out UsageInfo>): UsageViewDescriptor {
|
||||||
return MoveFilesWithDeclarationsViewDescriptor(elementsToMove.toTypedArray<PsiElement>(), targetDirectory)
|
return MoveFilesWithDeclarationsViewDescriptor(elementsToMove.toTypedArray(), targetDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findUsages(): Array<UsageInfo> {
|
override fun findUsages(): Array<UsageInfo> {
|
||||||
try {
|
try {
|
||||||
markScopeToMove(elementsToMove)
|
markScopeToMove(elementsToMove)
|
||||||
return if (searchReferences) super.findUsages() else UsageInfo.EMPTY_ARRAY
|
return if (searchReferences) super.findUsages() else UsageInfo.EMPTY_ARRAY
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
markScopeToMove(null)
|
markScopeToMove(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun preprocessUsages(refUsages: Ref<Array<UsageInfo>>): Boolean {
|
override fun preprocessUsages(refUsages: Ref<Array<UsageInfo>>): Boolean {
|
||||||
val usages = refUsages.get()
|
val (conflicts, usages) = MoveToKotlinFileProcessor.preprocessConflictUsages(refUsages)
|
||||||
|
|
||||||
val (conflictUsages, usagesToProcess) = usages.partition { it is ConflictUsageInfo }
|
|
||||||
|
|
||||||
val conflicts = MultiMap<PsiElement, String>()
|
|
||||||
for (conflictUsage in conflictUsages) {
|
|
||||||
conflicts.putValues(conflictUsage.element, (conflictUsage as ConflictUsageInfo).messages)
|
|
||||||
}
|
|
||||||
|
|
||||||
refUsages.set(usagesToProcess.toTypedArray())
|
|
||||||
|
|
||||||
return showConflicts(conflicts, usages)
|
return showConflicts(conflicts, usages)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,8 +81,7 @@ class KotlinAwareMoveFilesOrDirectoriesProcessor @JvmOverloads constructor (
|
|||||||
try {
|
try {
|
||||||
markShouldFixFqName(true)
|
markShouldFixFqName(true)
|
||||||
super.performRefactoring(usages)
|
super.performRefactoring(usages)
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
markShouldFixFqName(false)
|
markShouldFixFqName(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-32
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
@@ -52,16 +41,16 @@ interface KotlinDirectoryBasedMoveTarget : KotlinMoveTarget {
|
|||||||
get() = super.targetScope ?: directory?.virtualFile
|
get() = super.targetScope ?: directory?.virtualFile
|
||||||
}
|
}
|
||||||
|
|
||||||
object EmptyKotlinMoveTarget: KotlinMoveTarget {
|
object EmptyKotlinMoveTarget : KotlinMoveTarget {
|
||||||
override val targetContainerFqName = null
|
override val targetContainerFqName: FqName? = null
|
||||||
override val targetFile = null
|
override val targetFile: VirtualFile? = null
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = null
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement? = null
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
|
||||||
override fun verify(file: PsiFile) = null
|
override fun verify(file: PsiFile): String? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinMoveTargetForExistingElement(val targetElement: KtElement): KotlinMoveTarget {
|
class KotlinMoveTargetForExistingElement(val targetElement: KtElement) : KotlinMoveTarget {
|
||||||
override val targetContainerFqName = targetElement.containingKtFile.packageFqName
|
override val targetContainerFqName = targetElement.containingKtFile.packageFqName
|
||||||
|
|
||||||
override val targetFile: VirtualFile? = targetElement.containingKtFile.virtualFile
|
override val targetFile: VirtualFile? = targetElement.containingKtFile.virtualFile
|
||||||
@@ -74,9 +63,9 @@ class KotlinMoveTargetForExistingElement(val targetElement: KtElement): KotlinMo
|
|||||||
override fun verify(file: PsiFile): String? = null
|
override fun verify(file: PsiFile): String? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinMoveTargetForCompanion(val targetClass: KtClass): KotlinMoveTarget {
|
class KotlinMoveTargetForCompanion(val targetClass: KtClass) : KotlinMoveTarget {
|
||||||
override val targetContainerFqName = targetClass.companionObjects.firstOrNull()?.fqName
|
override val targetContainerFqName = targetClass.companionObjects.firstOrNull()?.fqName
|
||||||
?: targetClass.fqName!!.child(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
|
?: targetClass.fqName!!.child(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT)
|
||||||
|
|
||||||
override val targetFile: VirtualFile? = targetClass.containingKtFile.virtualFile
|
override val targetFile: VirtualFile? = targetClass.containingKtFile.virtualFile
|
||||||
|
|
||||||
@@ -89,11 +78,11 @@ class KotlinMoveTargetForCompanion(val targetClass: KtClass): KotlinMoveTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class KotlinMoveTargetForDeferredFile(
|
class KotlinMoveTargetForDeferredFile(
|
||||||
override val targetContainerFqName: FqName,
|
override val targetContainerFqName: FqName,
|
||||||
override val directory: PsiDirectory?,
|
override val directory: PsiDirectory?,
|
||||||
override val targetFile: VirtualFile? = directory?.virtualFile,
|
override val targetFile: VirtualFile? = directory?.virtualFile,
|
||||||
private val createFile: (KtFile) -> KtFile?
|
private val createFile: (KtFile) -> KtFile?
|
||||||
): KotlinDirectoryBasedMoveTarget {
|
) : KotlinDirectoryBasedMoveTarget {
|
||||||
private val createdFiles = HashMap<KtFile, KtFile?>()
|
private val createdFiles = HashMap<KtFile, KtFile?>()
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement? {
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement): KtElement? {
|
||||||
@@ -101,23 +90,23 @@ class KotlinMoveTargetForDeferredFile(
|
|||||||
return createdFiles.getOrPutNullable(originalFile) { createFile(originalFile) }
|
return createdFiles.getOrPutNullable(originalFile) { createFile(originalFile) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
|
||||||
|
|
||||||
// No additional verification is needed
|
// No additional verification is needed
|
||||||
override fun verify(file: PsiFile): String? = null
|
override fun verify(file: PsiFile): String? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
class KotlinDirectoryMoveTarget(
|
class KotlinDirectoryMoveTarget(
|
||||||
override val targetContainerFqName: FqName,
|
override val targetContainerFqName: FqName,
|
||||||
override val directory: PsiDirectory
|
override val directory: PsiDirectory
|
||||||
) : KotlinDirectoryBasedMoveTarget {
|
) : KotlinDirectoryBasedMoveTarget {
|
||||||
override val targetFile: VirtualFile? = directory.virtualFile
|
override val targetFile: VirtualFile? = directory.virtualFile
|
||||||
|
|
||||||
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile
|
override fun getOrCreateTargetPsi(originalPsi: PsiElement) = originalPsi.containingFile as? KtFile
|
||||||
|
|
||||||
override fun getTargetPsiIfExists(originalPsi: PsiElement) = null
|
override fun getTargetPsiIfExists(originalPsi: PsiElement): KtElement? = null
|
||||||
|
|
||||||
override fun verify(file: PsiFile) = null
|
override fun verify(file: PsiFile): String? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinMoveTarget.getTargetModule(project: Project) = targetScope?.getModule(project)
|
fun KotlinMoveTarget.getTargetModule(project: Project) = targetScope?.getModule(project)
|
||||||
+16
-28
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
@@ -39,9 +28,9 @@ sealed class MoveDeclarationsDelegate {
|
|||||||
open fun findInternalUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo> = emptyList()
|
open fun findInternalUsages(descriptor: MoveDeclarationsDescriptor): List<UsageInfo> = emptyList()
|
||||||
|
|
||||||
open fun collectConflicts(
|
open fun collectConflicts(
|
||||||
descriptor: MoveDeclarationsDescriptor,
|
descriptor: MoveDeclarationsDescriptor,
|
||||||
internalUsages: MutableSet<UsageInfo>,
|
internalUsages: MutableSet<UsageInfo>,
|
||||||
conflicts: MultiMap<PsiElement, String>
|
conflicts: MultiMap<PsiElement, String>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -63,8 +52,8 @@ sealed class MoveDeclarationsDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class NestedClass(
|
class NestedClass(
|
||||||
val newClassName: String? = null,
|
val newClassName: String? = null,
|
||||||
val outerInstanceParameterName: String? = null
|
val outerInstanceParameterName: String? = null
|
||||||
) : MoveDeclarationsDelegate() {
|
) : MoveDeclarationsDelegate() {
|
||||||
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
|
override fun getContainerChangeInfo(originalDeclaration: KtNamedDeclaration, moveTarget: KotlinMoveTarget): ContainerChangeInfo {
|
||||||
val originalInfo = ContainerInfo.Class(originalDeclaration.containingClassOrObject!!.fqName!!)
|
val originalInfo = ContainerInfo.Class(originalDeclaration.containingClassOrObject!!.fqName!!)
|
||||||
@@ -84,11 +73,10 @@ sealed class MoveDeclarationsDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isValidTargetForImplicitCompanionAsDispatchReceiver(
|
private fun isValidTargetForImplicitCompanionAsDispatchReceiver(
|
||||||
moveDescriptor: MoveDeclarationsDescriptor,
|
moveDescriptor: MoveDeclarationsDescriptor,
|
||||||
companionDescriptor: ClassDescriptor
|
companionDescriptor: ClassDescriptor
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val moveTarget = moveDescriptor.moveTarget
|
return when (val moveTarget = moveDescriptor.moveTarget) {
|
||||||
return when (moveTarget) {
|
|
||||||
is KotlinMoveTargetForCompanion -> true
|
is KotlinMoveTargetForCompanion -> true
|
||||||
is KotlinMoveTargetForExistingElement -> {
|
is KotlinMoveTargetForExistingElement -> {
|
||||||
val targetClass = moveTarget.targetElement as? KtClassOrObject ?: return false
|
val targetClass = moveTarget.targetElement as? KtClassOrObject ?: return false
|
||||||
@@ -101,9 +89,9 @@ sealed class MoveDeclarationsDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun collectConflicts(
|
override fun collectConflicts(
|
||||||
descriptor: MoveDeclarationsDescriptor,
|
descriptor: MoveDeclarationsDescriptor,
|
||||||
internalUsages: MutableSet<UsageInfo>,
|
internalUsages: MutableSet<UsageInfo>,
|
||||||
conflicts: MultiMap<PsiElement, String>
|
conflicts: MultiMap<PsiElement, String>
|
||||||
) {
|
) {
|
||||||
val usageIterator = internalUsages.iterator()
|
val usageIterator = internalUsages.iterator()
|
||||||
while (usageIterator.hasNext()) {
|
while (usageIterator.hasNext()) {
|
||||||
@@ -141,7 +129,7 @@ sealed class MoveDeclarationsDelegate {
|
|||||||
if (outerInstanceParameterName != null) {
|
if (outerInstanceParameterName != null) {
|
||||||
val type = (containingClassOrObject!!.unsafeResolveToDescriptor() as ClassDescriptor).defaultType
|
val type = (containingClassOrObject!!.unsafeResolveToDescriptor() as ClassDescriptor).defaultType
|
||||||
val parameter = KtPsiFactory(project)
|
val parameter = KtPsiFactory(project)
|
||||||
.createParameter("private val $outerInstanceParameterName: ${IdeDescriptorRenderers.SOURCE_CODE.renderType(type)}")
|
.createParameter("private val $outerInstanceParameterName: ${IdeDescriptorRenderers.SOURCE_CODE.renderType(type)}")
|
||||||
createPrimaryConstructorParameterListIfAbsent().addParameter(parameter).isToBeShortened = true
|
createPrimaryConstructorParameterListIfAbsent().addParameter(parameter).isToBeShortened = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,8 +150,8 @@ sealed class MoveDeclarationsDelegate {
|
|||||||
val lightOuterClass = outerClass?.toLightClass()
|
val lightOuterClass = outerClass?.toLightClass()
|
||||||
if (lightOuterClass != null) {
|
if (lightOuterClass != null) {
|
||||||
MoveInnerClassUsagesHandler.EP_NAME
|
MoveInnerClassUsagesHandler.EP_NAME
|
||||||
.forLanguage(usage.element!!.language)
|
.forLanguage(usage.element!!.language)
|
||||||
?.correctInnerClassUsage(usage, lightOuterClass, outerInstanceParameterName)
|
?.correctInnerClassUsage(usage, lightOuterClass, outerInstanceParameterName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-22
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
@@ -25,21 +14,24 @@ import com.intellij.usageView.UsageViewDescriptor
|
|||||||
import com.intellij.usageView.UsageViewUtil
|
import com.intellij.usageView.UsageViewUtil
|
||||||
|
|
||||||
internal class MoveFilesWithDeclarationsViewDescriptor(
|
internal class MoveFilesWithDeclarationsViewDescriptor(
|
||||||
private val myElementsToMove: Array<PsiElement>,
|
private val myElementsToMove: Array<PsiElement>,
|
||||||
newParent: PsiDirectory
|
newParent: PsiDirectory
|
||||||
) : UsageViewDescriptor {
|
) : UsageViewDescriptor {
|
||||||
private var myProcessedElementsHeader: String? = null
|
private var myProcessedElementsHeader: String? = null
|
||||||
private val myCodeReferencesText: String
|
private val myCodeReferencesText: String
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (myElementsToMove.size == 1) {
|
if (myElementsToMove.size == 1) {
|
||||||
myProcessedElementsHeader = RefactoringBundle.message("move.single.element.elements.header",
|
myProcessedElementsHeader = RefactoringBundle.message(
|
||||||
UsageViewUtil.getType(myElementsToMove[0]),
|
"move.single.element.elements.header",
|
||||||
newParent.virtualFile.presentableUrl).capitalize()
|
UsageViewUtil.getType(myElementsToMove[0]),
|
||||||
myCodeReferencesText = "References in code to ${UsageViewUtil.getType(myElementsToMove[0])} ${UsageViewUtil.getLongName(myElementsToMove[0])} and its declarations"
|
newParent.virtualFile.presentableUrl
|
||||||
}
|
).capitalize()
|
||||||
else {
|
myCodeReferencesText =
|
||||||
myProcessedElementsHeader = StringUtil.capitalize(RefactoringBundle.message("move.files.elements.header", newParent.virtualFile.presentableUrl))
|
"References in code to ${UsageViewUtil.getType(myElementsToMove[0])} ${UsageViewUtil.getLongName(myElementsToMove[0])} and its declarations"
|
||||||
|
} else {
|
||||||
|
myProcessedElementsHeader =
|
||||||
|
StringUtil.capitalize(RefactoringBundle.message("move.files.elements.header", newParent.virtualFile.presentableUrl))
|
||||||
myCodeReferencesText = RefactoringBundle.message("references.found.in.code")
|
myCodeReferencesText = RefactoringBundle.message("references.found.in.code")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-18
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
@@ -153,10 +142,13 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
|
|
||||||
private var nonCodeUsages: Array<NonCodeUsageInfo>? = null
|
private var nonCodeUsages: Array<NonCodeUsageInfo>? = null
|
||||||
private val moveEntireFile = descriptor.moveSource is MoveSource.File
|
private val moveEntireFile = descriptor.moveSource is MoveSource.File
|
||||||
private val elementsToMove = descriptor.moveSource.elementsToMove.filter { e -> e.parent != descriptor.moveTarget.getTargetPsiIfExists(e) }
|
private val elementsToMove = descriptor.moveSource.elementsToMove.filter { e ->
|
||||||
|
e.parent != descriptor.moveTarget.getTargetPsiIfExists(e)
|
||||||
|
}
|
||||||
|
|
||||||
private val kotlinToLightElementsBySourceFile = elementsToMove
|
private val kotlinToLightElementsBySourceFile = elementsToMove
|
||||||
.groupBy { it.containingKtFile }
|
.groupBy { it.containingKtFile }
|
||||||
.mapValues { it.value.keysToMap { it.toLightElements().ifEmpty { listOf(it) } } }
|
.mapValues { it.value.keysToMap { declaration -> declaration.toLightElements().ifEmpty { listOf(declaration) } } }
|
||||||
private val conflicts = MultiMap<PsiElement, String>()
|
private val conflicts = MultiMap<PsiElement, String>()
|
||||||
|
|
||||||
override fun getRefactoringId() = REFACTORING_ID
|
override fun getRefactoringId() = REFACTORING_ID
|
||||||
@@ -209,10 +201,9 @@ class MoveKotlinDeclarationsProcessor(
|
|||||||
val results = ReferencesSearch
|
val results = ReferencesSearch
|
||||||
.search(lightElement, searchScope)
|
.search(lightElement, searchScope)
|
||||||
.mapNotNullTo(ArrayList()) { ref ->
|
.mapNotNullTo(ArrayList()) { ref ->
|
||||||
if (foundReferences.add(ref) && elementsToMove.none { it.isAncestor(ref.element)}) {
|
if (foundReferences.add(ref) && elementsToMove.none { it.isAncestor(ref.element) }) {
|
||||||
createMoveUsageInfoIfPossible(ref, lightElement, addImportToOriginalFile = true, isInternal = false)
|
createMoveUsageInfoIfPossible(ref, lightElement, addImportToOriginalFile = true, isInternal = false)
|
||||||
}
|
} else null
|
||||||
else null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val name = lightElement.getKotlinFqName()?.quoteIfNeeded()?.asString()
|
val name = lightElement.getKotlinFqName()?.quoteIfNeeded()?.asString()
|
||||||
|
|||||||
+40
-30
@@ -29,23 +29,25 @@ import com.intellij.util.containers.MultiMap
|
|||||||
import com.intellij.util.text.UniqueNameGenerator
|
import com.intellij.util.text.UniqueNameGenerator
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
class MoveToKotlinFileProcessor @JvmOverloads constructor (
|
class MoveToKotlinFileProcessor @JvmOverloads constructor(
|
||||||
project: Project,
|
project: Project,
|
||||||
private val sourceFile: KtFile,
|
private val sourceFile: KtFile,
|
||||||
private val targetDirectory: PsiDirectory,
|
private val targetDirectory: PsiDirectory,
|
||||||
private val targetFileName: String,
|
private val targetFileName: String,
|
||||||
searchInComments: Boolean,
|
searchInComments: Boolean,
|
||||||
searchInNonJavaFiles: Boolean,
|
searchInNonJavaFiles: Boolean,
|
||||||
moveCallback: MoveCallback?,
|
moveCallback: MoveCallback?,
|
||||||
prepareSuccessfulCallback: Runnable = EmptyRunnable.INSTANCE
|
prepareSuccessfulCallback: Runnable = EmptyRunnable.INSTANCE
|
||||||
) : MoveFilesOrDirectoriesProcessor(project,
|
) : MoveFilesOrDirectoriesProcessor(
|
||||||
arrayOf(sourceFile),
|
project,
|
||||||
targetDirectory,
|
arrayOf(sourceFile),
|
||||||
true,
|
targetDirectory,
|
||||||
searchInComments,
|
true,
|
||||||
searchInNonJavaFiles,
|
searchInComments,
|
||||||
moveCallback,
|
searchInNonJavaFiles,
|
||||||
prepareSuccessfulCallback) {
|
moveCallback,
|
||||||
|
prepareSuccessfulCallback
|
||||||
|
) {
|
||||||
override fun getCommandName() = "Move ${sourceFile.name}"
|
override fun getCommandName() = "Move ${sourceFile.name}"
|
||||||
|
|
||||||
override fun createUsageViewDescriptor(usages: Array<out UsageInfo>): UsageViewDescriptor {
|
override fun createUsageViewDescriptor(usages: Array<out UsageInfo>): UsageViewDescriptor {
|
||||||
@@ -53,17 +55,7 @@ class MoveToKotlinFileProcessor @JvmOverloads constructor (
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun preprocessUsages(refUsages: Ref<Array<UsageInfo>>): Boolean {
|
override fun preprocessUsages(refUsages: Ref<Array<UsageInfo>>): Boolean {
|
||||||
val usages = refUsages.get()
|
val (conflicts, usages) = preprocessConflictUsages(refUsages)
|
||||||
|
|
||||||
val (conflictUsages, usagesToProcess) = usages.partition { it is ConflictUsageInfo }
|
|
||||||
|
|
||||||
val conflicts = MultiMap<PsiElement, String>()
|
|
||||||
for (conflictUsage in conflictUsages) {
|
|
||||||
conflicts.putValues(conflictUsage.element, (conflictUsage as ConflictUsageInfo).messages)
|
|
||||||
}
|
|
||||||
|
|
||||||
refUsages.set(usagesToProcess.toTypedArray())
|
|
||||||
|
|
||||||
return showConflicts(conflicts, usages)
|
return showConflicts(conflicts, usages)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,11 +77,29 @@ class MoveToKotlinFileProcessor @JvmOverloads constructor (
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
super.performRefactoring(usages)
|
super.performRefactoring(usages)
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
if (needTemporaryRename) {
|
if (needTemporaryRename) {
|
||||||
sourceFile.name = targetFileName
|
sourceFile.name = targetFileName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
data class ConflictUsages(val conflicts: MultiMap<PsiElement, String>, @Suppress("ArrayInDataClass") val usages: Array<UsageInfo>)
|
||||||
|
|
||||||
|
fun preprocessConflictUsages(refUsages: Ref<Array<UsageInfo>>): ConflictUsages {
|
||||||
|
val usages: Array<UsageInfo> = refUsages.get()
|
||||||
|
|
||||||
|
val (conflictUsages, usagesToProcess) = usages.partition { it is ConflictUsageInfo }
|
||||||
|
|
||||||
|
val conflicts = MultiMap<PsiElement, String>()
|
||||||
|
for (conflictUsage in conflictUsages) {
|
||||||
|
conflicts.putValues(conflictUsage.element, (conflictUsage as ConflictUsageInfo).messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
refUsages.set(usagesToProcess.toTypedArray())
|
||||||
|
|
||||||
|
return ConflictUsages(conflicts, usages)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-37
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations
|
||||||
@@ -62,6 +51,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
||||||
@@ -73,7 +63,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
||||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.findPackageFragmentForFile
|
import org.jetbrains.kotlin.resolve.lazy.descriptors.findPackageFragmentForFile
|
||||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||||
@@ -115,22 +104,19 @@ class MoveConflictChecker(
|
|||||||
|
|
||||||
private fun KotlinMoveTarget.getContainerDescriptor(): DeclarationDescriptor? {
|
private fun KotlinMoveTarget.getContainerDescriptor(): DeclarationDescriptor? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is KotlinMoveTargetForExistingElement -> {
|
is KotlinMoveTargetForExistingElement -> when (val targetElement = targetElement) {
|
||||||
val targetElement = targetElement
|
is KtNamedDeclaration -> resolutionFacade.resolveToDescriptor(targetElement)
|
||||||
when (targetElement) {
|
|
||||||
is KtNamedDeclaration -> resolutionFacade.resolveToDescriptor(targetElement)
|
|
||||||
|
|
||||||
is KtFile -> {
|
is KtFile -> {
|
||||||
val packageFragment =
|
val packageFragment =
|
||||||
targetElement
|
targetElement
|
||||||
.findModuleDescriptor()
|
.findModuleDescriptor()
|
||||||
.findPackageFragmentForFile(targetElement)
|
.findPackageFragmentForFile(targetElement)
|
||||||
|
|
||||||
packageFragment?.withSource(targetElement)
|
packageFragment?.withSource(targetElement)
|
||||||
}
|
|
||||||
|
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
is KotlinDirectoryBasedMoveTarget -> {
|
is KotlinDirectoryBasedMoveTarget -> {
|
||||||
@@ -159,8 +145,7 @@ class MoveConflictChecker(
|
|||||||
): DeclarationDescriptor? {
|
): DeclarationDescriptor? {
|
||||||
if (newContainer == null && newVisibility == null) return this
|
if (newContainer == null && newVisibility == null) return this
|
||||||
|
|
||||||
val wrappedDescriptor = this
|
return when (val wrappedDescriptor = this) {
|
||||||
return when (wrappedDescriptor) {
|
|
||||||
// We rely on visibility not depending on more specific type of CallableMemberDescriptor
|
// We rely on visibility not depending on more specific type of CallableMemberDescriptor
|
||||||
is CallableMemberDescriptor -> object : CallableMemberDescriptor by wrappedDescriptor {
|
is CallableMemberDescriptor -> object : CallableMemberDescriptor by wrappedDescriptor {
|
||||||
override fun getOriginal() = this
|
override fun getOriginal() = this
|
||||||
@@ -255,7 +240,7 @@ class MoveConflictChecker(
|
|||||||
val referencedElementsToSkip = newConflicts.keySet().mapNotNullTo(HashSet()) { it.namedUnwrappedElement }
|
val referencedElementsToSkip = newConflicts.keySet().mapNotNullTo(HashSet()) { it.namedUnwrappedElement }
|
||||||
externalUsages.removeIf {
|
externalUsages.removeIf {
|
||||||
it is MoveRenameUsageInfo &&
|
it is MoveRenameUsageInfo &&
|
||||||
it.referencedElement?.namedUnwrappedElement?.let { it in referencedElementsToSkip } ?: false
|
it.referencedElement?.namedUnwrappedElement?.let { element -> element in referencedElementsToSkip } ?: false
|
||||||
}
|
}
|
||||||
conflicts.putAllValues(newConflicts)
|
conflicts.putAllValues(newConflicts)
|
||||||
}
|
}
|
||||||
@@ -318,20 +303,20 @@ class MoveConflictChecker(
|
|||||||
val renderedImportableTarget = DESCRIPTOR_RENDERER_FOR_COMPARISON.render(importableDescriptor)
|
val renderedImportableTarget = DESCRIPTOR_RENDERER_FOR_COMPARISON.render(importableDescriptor)
|
||||||
val renderedTarget by lazy { DESCRIPTOR_RENDERER_FOR_COMPARISON.render(targetDescriptor) }
|
val renderedTarget by lazy { DESCRIPTOR_RENDERER_FOR_COMPARISON.render(targetDescriptor) }
|
||||||
|
|
||||||
return newTargetDescriptors.any {
|
return newTargetDescriptors.any { descriptor ->
|
||||||
if (DESCRIPTOR_RENDERER_FOR_COMPARISON.render(it) != renderedImportableTarget) return@any false
|
if (DESCRIPTOR_RENDERER_FOR_COMPARISON.render(descriptor) != renderedImportableTarget) return@any false
|
||||||
if (importableDescriptor == targetDescriptor) return@any true
|
if (importableDescriptor == targetDescriptor) return@any true
|
||||||
|
|
||||||
val candidateDescriptors: Collection<DeclarationDescriptor> = when (targetDescriptor) {
|
val candidateDescriptors: Collection<DeclarationDescriptor> = when (targetDescriptor) {
|
||||||
is ConstructorDescriptor -> {
|
is ConstructorDescriptor -> {
|
||||||
(it as? ClassDescriptor)?.constructors ?: emptyList<DeclarationDescriptor>()
|
(descriptor as? ClassDescriptor)?.constructors ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
is PropertyAccessorDescriptor -> {
|
is PropertyAccessorDescriptor -> {
|
||||||
(it as? PropertyDescriptor)
|
(descriptor as? PropertyDescriptor)
|
||||||
?.let { if (targetDescriptor is PropertyGetterDescriptor) it.getter else it.setter }
|
?.let { if (targetDescriptor is PropertyGetterDescriptor) it.getter else it.setter }
|
||||||
?.let { listOf(it) }
|
?.let { listOf(it) }
|
||||||
?: emptyList<DeclarationDescriptor>()
|
?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
@@ -375,7 +360,7 @@ class MoveConflictChecker(
|
|||||||
referencesToSkip += refExpr
|
referencesToSkip += refExpr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internalUsages.removeIf { it.reference?.element?.let { it in referencesToSkip } ?: false }
|
internalUsages.removeIf { it.reference?.element?.let { element -> element in referencesToSkip } ?: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkVisibilityInUsages(usages: Collection<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
|
fun checkVisibilityInUsages(usages: Collection<UsageInfo>, conflicts: MultiMap<PsiElement, String>) {
|
||||||
@@ -396,7 +381,7 @@ class MoveConflictChecker(
|
|||||||
) continue
|
) continue
|
||||||
|
|
||||||
val container = element.getUsageContext()
|
val container = element.getUsageContext()
|
||||||
if (!declarationToContainers.getOrPut(referencedElement) { HashSet<PsiElement>() }.add(container)) continue
|
if (!declarationToContainers.getOrPut(referencedElement) { HashSet() }.add(container)) continue
|
||||||
|
|
||||||
val targetContainer = moveTarget.getContainerDescriptor() ?: continue
|
val targetContainer = moveTarget.getContainerDescriptor() ?: continue
|
||||||
|
|
||||||
|
|||||||
+30
-28
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -41,13 +41,13 @@ import java.io.File
|
|||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
|
|
||||||
class KotlinAwareMoveFilesOrDirectoriesDialog(
|
class KotlinAwareMoveFilesOrDirectoriesDialog(
|
||||||
private val project: Project,
|
private val project: Project,
|
||||||
private val initialDirectory: PsiDirectory?,
|
private val initialDirectory: PsiDirectory?,
|
||||||
private val callback: (KotlinAwareMoveFilesOrDirectoriesDialog?) -> Unit
|
private val callback: (KotlinAwareMoveFilesOrDirectoriesDialog?) -> Unit
|
||||||
) : DialogWrapper(project, true) {
|
) : DialogWrapper(project, true) {
|
||||||
companion object {
|
companion object {
|
||||||
private val RECENT_KEYS = "MoveFile.RECENT_KEYS"
|
private const val RECENT_KEYS = "MoveFile.RECENT_KEYS"
|
||||||
private val MOVE_FILES_OPEN_IN_EDITOR = "MoveFile.OpenInEditor"
|
private const val MOVE_FILES_OPEN_IN_EDITOR = "MoveFile.OpenInEditor"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val nameLabel = JBLabelDecorator.createJBLabelDecorator().setBold(true)
|
private val nameLabel = JBLabelDecorator.createJBLabelDecorator().setBold(true)
|
||||||
@@ -81,11 +81,13 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
|||||||
RecentsManager.getInstance(project).getRecentEntries(RECENT_KEYS)?.let { targetDirectoryField.childComponent.history = it }
|
RecentsManager.getInstance(project).getRecentEntries(RECENT_KEYS)?.let { targetDirectoryField.childComponent.history = it }
|
||||||
|
|
||||||
val descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor()
|
val descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor()
|
||||||
targetDirectoryField.addBrowseFolderListener(RefactoringBundle.message("select.target.directory"),
|
targetDirectoryField.addBrowseFolderListener(
|
||||||
RefactoringBundle.message("the.file.will.be.moved.to.this.directory"),
|
RefactoringBundle.message("select.target.directory"),
|
||||||
project,
|
RefactoringBundle.message("the.file.will.be.moved.to.this.directory"),
|
||||||
descriptor,
|
project,
|
||||||
TextComponentAccessor.TEXT_FIELD_WITH_HISTORY_WHOLE_TEXT)
|
descriptor,
|
||||||
|
TextComponentAccessor.TEXT_FIELD_WITH_HISTORY_WHOLE_TEXT
|
||||||
|
)
|
||||||
val textField = targetDirectoryField.childComponent.textEditor
|
val textField = targetDirectoryField.childComponent.textEditor
|
||||||
FileChooserFactory.getInstance().installFileCompletion(textField, descriptor, true, disposable)
|
FileChooserFactory.getInstance().installFileCompletion(textField, descriptor, true, disposable)
|
||||||
textField.onTextChange { validateOKButton() }
|
textField.onTextChange { validateOKButton() }
|
||||||
@@ -96,13 +98,13 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
|||||||
|
|
||||||
val shortcutText = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION))
|
val shortcutText = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION))
|
||||||
return FormBuilder.createFormBuilder()
|
return FormBuilder.createFormBuilder()
|
||||||
.addComponent(nameLabel)
|
.addComponent(nameLabel)
|
||||||
.addLabeledComponent(RefactoringBundle.message("move.files.to.directory.label"), targetDirectoryField, UIUtil.LARGE_VGAP)
|
.addLabeledComponent(RefactoringBundle.message("move.files.to.directory.label"), targetDirectoryField, UIUtil.LARGE_VGAP)
|
||||||
.addTooltip(RefactoringBundle.message("path.completion.shortcut", shortcutText))
|
.addTooltip(RefactoringBundle.message("path.completion.shortcut", shortcutText))
|
||||||
.addComponentToRightColumn(searchReferencesCb, UIUtil.LARGE_VGAP)
|
.addComponentToRightColumn(searchReferencesCb, UIUtil.LARGE_VGAP)
|
||||||
.addComponentToRightColumn(openInEditorCb, UIUtil.LARGE_VGAP)
|
.addComponentToRightColumn(openInEditorCb, UIUtil.LARGE_VGAP)
|
||||||
.addComponentToRightColumn(updatePackageDirectiveCb, UIUtil.LARGE_VGAP)
|
.addComponentToRightColumn(updatePackageDirectiveCb, UIUtil.LARGE_VGAP)
|
||||||
.panel
|
.panel
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setData(psiElements: Array<out PsiElement>, initialTargetDirectory: PsiDirectory?, helpID: String) {
|
fun setData(psiElements: Array<out PsiElement>, initialTargetDirectory: PsiDirectory?, helpID: String) {
|
||||||
@@ -113,8 +115,7 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
|||||||
is PsiFile -> RefactoringBundle.message("move.file.0", shortenedPath)
|
is PsiFile -> RefactoringBundle.message("move.file.0", shortenedPath)
|
||||||
else -> RefactoringBundle.message("move.directory.0", shortenedPath)
|
else -> RefactoringBundle.message("move.directory.0", shortenedPath)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val isFile = psiElements.all { it is PsiFile }
|
val isFile = psiElements.all { it is PsiFile }
|
||||||
val isDirectory = psiElements.all { it is PsiDirectory }
|
val isDirectory = psiElements.all { it is PsiDirectory }
|
||||||
nameLabel.text = when {
|
nameLabel.text = when {
|
||||||
@@ -129,7 +130,7 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
|||||||
validateOKButton()
|
validateOKButton()
|
||||||
this.helpID = helpID
|
this.helpID = helpID
|
||||||
|
|
||||||
with (updatePackageDirectiveCb) {
|
with(updatePackageDirectiveCb) {
|
||||||
val jetFiles = psiElements.filterIsInstance<KtFile>().filter(KtFile::isInJavaSourceRoot)
|
val jetFiles = psiElements.filterIsInstance<KtFile>().filter(KtFile::isInJavaSourceRoot)
|
||||||
if (jetFiles.isEmpty()) {
|
if (jetFiles.isEmpty()) {
|
||||||
parent.remove(updatePackageDirectiveCb)
|
parent.remove(updatePackageDirectiveCb)
|
||||||
@@ -150,7 +151,7 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun validateOKButton() {
|
private fun validateOKButton() {
|
||||||
isOKActionEnabled = targetDirectoryField.childComponent.text.length > 0
|
isOKActionEnabled = targetDirectoryField.childComponent.text.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doOKAction() {
|
override fun doOKAction() {
|
||||||
@@ -172,17 +173,18 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
targetDirectory = DirectoryUtil.mkdirs(PsiManager.getInstance(project), directoryName)
|
targetDirectory = DirectoryUtil.mkdirs(PsiManager.getInstance(project), directoryName)
|
||||||
}
|
} catch (e: IncorrectOperationException) {
|
||||||
catch (e: IncorrectOperationException) {
|
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetDirectory == null) {
|
if (targetDirectory == null) {
|
||||||
CommonRefactoringUtil.showErrorMessage(title,
|
CommonRefactoringUtil.showErrorMessage(
|
||||||
RefactoringBundle.message("cannot.create.directory"),
|
title,
|
||||||
helpID,
|
RefactoringBundle.message("cannot.create.directory"),
|
||||||
project)
|
helpID,
|
||||||
|
project
|
||||||
|
)
|
||||||
return@executeCommand
|
return@executeCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-29
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.ui
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui
|
||||||
@@ -29,10 +18,10 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
|||||||
import java.awt.BorderLayout
|
import java.awt.BorderLayout
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
|
|
||||||
internal class KotlinSelectNestedClassRefactoringDialog private constructor (
|
internal class KotlinSelectNestedClassRefactoringDialog private constructor(
|
||||||
project: Project,
|
project: Project,
|
||||||
private val nestedClass: KtClassOrObject,
|
private val nestedClass: KtClassOrObject,
|
||||||
private val targetContainer: PsiElement?
|
private val targetContainer: PsiElement?
|
||||||
) : DialogWrapper(project, true) {
|
) : DialogWrapper(project, true) {
|
||||||
private val moveToUpperLevelButton = JRadioButton()
|
private val moveToUpperLevelButton = JRadioButton()
|
||||||
private val moveMembersButton = JRadioButton()
|
private val moveMembersButton = JRadioButton()
|
||||||
@@ -83,32 +72,34 @@ internal class KotlinSelectNestedClassRefactoringDialog private constructor (
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun MoveKotlinNestedClassesToUpperLevelDialog(
|
private fun MoveKotlinNestedClassesToUpperLevelDialog(
|
||||||
nestedClass: KtClassOrObject,
|
nestedClass: KtClassOrObject,
|
||||||
targetContainer: PsiElement?
|
targetContainer: PsiElement?
|
||||||
): MoveKotlinNestedClassesToUpperLevelDialog? {
|
): MoveKotlinNestedClassesToUpperLevelDialog? {
|
||||||
val outerClass = nestedClass.containingClassOrObject ?: return null
|
val outerClass = nestedClass.containingClassOrObject ?: return null
|
||||||
val newTarget = targetContainer
|
val newTarget = targetContainer
|
||||||
?: outerClass.containingClassOrObject
|
?: outerClass.containingClassOrObject
|
||||||
?: outerClass.containingFile.let { it.containingDirectory ?: it }
|
?: outerClass.containingFile.let { it.containingDirectory ?: it }
|
||||||
return MoveKotlinNestedClassesToUpperLevelDialog(nestedClass.project, nestedClass, newTarget)
|
return MoveKotlinNestedClassesToUpperLevelDialog(nestedClass.project, nestedClass, newTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MoveKotlinNestedClassesDialog(
|
private fun MoveKotlinNestedClassesDialog(
|
||||||
nestedClass: KtClassOrObject,
|
nestedClass: KtClassOrObject,
|
||||||
targetContainer: PsiElement?
|
targetContainer: PsiElement?
|
||||||
): MoveKotlinNestedClassesDialog {
|
): MoveKotlinNestedClassesDialog {
|
||||||
return MoveKotlinNestedClassesDialog(nestedClass.project,
|
return MoveKotlinNestedClassesDialog(
|
||||||
listOf(nestedClass),
|
nestedClass.project,
|
||||||
nestedClass.containingClassOrObject!!,
|
listOf(nestedClass),
|
||||||
targetContainer as? KtClassOrObject ?: nestedClass.containingClassOrObject!!,
|
nestedClass.containingClassOrObject!!,
|
||||||
null)
|
targetContainer as? KtClassOrObject ?: nestedClass.containingClassOrObject!!,
|
||||||
|
null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun chooseNestedClassRefactoring(nestedClass: KtClassOrObject, targetContainer: PsiElement?) {
|
fun chooseNestedClassRefactoring(nestedClass: KtClassOrObject, targetContainer: PsiElement?) {
|
||||||
val project = nestedClass.project
|
val project = nestedClass.project
|
||||||
val dialog = when {
|
val dialog = when {
|
||||||
targetContainer != null && targetContainer !is KtClassOrObject ||
|
targetContainer != null && targetContainer !is KtClassOrObject ||
|
||||||
nestedClass is KtClass && nestedClass.isInner() -> {
|
nestedClass is KtClass && nestedClass.isInner() -> {
|
||||||
MoveKotlinNestedClassesToUpperLevelDialog(nestedClass, targetContainer)
|
MoveKotlinNestedClassesToUpperLevelDialog(nestedClass, targetContainer)
|
||||||
}
|
}
|
||||||
nestedClass is KtEnumEntry -> return
|
nestedClass is KtEnumEntry -> return
|
||||||
|
|||||||
+39
-64
@@ -1,23 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.ui;
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
||||||
|
|
||||||
import com.intellij.codeInsight.lookup.LookupElement;
|
|
||||||
import com.intellij.ide.util.ClassFilter;
|
|
||||||
import com.intellij.ide.util.TreeClassChooser;
|
import com.intellij.ide.util.TreeClassChooser;
|
||||||
import com.intellij.ide.util.TreeJavaClassChooserDialog;
|
import com.intellij.ide.util.TreeJavaClassChooserDialog;
|
||||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||||
@@ -36,7 +23,6 @@ import com.intellij.refactoring.move.MoveCallback;
|
|||||||
import com.intellij.refactoring.move.MoveHandler;
|
import com.intellij.refactoring.move.MoveHandler;
|
||||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import kotlin.jvm.functions.Function1;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
|
||||||
@@ -59,8 +45,7 @@ import java.awt.*;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import static org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessorKt.MoveSource;
|
|
||||||
|
|
||||||
public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
||||||
private static final String RECENTS_KEY = MoveKotlinNestedClassesDialog.class.getName() + ".RECENTS_KEY";
|
private static final String RECENTS_KEY = MoveKotlinNestedClassesDialog.class.getName() + ".RECENTS_KEY";
|
||||||
@@ -74,6 +59,7 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
private JPanel targetClassChooserPanel;
|
private JPanel targetClassChooserPanel;
|
||||||
private KotlinMemberSelectionTable memberTable;
|
private KotlinMemberSelectionTable memberTable;
|
||||||
private PsiElement targetClass;
|
private PsiElement targetClass;
|
||||||
|
|
||||||
public MoveKotlinNestedClassesDialog(
|
public MoveKotlinNestedClassesDialog(
|
||||||
@NotNull Project project,
|
@NotNull Project project,
|
||||||
@NotNull List<KtClassOrObject> elementsToMove,
|
@NotNull List<KtClassOrObject> elementsToMove,
|
||||||
@@ -111,23 +97,20 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
RefactoringBundle.message("choose.destination.class"),
|
RefactoringBundle.message("choose.destination.class"),
|
||||||
myProject,
|
myProject,
|
||||||
GlobalSearchScope.projectScope(myProject),
|
GlobalSearchScope.projectScope(myProject),
|
||||||
new ClassFilter() {
|
aClass -> {
|
||||||
@Override
|
if (!(aClass instanceof KtLightClassForSourceDeclaration)) return false;
|
||||||
public boolean isAccepted(PsiClass aClass) {
|
KtClassOrObject classOrObject = ((KtLightClassForSourceDeclaration) aClass).getKotlinOrigin();
|
||||||
if (!(aClass instanceof KtLightClassForSourceDeclaration)) return false;
|
|
||||||
KtClassOrObject classOrObject = ((KtLightClassForSourceDeclaration) aClass).getKotlinOrigin();
|
|
||||||
|
|
||||||
if (classOrObject instanceof KtObjectDeclaration) {
|
if (classOrObject instanceof KtObjectDeclaration) {
|
||||||
return !((KtObjectDeclaration) classOrObject).isObjectLiteral();
|
return !((KtObjectDeclaration) classOrObject).isObjectLiteral();
|
||||||
}
|
|
||||||
|
|
||||||
if (classOrObject instanceof KtClass) {
|
|
||||||
KtClass ktClass = (KtClass) classOrObject;
|
|
||||||
return !(ktClass.isInner() || ktClass.isAnnotation());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (classOrObject instanceof KtClass) {
|
||||||
|
KtClass ktClass = (KtClass) classOrObject;
|
||||||
|
return !(ktClass.isInner() || ktClass.isAnnotation());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
@@ -144,13 +127,14 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
return LightClassUtilsKt.toLightClass(((KtClassOrObjectTreeNode) userObject).getValue());
|
return LightClassUtilsKt.toLightClass(((KtClassOrObjectTreeNode) userObject).getValue());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
chooser.selectDirectory((targetClass != null ? targetClass : originalClass).getContainingFile().getContainingDirectory());
|
chooser.selectDirectory(
|
||||||
|
(targetClass != null ? targetClass : originalClass).getContainingFile().getContainingDirectory());
|
||||||
chooser.showDialog();
|
chooser.showDialog();
|
||||||
|
|
||||||
PsiClass aClass = chooser.getSelected();
|
PsiClass aClass = chooser.getSelected();
|
||||||
if (aClass instanceof KtLightClassForSourceDeclaration) {
|
if (aClass instanceof KtLightClassForSourceDeclaration) {
|
||||||
targetClass = ((KtLightClassForSourceDeclaration) aClass).getKotlinOrigin();
|
targetClass = ((KtLightClassForSourceDeclaration) aClass).getKotlinOrigin();
|
||||||
targetClassChooser.setText(aClass.getQualifiedName());
|
targetClassChooser.setText(Objects.requireNonNull(aClass.getQualifiedName()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
targetClass = aClass;
|
targetClass = aClass;
|
||||||
@@ -164,15 +148,12 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
if (codeFragment != null) {
|
if (codeFragment != null) {
|
||||||
CompletionUtilsKt.setExtraCompletionFilter(
|
CompletionUtilsKt.setExtraCompletionFilter(
|
||||||
codeFragment,
|
codeFragment,
|
||||||
new Function1<LookupElement, Boolean>() {
|
lookupElement -> {
|
||||||
@Override
|
Object lookupObject = lookupElement.getObject();
|
||||||
public Boolean invoke(LookupElement lookupElement) {
|
if (!(lookupObject instanceof DeclarationLookupObject)) return false;
|
||||||
Object lookupObject = lookupElement.getObject();
|
PsiElement psiElement = ((DeclarationLookupObject) lookupObject).getPsiElement();
|
||||||
if (!(lookupObject instanceof DeclarationLookupObject)) return false;
|
if (lookupObject instanceof PackageLookupObject) return true;
|
||||||
PsiElement psiElement = ((DeclarationLookupObject) lookupObject).getPsiElement();
|
return (psiElement instanceof KtClassOrObject) && KotlinRefactoringUtilKt.canRefactor(psiElement);
|
||||||
if (lookupObject instanceof PackageLookupObject) return true;
|
|
||||||
return (psiElement instanceof KtClassOrObject) && KotlinRefactoringUtilKt.canRefactor(psiElement);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -193,28 +174,27 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
targetClassChooserPanel.add(targetClassChooser);
|
targetClassChooserPanel.add(targetClassChooser);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initMemberInfo(@NotNull final List<KtClassOrObject> elementsToMove) {
|
private void initMemberInfo(@NotNull List<KtClassOrObject> elementsToMove) {
|
||||||
List<KotlinMemberInfo> memberInfos = CollectionsKt.mapNotNull(
|
List<KotlinMemberInfo> memberInfos = CollectionsKt.mapNotNull(
|
||||||
originalClass.getDeclarations(),
|
originalClass.getDeclarations(),
|
||||||
new Function1<KtDeclaration, KotlinMemberInfo>() {
|
declaration -> {
|
||||||
@Override
|
if (!(declaration instanceof KtClassOrObject)) return null;
|
||||||
public KotlinMemberInfo invoke(KtDeclaration declaration) {
|
KtClassOrObject classOrObject = (KtClassOrObject) declaration;
|
||||||
if (!(declaration instanceof KtClassOrObject)) return null;
|
|
||||||
KtClassOrObject classOrObject = (KtClassOrObject) declaration;
|
|
||||||
|
|
||||||
if (classOrObject instanceof KtClass && ((KtClass) classOrObject).isInner()) return null;
|
if (classOrObject instanceof KtClass && ((KtClass) classOrObject).isInner()) return null;
|
||||||
if (classOrObject instanceof KtObjectDeclaration && ((KtObjectDeclaration) classOrObject).isCompanion()) return null;
|
if (classOrObject instanceof KtObjectDeclaration && ((KtObjectDeclaration) classOrObject).isCompanion()) {
|
||||||
|
return null;
|
||||||
KotlinMemberInfo memberInfo = new KotlinMemberInfo(classOrObject, false);
|
|
||||||
memberInfo.setChecked(elementsToMove.contains(declaration));
|
|
||||||
return memberInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KotlinMemberInfo memberInfo = new KotlinMemberInfo(classOrObject, false);
|
||||||
|
memberInfo.setChecked(elementsToMove.contains(declaration));
|
||||||
|
return memberInfo;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
KotlinMemberSelectionPanel selectionPanel = new KotlinMemberSelectionPanel(getTitle(), memberInfos, null);
|
KotlinMemberSelectionPanel selectionPanel = new KotlinMemberSelectionPanel(getTitle(), memberInfos, null);
|
||||||
memberTable = selectionPanel.getTable();
|
memberTable = selectionPanel.getTable();
|
||||||
MemberInfoModelImpl memberInfoModel = new MemberInfoModelImpl();
|
MemberInfoModelImpl memberInfoModel = new MemberInfoModelImpl();
|
||||||
memberInfoModel.memberInfoChanged(new MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo>(memberInfos));
|
memberInfoModel.memberInfoChanged(new MemberInfoChange<>(memberInfos));
|
||||||
selectionPanel.getTable().setMemberInfoModel(memberInfoModel);
|
selectionPanel.getTable().setMemberInfoModel(memberInfoModel);
|
||||||
selectionPanel.getTable().addMemberInfoChangeListener(memberInfoModel);
|
selectionPanel.getTable().addMemberInfoChangeListener(memberInfoModel);
|
||||||
membersInfoPanel.add(selectionPanel, BorderLayout.CENTER);
|
membersInfoPanel.add(selectionPanel, BorderLayout.CENTER);
|
||||||
@@ -223,12 +203,7 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
private List<KtClassOrObject> getSelectedElementsToMove() {
|
private List<KtClassOrObject> getSelectedElementsToMove() {
|
||||||
return CollectionsKt.map(
|
return CollectionsKt.map(
|
||||||
memberTable.getSelectedMemberInfos(),
|
memberTable.getSelectedMemberInfos(),
|
||||||
new Function1<KotlinMemberInfo, KtClassOrObject>() {
|
info -> (KtClassOrObject) info.getMember()
|
||||||
@Override
|
|
||||||
public KtClassOrObject invoke(KotlinMemberInfo info) {
|
|
||||||
return (KtClassOrObject) info.getMember();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +241,7 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
|||||||
MoveDeclarationsDelegate.NestedClass delegate = new MoveDeclarationsDelegate.NestedClass();
|
MoveDeclarationsDelegate.NestedClass delegate = new MoveDeclarationsDelegate.NestedClass();
|
||||||
MoveDeclarationsDescriptor descriptor = new MoveDeclarationsDescriptor(
|
MoveDeclarationsDescriptor descriptor = new MoveDeclarationsDescriptor(
|
||||||
myProject,
|
myProject,
|
||||||
MoveSource(elementsToMove),
|
MoveKotlinDeclarationsProcessorKt.MoveSource(elementsToMove),
|
||||||
target,
|
target,
|
||||||
delegate,
|
delegate,
|
||||||
false,
|
false,
|
||||||
|
|||||||
+37
-64
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.ui;
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
||||||
@@ -66,13 +55,9 @@ import org.jetbrains.kotlin.types.KotlinType;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ItemEvent;
|
|
||||||
import java.awt.event.ItemListener;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessorKt.MoveSource;
|
|
||||||
|
|
||||||
public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||||
@NonNls private static final String RECENTS_KEY = MoveKotlinNestedClassesToUpperLevelDialog.class.getName() + ".RECENTS_KEY";
|
@NonNls private static final String RECENTS_KEY = MoveKotlinNestedClassesToUpperLevelDialog.class.getName() + ".RECENTS_KEY";
|
||||||
|
|
||||||
@@ -160,7 +145,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isThisNeeded() {
|
private boolean isThisNeeded() {
|
||||||
return innerClass instanceof KtClass && MoveUtilsKt.traverseOuterInstanceReferences((KtClass) innerClass, true);
|
return innerClass instanceof KtClass && MoveUtilsKt.traverseOuterInstanceReferences(innerClass, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -180,12 +165,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
|
|
||||||
if (innerClass instanceof KtClass && ((KtClass) innerClass).isInner()) {
|
if (innerClass instanceof KtClass && ((KtClass) innerClass).isInner()) {
|
||||||
passOuterClassCheckBox.setSelected(true);
|
passOuterClassCheckBox.setSelected(true);
|
||||||
passOuterClassCheckBox.addItemListener(new ItemListener() {
|
passOuterClassCheckBox.addItemListener(e -> parameterField.setEnabled(passOuterClassCheckBox.isSelected()));
|
||||||
@Override
|
|
||||||
public void itemStateChanged(ItemEvent e) {
|
|
||||||
parameterField.setEnabled(passOuterClassCheckBox.isSelected());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
passOuterClassCheckBox.setSelected(false);
|
passOuterClassCheckBox.setSelected(false);
|
||||||
@@ -199,12 +179,9 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
parameterField.setEnabled(thisNeeded);
|
parameterField.setEnabled(thisNeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
passOuterClassCheckBox.addItemListener(new ItemListener() {
|
passOuterClassCheckBox.addItemListener(e -> {
|
||||||
@Override
|
boolean selected = passOuterClassCheckBox.isSelected();
|
||||||
public void itemStateChanged(ItemEvent e) {
|
parameterField.getComponent().setEnabled(selected);
|
||||||
boolean selected = passOuterClassCheckBox.isSelected();
|
|
||||||
parameterField.getComponent().setEnabled(selected);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(targetContainer instanceof PsiDirectory)) {
|
if (!(targetContainer instanceof PsiDirectory)) {
|
||||||
@@ -218,7 +195,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
innerClassBody != null
|
innerClassBody != null
|
||||||
? new NewDeclarationNameValidator(innerClassBody, (PsiElement) null,
|
? new NewDeclarationNameValidator(innerClassBody, (PsiElement) null,
|
||||||
NewDeclarationNameValidator.Target.VARIABLES,
|
NewDeclarationNameValidator.Target.VARIABLES,
|
||||||
Collections.<KtDeclaration>emptyList())
|
Collections.emptyList())
|
||||||
: new CollectingNameValidator();
|
: new CollectingNameValidator();
|
||||||
List<String> suggestions = KotlinNameSuggester.INSTANCE.suggestNamesByType(getOuterInstanceType(), validator, "outer");
|
List<String> suggestions = KotlinNameSuggester.INSTANCE.suggestNamesByType(getOuterInstanceType(), validator, "outer");
|
||||||
parameterField.setSuggestions(ArrayUtil.toStringArray(suggestions));
|
parameterField.setSuggestions(ArrayUtil.toStringArray(suggestions));
|
||||||
@@ -268,8 +245,8 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
if (!Comparing.equal(oldPackageFqName != null ? oldPackageFqName.asString() : null, targetName)) {
|
if (!Comparing.equal(oldPackageFqName != null ? oldPackageFqName.asString() : null, targetName)) {
|
||||||
ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project);
|
ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project);
|
||||||
List<VirtualFile> contentSourceRoots = JavaProjectRootsUtil.getSuitableDestinationSourceRoots(project);
|
List<VirtualFile> contentSourceRoots = JavaProjectRootsUtil.getSuitableDestinationSourceRoots(project);
|
||||||
final PackageWrapper newPackage = new PackageWrapper(PsiManager.getInstance(project), targetName);
|
PackageWrapper newPackage = new PackageWrapper(PsiManager.getInstance(project), targetName);
|
||||||
final VirtualFile targetSourceRoot;
|
VirtualFile targetSourceRoot;
|
||||||
if (contentSourceRoots.size() > 1) {
|
if (contentSourceRoots.size() > 1) {
|
||||||
PsiDirectory initialDir = null;
|
PsiDirectory initialDir = null;
|
||||||
PsiPackage oldPackage = oldPackageFqName != null
|
PsiPackage oldPackage = oldPackageFqName != null
|
||||||
@@ -293,15 +270,12 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
}
|
}
|
||||||
PsiDirectory dir = RefactoringUtil.findPackageDirectoryInSourceRoot(newPackage, targetSourceRoot);
|
PsiDirectory dir = RefactoringUtil.findPackageDirectoryInSourceRoot(newPackage, targetSourceRoot);
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
dir = ApplicationManager.getApplication().runWriteAction(new NullableComputable<PsiDirectory>() {
|
dir = ApplicationManager.getApplication().runWriteAction((NullableComputable<PsiDirectory>) () -> {
|
||||||
@Override
|
try {
|
||||||
public PsiDirectory compute() {
|
return RefactoringUtil.createPackageDirectoryInSourceRoot(newPackage, targetSourceRoot);
|
||||||
try {
|
}
|
||||||
return RefactoringUtil.createPackageDirectoryInSourceRoot(newPackage, targetSourceRoot);
|
catch (IncorrectOperationException e) {
|
||||||
}
|
return null;
|
||||||
catch (IncorrectOperationException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -321,12 +295,20 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
String className = getClassName();
|
String className = getClassName();
|
||||||
String parameterName = getParameterName();
|
String parameterName = getParameterName();
|
||||||
|
|
||||||
if (className != null && className.isEmpty()) throw new ConfigurationException(RefactoringBundle.message("no.class.name.specified"));
|
if (className != null && className.isEmpty()) {
|
||||||
if (!KtPsiUtilKt.isIdentifier(className)) throw new ConfigurationException(RefactoringMessageUtil.getIncorrectIdentifierMessage(className));
|
throw new ConfigurationException(RefactoringBundle.message("no.class.name.specified"));
|
||||||
|
}
|
||||||
|
if (!KtPsiUtilKt.isIdentifier(className)) {
|
||||||
|
throw new ConfigurationException(RefactoringMessageUtil.getIncorrectIdentifierMessage(className));
|
||||||
|
}
|
||||||
|
|
||||||
if (passOuterClassCheckBox.isSelected()) {
|
if (passOuterClassCheckBox.isSelected()) {
|
||||||
if (parameterName != null && parameterName.isEmpty()) throw new ConfigurationException(RefactoringBundle.message("no.parameter.name.specified"));
|
if (parameterName != null && parameterName.isEmpty()) {
|
||||||
if (!KtPsiUtilKt.isIdentifier(parameterName)) throw new ConfigurationException(RefactoringMessageUtil.getIncorrectIdentifierMessage(parameterName));
|
throw new ConfigurationException(RefactoringBundle.message("no.parameter.name.specified"));
|
||||||
|
}
|
||||||
|
if (!KtPsiUtilKt.isIdentifier(parameterName)) {
|
||||||
|
throw new ConfigurationException(RefactoringMessageUtil.getIncorrectIdentifierMessage(parameterName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PsiElement targetContainer = getTargetContainer();
|
PsiElement targetContainer = getTargetContainer();
|
||||||
@@ -350,7 +332,9 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
.getPackage(targetPackageFqName)
|
.getPackage(targetPackageFqName)
|
||||||
.getMemberScope()
|
.getMemberScope()
|
||||||
.getContributedClassifier(Name.identifier(className), NoLookupLocation.FROM_IDE);
|
.getContributedClassifier(Name.identifier(className), NoLookupLocation.FROM_IDE);
|
||||||
if (existingClass != null) throw new ConfigurationException("Class " + className + " already exists in package " + targetPackageFqName);
|
if (existingClass != null) {
|
||||||
|
throw new ConfigurationException("Class " + className + " already exists in package " + targetPackageFqName);
|
||||||
|
}
|
||||||
|
|
||||||
PsiDirectory targetDir = targetContainer instanceof PsiDirectory
|
PsiDirectory targetDir = targetContainer instanceof PsiDirectory
|
||||||
? (PsiDirectory) targetContainer
|
? (PsiDirectory) targetContainer
|
||||||
@@ -382,34 +366,23 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
|
|
||||||
KotlinMoveTarget moveTarget;
|
KotlinMoveTarget moveTarget;
|
||||||
if (target instanceof PsiDirectory) {
|
if (target instanceof PsiDirectory) {
|
||||||
final PsiDirectory targetDir = (PsiDirectory) target;
|
PsiDirectory targetDir = (PsiDirectory) target;
|
||||||
|
|
||||||
final FqName targetPackageFqName = getTargetPackageFqName(target);
|
FqName targetPackageFqName = getTargetPackageFqName(target);
|
||||||
if (targetPackageFqName == null) return;
|
if (targetPackageFqName == null) return;
|
||||||
|
|
||||||
final String targetFileName = KotlinNameSuggester.INSTANCE.suggestNameByName(
|
String targetFileName = KotlinNameSuggester.INSTANCE.suggestNameByName(
|
||||||
newClassName,
|
newClassName,
|
||||||
new Function1<String, Boolean>() {
|
s -> targetDir.findFile(s + "." + KotlinFileType.EXTENSION) == null
|
||||||
@Override
|
|
||||||
public Boolean invoke(String s) {
|
|
||||||
return targetDir.findFile(s + "." + KotlinFileType.EXTENSION) == null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) + "." + KotlinFileType.EXTENSION;
|
) + "." + KotlinFileType.EXTENSION;
|
||||||
moveTarget = new KotlinMoveTargetForDeferredFile(
|
moveTarget = new KotlinMoveTargetForDeferredFile(
|
||||||
targetPackageFqName,
|
targetPackageFqName,
|
||||||
targetDir,
|
targetDir,
|
||||||
null,
|
null,
|
||||||
new Function1<KtFile, KtFile>() {
|
originalFile -> KotlinRefactoringUtilKt.createKotlinFile(targetFileName, targetDir, targetPackageFqName.asString())
|
||||||
@Override
|
|
||||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
|
||||||
return KotlinRefactoringUtilKt.createKotlinFile(targetFileName, targetDir, targetPackageFqName.asString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//noinspection ConstantConditions
|
|
||||||
moveTarget = new KotlinMoveTargetForExistingElement((KtElement) target);
|
moveTarget = new KotlinMoveTargetForExistingElement((KtElement) target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +390,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
|||||||
MoveDeclarationsDelegate delegate = new MoveDeclarationsDelegate.NestedClass(newClassName, outerInstanceParameterName);
|
MoveDeclarationsDelegate delegate = new MoveDeclarationsDelegate.NestedClass(newClassName, outerInstanceParameterName);
|
||||||
MoveDeclarationsDescriptor moveDescriptor = new MoveDeclarationsDescriptor(
|
MoveDeclarationsDescriptor moveDescriptor = new MoveDeclarationsDescriptor(
|
||||||
project,
|
project,
|
||||||
MoveSource(innerClass),
|
MoveKotlinDeclarationsProcessorKt.MoveSource(innerClass),
|
||||||
moveTarget,
|
moveTarget,
|
||||||
delegate,
|
delegate,
|
||||||
isSearchInComments(),
|
isSearchInComments(),
|
||||||
|
|||||||
+68
-167
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.ui;
|
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui;
|
||||||
@@ -32,8 +21,10 @@ import com.intellij.openapi.util.Pass;
|
|||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
|
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||||
import com.intellij.refactoring.*;
|
import com.intellij.refactoring.*;
|
||||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel;
|
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel;
|
||||||
|
import com.intellij.refactoring.classMembers.MemberInfoBase;
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoChange;
|
import com.intellij.refactoring.classMembers.MemberInfoChange;
|
||||||
import com.intellij.refactoring.classMembers.MemberInfoChangeListener;
|
import com.intellij.refactoring.classMembers.MemberInfoChangeListener;
|
||||||
import com.intellij.refactoring.move.MoveCallback;
|
import com.intellij.refactoring.move.MoveCallback;
|
||||||
@@ -46,12 +37,9 @@ import com.intellij.refactoring.util.CommonRefactoringUtil;
|
|||||||
import com.intellij.ui.ComboboxWithBrowseButton;
|
import com.intellij.ui.ComboboxWithBrowseButton;
|
||||||
import com.intellij.ui.RecentsManager;
|
import com.intellij.ui.RecentsManager;
|
||||||
import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
|
import com.intellij.ui.ReferenceEditorComboWithBrowseButton;
|
||||||
import com.intellij.util.Function;
|
|
||||||
import com.intellij.util.IncorrectOperationException;
|
import com.intellij.util.IncorrectOperationException;
|
||||||
import com.intellij.util.ui.UIUtil;
|
import com.intellij.util.ui.UIUtil;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
import kotlin.jvm.functions.Function0;
|
|
||||||
import kotlin.jvm.functions.Function1;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType;
|
import org.jetbrains.kotlin.idea.KotlinFileType;
|
||||||
@@ -70,19 +58,17 @@ import org.jetbrains.kotlin.idea.util.application.ApplicationUtilsKt;
|
|||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration;
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration;
|
||||||
|
import org.jetbrains.kotlin.psi.KtPureElement;
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessorKt.MoveSource;
|
|
||||||
|
|
||||||
public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||||
private static final String RECENTS_KEY = "MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY";
|
private static final String RECENTS_KEY = "MoveKotlinTopLevelDeclarationsDialog.RECENTS_KEY";
|
||||||
@@ -143,12 +129,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
return CollectionsKt.distinct(
|
return CollectionsKt.distinct(
|
||||||
CollectionsKt.map(
|
CollectionsKt.map(
|
||||||
elementsToMove,
|
elementsToMove,
|
||||||
new Function1<KtNamedDeclaration, KtFile>() {
|
KtPureElement::getContainingKtFile
|
||||||
@Override
|
|
||||||
public KtFile invoke(KtNamedDeclaration declaration) {
|
|
||||||
return declaration.getContainingKtFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -159,12 +140,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
CollectionsKt.distinct(
|
CollectionsKt.distinct(
|
||||||
CollectionsKt.map(
|
CollectionsKt.map(
|
||||||
sourceFiles,
|
sourceFiles,
|
||||||
new Function1<KtFile, PsiDirectory>() {
|
PsiFileImpl::getParent
|
||||||
@Override
|
|
||||||
public PsiDirectory invoke(KtFile jetFile) {
|
|
||||||
return jetFile.getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -174,12 +150,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
return CollectionsKt.filterIsInstance(
|
return CollectionsKt.filterIsInstance(
|
||||||
CollectionsKt.flatMap(
|
CollectionsKt.flatMap(
|
||||||
sourceFiles,
|
sourceFiles,
|
||||||
new Function1<KtFile, Iterable<?>>() {
|
KtPsiUtilKt::getFileOrScriptDeclarations
|
||||||
@Override
|
|
||||||
public Iterable<?> invoke(KtFile ktFile) {
|
|
||||||
return KtPsiUtilKt.getFileOrScriptDeclarations(ktFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
),
|
||||||
KtNamedDeclaration.class
|
KtNamedDeclaration.class
|
||||||
);
|
);
|
||||||
@@ -196,7 +167,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
private static List<PsiFile> getFilesExistingInTargetDir(
|
private static List<PsiFile> getFilesExistingInTargetDir(
|
||||||
@NotNull List<KtFile> sourceFiles,
|
@NotNull List<KtFile> sourceFiles,
|
||||||
@Nullable String targetFileName,
|
@Nullable String targetFileName,
|
||||||
@Nullable final PsiDirectory targetDirectory
|
@Nullable PsiDirectory targetDirectory
|
||||||
) {
|
) {
|
||||||
if (targetDirectory == null) return emptyList();
|
if (targetDirectory == null) return emptyList();
|
||||||
|
|
||||||
@@ -205,62 +176,44 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
? Collections.singletonList(targetFileName)
|
? Collections.singletonList(targetFileName)
|
||||||
: CollectionsKt.map(
|
: CollectionsKt.map(
|
||||||
sourceFiles,
|
sourceFiles,
|
||||||
new Function1<KtFile, String>() {
|
PsiFileImpl::getName
|
||||||
@Override
|
|
||||||
public String invoke(KtFile jetFile) {
|
|
||||||
return jetFile.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return CollectionsKt.filterNotNull(
|
return CollectionsKt.filterNotNull(
|
||||||
CollectionsKt.map(
|
CollectionsKt.map(
|
||||||
fileNames,
|
fileNames,
|
||||||
new Function1<String, PsiFile>() {
|
targetDirectory::findFile
|
||||||
@Override
|
|
||||||
public PsiFile invoke(String s) {
|
|
||||||
return targetDirectory.findFile(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initMemberInfo(
|
private void initMemberInfo(
|
||||||
@NotNull final Set<KtNamedDeclaration> elementsToMove,
|
@NotNull Set<KtNamedDeclaration> elementsToMove,
|
||||||
@NotNull List<KtFile> sourceFiles
|
@NotNull List<KtFile> sourceFiles
|
||||||
) {
|
) {
|
||||||
final List<KotlinMemberInfo> memberInfos = CollectionsKt.map(
|
List<KotlinMemberInfo> memberInfos = CollectionsKt.map(
|
||||||
getAllDeclarations(sourceFiles),
|
getAllDeclarations(sourceFiles),
|
||||||
new Function1<KtNamedDeclaration, KotlinMemberInfo>() {
|
declaration -> {
|
||||||
@Override
|
KotlinMemberInfo memberInfo = new KotlinMemberInfo(declaration, false);
|
||||||
public KotlinMemberInfo invoke(KtNamedDeclaration declaration) {
|
memberInfo.setChecked(elementsToMove.contains(declaration));
|
||||||
KotlinMemberInfo memberInfo = new KotlinMemberInfo(declaration, false);
|
return memberInfo;
|
||||||
memberInfo.setChecked(elementsToMove.contains(declaration));
|
|
||||||
return memberInfo;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
KotlinMemberSelectionPanel selectionPanel = new KotlinMemberSelectionPanel(getTitle(), memberInfos, null);
|
KotlinMemberSelectionPanel selectionPanel = new KotlinMemberSelectionPanel(getTitle(), memberInfos, null);
|
||||||
memberTable = selectionPanel.getTable();
|
memberTable = selectionPanel.getTable();
|
||||||
MemberInfoModelImpl memberInfoModel = new MemberInfoModelImpl();
|
MemberInfoModelImpl memberInfoModel = new MemberInfoModelImpl();
|
||||||
memberInfoModel.memberInfoChanged(new MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo>(memberInfos));
|
memberInfoModel.memberInfoChanged(new MemberInfoChange<>(memberInfos));
|
||||||
selectionPanel.getTable().setMemberInfoModel(memberInfoModel);
|
selectionPanel.getTable().setMemberInfoModel(memberInfoModel);
|
||||||
selectionPanel.getTable().addMemberInfoChangeListener(memberInfoModel);
|
selectionPanel.getTable().addMemberInfoChangeListener(memberInfoModel);
|
||||||
selectionPanel.getTable().addMemberInfoChangeListener(
|
selectionPanel.getTable().addMemberInfoChangeListener(
|
||||||
new MemberInfoChangeListener<KtNamedDeclaration, KotlinMemberInfo>() {
|
new MemberInfoChangeListener<KtNamedDeclaration, KotlinMemberInfo>() {
|
||||||
private boolean shouldUpdateFileNameField(final Collection<KotlinMemberInfo> changedMembers) {
|
private boolean shouldUpdateFileNameField(Collection<KotlinMemberInfo> changedMembers) {
|
||||||
if (!tfFileNameInPackage.isEnabled()) return true;
|
if (!tfFileNameInPackage.isEnabled()) return true;
|
||||||
|
|
||||||
Collection<KtNamedDeclaration> previousDeclarations = CollectionsKt.filterNotNull(
|
Collection<KtNamedDeclaration> previousDeclarations = CollectionsKt.filterNotNull(
|
||||||
CollectionsKt.map(
|
CollectionsKt.map(
|
||||||
memberInfos,
|
memberInfos,
|
||||||
new Function1<KotlinMemberInfo, KtNamedDeclaration>() {
|
info -> changedMembers.contains(info) != info.isChecked() ? info.getMember() : null
|
||||||
@Override
|
|
||||||
public KtNamedDeclaration invoke(KotlinMemberInfo info) {
|
|
||||||
return changedMembers.contains(info) != info.isChecked() ? info.getMember() : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
String suggestedText = previousDeclarations.isEmpty()
|
String suggestedText = previousDeclarations.isEmpty()
|
||||||
@@ -270,7 +223,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void memberInfoChanged(MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo> event) {
|
public void memberInfoChanged(@NotNull MemberInfoChange<KtNamedDeclaration, KotlinMemberInfo> event) {
|
||||||
updatePackageDirectiveCheckBox();
|
updatePackageDirectiveCheckBox();
|
||||||
updateFileNameInPackageField();
|
updateFileNameInPackageField();
|
||||||
// Update file name field only if it user hasn't changed it to some non-default value
|
// Update file name field only if it user hasn't changed it to some non-default value
|
||||||
@@ -285,7 +238,6 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
private void updateSuggestedFileName() {
|
private void updateSuggestedFileName() {
|
||||||
tfFileNameInPackage.setText(MoveUtilsKt.guessNewFileName(getSelectedElementsToMove()));
|
tfFileNameInPackage.setText(MoveUtilsKt.guessNewFileName(getSelectedElementsToMove()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFileNameInPackageField() {
|
private void updateFileNameInPackageField() {
|
||||||
@@ -316,14 +268,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
classPackageChooser.getChildComponent()
|
classPackageChooser.getChildComponent()
|
||||||
);
|
);
|
||||||
|
|
||||||
cbSpecifyFileNameInPackage.addActionListener(
|
cbSpecifyFileNameInPackage.addActionListener(e -> updateFileNameInPackageField());
|
||||||
new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(@NotNull ActionEvent e) {
|
|
||||||
updateFileNameInPackageField();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
cbUpdatePackageDirective.setSelected(arePackagesAndDirectoryMatched(sourceFiles));
|
cbUpdatePackageDirective.setSelected(arePackagesAndDirectoryMatched(sourceFiles));
|
||||||
}
|
}
|
||||||
@@ -342,22 +287,16 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rbMoveToPackage.addActionListener(
|
rbMoveToPackage.addActionListener(
|
||||||
new ActionListener() {
|
e -> {
|
||||||
@Override
|
classPackageChooser.requestFocus();
|
||||||
public void actionPerformed(@NotNull ActionEvent e) {
|
updateControls();
|
||||||
classPackageChooser.requestFocus();
|
|
||||||
updateControls();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
rbMoveToFile.addActionListener(
|
rbMoveToFile.addActionListener(
|
||||||
new ActionListener() {
|
e -> {
|
||||||
@Override
|
fileChooser.requestFocus();
|
||||||
public void actionPerformed(@NotNull ActionEvent e) {
|
updateControls();
|
||||||
fileChooser.requestFocus();
|
|
||||||
updateControls();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -367,33 +306,30 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
@NotNull Set<KtNamedDeclaration> elementsToMove,
|
@NotNull Set<KtNamedDeclaration> elementsToMove,
|
||||||
@NotNull List<KtFile> sourceFiles
|
@NotNull List<KtFile> sourceFiles
|
||||||
) {
|
) {
|
||||||
final PsiDirectory sourceDir = sourceFiles.get(0).getParent();
|
PsiDirectory sourceDir = sourceFiles.get(0).getParent();
|
||||||
assert sourceDir != null : sourceFiles.get(0).getVirtualFile().getPath();
|
assert sourceDir != null : sourceFiles.get(0).getVirtualFile().getPath();
|
||||||
|
|
||||||
fileChooser.addActionListener(
|
fileChooser.addActionListener(
|
||||||
new ActionListener() {
|
e -> {
|
||||||
@Override
|
KotlinFileChooserDialog dialog = new KotlinFileChooserDialog("Choose Containing File", myProject);
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
KotlinFileChooserDialog dialog = new KotlinFileChooserDialog("Choose Containing File", myProject);
|
|
||||||
|
|
||||||
File targetFile = new File(getTargetFilePath());
|
File targetFile1 = new File(getTargetFilePath());
|
||||||
PsiFile targetPsiFile = PhysicalFileSystemUtilsKt.toPsiFile(targetFile, myProject);
|
PsiFile targetPsiFile = PhysicalFileSystemUtilsKt.toPsiFile(targetFile1, myProject);
|
||||||
if (targetPsiFile instanceof KtFile) {
|
if (targetPsiFile instanceof KtFile) {
|
||||||
dialog.select((KtFile) targetPsiFile);
|
dialog.select((KtFile) targetPsiFile);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PsiDirectory targetDir = PhysicalFileSystemUtilsKt.toPsiDirectory(targetFile.getParentFile(), myProject);
|
PsiDirectory targetDir = PhysicalFileSystemUtilsKt.toPsiDirectory(targetFile1.getParentFile(), myProject);
|
||||||
if (targetDir == null) {
|
if (targetDir == null) {
|
||||||
targetDir = sourceDir;
|
targetDir = sourceDir;
|
||||||
}
|
|
||||||
dialog.selectDirectory(targetDir);
|
|
||||||
}
|
}
|
||||||
|
dialog.selectDirectory(targetDir);
|
||||||
|
}
|
||||||
|
|
||||||
dialog.showDialog();
|
dialog.showDialog();
|
||||||
KtFile selectedFile = dialog.isOK() ? dialog.getSelected() : null;
|
KtFile selectedFile = dialog.isOK() ? dialog.getSelected() : null;
|
||||||
if (selectedFile != null) {
|
if (selectedFile != null) {
|
||||||
fileChooser.setText(selectedFile.getVirtualFile().getPath());
|
fileChooser.setText(selectedFile.getVirtualFile().getPath());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -446,12 +382,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
private boolean isFullFileMove() {
|
private boolean isFullFileMove() {
|
||||||
Map<KtFile, List<KtNamedDeclaration>> fileToElements = CollectionsKt.groupBy(
|
Map<KtFile, List<KtNamedDeclaration>> fileToElements = CollectionsKt.groupBy(
|
||||||
getSelectedElementsToMove(),
|
getSelectedElementsToMove(),
|
||||||
new Function1<KtNamedDeclaration, KtFile>() {
|
KtPureElement::getContainingKtFile
|
||||||
@Override
|
|
||||||
public KtFile invoke(KtNamedDeclaration declaration) {
|
|
||||||
return declaration.getContainingKtFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
for (Map.Entry<KtFile, List<KtNamedDeclaration>> entry : fileToElements.entrySet()) {
|
for (Map.Entry<KtFile, List<KtNamedDeclaration>> entry : fileToElements.entrySet()) {
|
||||||
if (KtPsiUtilKt.getFileOrScriptDeclarations(entry.getKey()).size() != entry.getValue().size()) return false;
|
if (KtPsiUtilKt.getFileOrScriptDeclarations(entry.getKey()).size() != entry.getValue().size()) return false;
|
||||||
@@ -486,7 +417,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
if (ret != Messages.YES) return null;
|
if (ret != Messages.YES) return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryChooser.ItemWrapper selectedItem = (DirectoryChooser.ItemWrapper)destinationFolderCB.getComboBox().getSelectedItem();
|
DirectoryChooser.ItemWrapper selectedItem = (DirectoryChooser.ItemWrapper) destinationFolderCB.getComboBox().getSelectedItem();
|
||||||
PsiDirectory selectedPsiDirectory = selectedItem != null ? selectedItem.getDirectory() : null;
|
PsiDirectory selectedPsiDirectory = selectedItem != null ? selectedItem.getDirectory() : null;
|
||||||
if (selectedPsiDirectory == null) {
|
if (selectedPsiDirectory == null) {
|
||||||
if (initialTargetDirectory != null) {
|
if (initialTargetDirectory != null) {
|
||||||
@@ -525,9 +456,9 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
if (targetDirWithMoveDestination == null) return null;
|
if (targetDirWithMoveDestination == null) return null;
|
||||||
|
|
||||||
VirtualFile targetDir = targetDirWithMoveDestination.getFirst();
|
VirtualFile targetDir = targetDirWithMoveDestination.getFirst();
|
||||||
final MoveDestination moveDestination = targetDirWithMoveDestination.getSecond();
|
MoveDestination moveDestination = targetDirWithMoveDestination.getSecond();
|
||||||
|
|
||||||
final String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||||
if (targetFileName != null && !checkTargetFileName(targetFileName)) return null;
|
if (targetFileName != null && !checkTargetFileName(targetFileName)) return null;
|
||||||
|
|
||||||
PsiDirectory targetDirectory = moveDestination.getTargetIfExists(sourceDirectory);
|
PsiDirectory targetDirectory = moveDestination.getTargetIfExists(sourceDirectory);
|
||||||
@@ -537,12 +468,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
if (filesExistingInTargetDir.size() > 1) {
|
if (filesExistingInTargetDir.size() > 1) {
|
||||||
String filePathsToReport = StringUtil.join(
|
String filePathsToReport = StringUtil.join(
|
||||||
filesExistingInTargetDir,
|
filesExistingInTargetDir,
|
||||||
new Function<PsiFile, String>() {
|
file -> file.getVirtualFile().getPath(),
|
||||||
@Override
|
|
||||||
public String fun(PsiFile file) {
|
|
||||||
return file.getVirtualFile().getPath();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"\n"
|
"\n"
|
||||||
);
|
);
|
||||||
Messages.showErrorDialog(
|
Messages.showErrorDialog(
|
||||||
@@ -560,7 +486,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
"File '%s' already exists. Do you want to move selected declarations to this file?",
|
"File '%s' already exists. Do you want to move selected declarations to this file?",
|
||||||
targetFile.getVirtualFile().getPath()
|
targetFile.getVirtualFile().getPath()
|
||||||
);
|
);
|
||||||
int ret=
|
int ret =
|
||||||
Messages.showYesNoDialog(myProject, question, RefactoringBundle.message("move.title"),
|
Messages.showYesNoDialog(myProject, question, RefactoringBundle.message("move.title"),
|
||||||
Messages.getQuestionIcon());
|
Messages.getQuestionIcon());
|
||||||
if (ret != Messages.YES) return null;
|
if (ret != Messages.YES) return null;
|
||||||
@@ -576,19 +502,14 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
new FqName(getTargetPackage()),
|
new FqName(getTargetPackage()),
|
||||||
moveDestination.getTargetIfExists(sourceFiles.get(0)),
|
moveDestination.getTargetIfExists(sourceFiles.get(0)),
|
||||||
targetDir,
|
targetDir,
|
||||||
new Function1<KtFile, KtFile>() {
|
originalFile -> KotlinRefactoringUtilKt.getOrCreateKotlinFile(
|
||||||
@Override
|
targetFileName != null ? targetFileName : originalFile.getName(),
|
||||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
moveDestination.getTargetDirectory(originalFile)
|
||||||
return KotlinRefactoringUtilKt.getOrCreateKotlinFile(
|
)
|
||||||
targetFileName != null ? targetFileName : originalFile.getName(),
|
|
||||||
moveDestination.getTargetDirectory(originalFile)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final File targetFile = new File(getTargetFilePath());
|
File targetFile = new File(getTargetFilePath());
|
||||||
if (!checkTargetFileName(targetFile.getName())) return null;
|
if (!checkTargetFileName(targetFile.getName())) return null;
|
||||||
KtFile jetFile = (KtFile) PhysicalFileSystemUtilsKt.toPsiFile(targetFile, myProject);
|
KtFile jetFile = (KtFile) PhysicalFileSystemUtilsKt.toPsiFile(targetFile, myProject);
|
||||||
if (jetFile != null) {
|
if (jetFile != null) {
|
||||||
@@ -602,7 +523,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
Path targetFilePath = targetFile.toPath();
|
Path targetFilePath = targetFile.toPath();
|
||||||
Path targetDirPath = targetFilePath.getParent();
|
Path targetDirPath = targetFilePath.getParent();
|
||||||
if (targetDirPath == null || !targetDirPath.startsWith(getProject().getBasePath())) {
|
if (targetDirPath == null || !targetDirPath.startsWith(Objects.requireNonNull(getProject().getBasePath()))) {
|
||||||
setErrorText("Incorrect target path. Directory " + targetDirPath + " does not belong to current project.");
|
setErrorText("Incorrect target path. Directory " + targetDirPath + " does not belong to current project.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -625,7 +546,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
File targetDir = targetDirPath.toFile();
|
File targetDir = targetDirPath.toFile();
|
||||||
final PsiDirectory psiDirectory = targetDir != null ? PhysicalFileSystemUtilsKt.toPsiDirectory(targetDir, myProject) : null;
|
PsiDirectory psiDirectory = targetDir != null ? PhysicalFileSystemUtilsKt.toPsiDirectory(targetDir, myProject) : null;
|
||||||
if (psiDirectory == null) {
|
if (psiDirectory == null) {
|
||||||
setErrorText("No directory found for file: " + targetFile.getPath());
|
setErrorText("No directory found for file: " + targetFile.getPath());
|
||||||
return null;
|
return null;
|
||||||
@@ -633,13 +554,8 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
Set<FqName> sourcePackageFqNames = CollectionsKt.mapTo(
|
Set<FqName> sourcePackageFqNames = CollectionsKt.mapTo(
|
||||||
sourceFiles,
|
sourceFiles,
|
||||||
new LinkedHashSet<FqName>(),
|
new LinkedHashSet<>(),
|
||||||
new Function1<KtFile, FqName>() {
|
KtFile::getPackageFqName
|
||||||
@Override
|
|
||||||
public FqName invoke(KtFile file) {
|
|
||||||
return file.getPackageFqName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
FqName targetPackageFqName = CollectionsKt.singleOrNull(sourcePackageFqNames);
|
FqName targetPackageFqName = CollectionsKt.singleOrNull(sourcePackageFqNames);
|
||||||
if (targetPackageFqName == null) {
|
if (targetPackageFqName == null) {
|
||||||
@@ -651,17 +567,12 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
targetPackageFqName = new FqName(psiPackage.getQualifiedName());
|
targetPackageFqName = new FqName(psiPackage.getQualifiedName());
|
||||||
}
|
}
|
||||||
|
|
||||||
final String finalTargetPackageFqName = targetPackageFqName.asString();
|
String finalTargetPackageFqName = targetPackageFqName.asString();
|
||||||
return new KotlinMoveTargetForDeferredFile(
|
return new KotlinMoveTargetForDeferredFile(
|
||||||
targetPackageFqName,
|
targetPackageFqName,
|
||||||
psiDirectory,
|
psiDirectory,
|
||||||
null,
|
null,
|
||||||
new Function1<KtFile, KtFile>() {
|
originalFile -> KotlinRefactoringUtilKt.getOrCreateKotlinFile(targetFile.getName(), psiDirectory, finalTargetPackageFqName)
|
||||||
@Override
|
|
||||||
public KtFile invoke(@NotNull KtFile originalFile) {
|
|
||||||
return KotlinRefactoringUtilKt.getOrCreateKotlinFile(targetFile.getName(), psiDirectory, finalTargetPackageFqName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,12 +603,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
private List<KtNamedDeclaration> getSelectedElementsToMove() {
|
private List<KtNamedDeclaration> getSelectedElementsToMove() {
|
||||||
return CollectionsKt.map(
|
return CollectionsKt.map(
|
||||||
memberTable.getSelectedMemberInfos(),
|
memberTable.getSelectedMemberInfos(),
|
||||||
new Function1<KotlinMemberInfo, KtNamedDeclaration>() {
|
MemberInfoBase::getMember
|
||||||
@Override
|
|
||||||
public KtNamedDeclaration invoke(KotlinMemberInfo info) {
|
|
||||||
return info.getMember();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +642,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
List<KtNamedDeclaration> elementsToMove = getSelectedElementsToMove();
|
List<KtNamedDeclaration> elementsToMove = getSelectedElementsToMove();
|
||||||
List<KtFile> sourceFiles = getSourceFiles(elementsToMove);
|
List<KtFile> sourceFiles = getSourceFiles(elementsToMove);
|
||||||
final PsiDirectory sourceDirectory = getSourceDirectory(sourceFiles);
|
PsiDirectory sourceDirectory = getSourceDirectory(sourceFiles);
|
||||||
|
|
||||||
for (PsiElement element : elementsToMove) {
|
for (PsiElement element : elementsToMove) {
|
||||||
String message = target.verify(element.getContainingFile());
|
String message = target.verify(element.getContainingFile());
|
||||||
@@ -754,7 +660,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
Pair<VirtualFile, ? extends MoveDestination> sourceRootWithMoveDestination =
|
Pair<VirtualFile, ? extends MoveDestination> sourceRootWithMoveDestination =
|
||||||
selectPackageBasedTargetDirAndDestination(false);
|
selectPackageBasedTargetDirAndDestination(false);
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
final MoveDestination moveDestination = sourceRootWithMoveDestination.getSecond();
|
MoveDestination moveDestination = sourceRootWithMoveDestination.getSecond();
|
||||||
|
|
||||||
PsiDirectory targetDir = moveDestination.getTargetIfExists(sourceDirectory);
|
PsiDirectory targetDir = moveDestination.getTargetIfExists(sourceDirectory);
|
||||||
String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
String targetFileName = sourceFiles.size() > 1 ? null : tfFileNameInPackage.getText();
|
||||||
@@ -762,12 +668,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
if (filesExistingInTargetDir.isEmpty()
|
if (filesExistingInTargetDir.isEmpty()
|
||||||
|| (filesExistingInTargetDir.size() == 1 && sourceFiles.contains(filesExistingInTargetDir.get(0)))) {
|
|| (filesExistingInTargetDir.size() == 1 && sourceFiles.contains(filesExistingInTargetDir.get(0)))) {
|
||||||
PsiDirectory targetDirectory = ApplicationUtilsKt.runWriteAction(
|
PsiDirectory targetDirectory = ApplicationUtilsKt.runWriteAction(
|
||||||
new Function0<PsiDirectory>() {
|
() -> moveDestination.getTargetDirectory(sourceDirectory)
|
||||||
@Override
|
|
||||||
public PsiDirectory invoke() {
|
|
||||||
return moveDestination.getTargetDirectory(sourceDirectory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
for (KtFile sourceFile : sourceFiles) {
|
for (KtFile sourceFile : sourceFiles) {
|
||||||
@@ -809,7 +710,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
|||||||
|
|
||||||
MoveDeclarationsDescriptor options = new MoveDeclarationsDescriptor(
|
MoveDeclarationsDescriptor options = new MoveDeclarationsDescriptor(
|
||||||
myProject,
|
myProject,
|
||||||
MoveSource(elementsToMove),
|
MoveKotlinDeclarationsProcessorKt.MoveSource(elementsToMove),
|
||||||
target,
|
target,
|
||||||
MoveDeclarationsDelegate.TopLevel.INSTANCE,
|
MoveDeclarationsDelegate.TopLevel.INSTANCE,
|
||||||
isSearchInComments(),
|
isSearchInComments(),
|
||||||
|
|||||||
+11
-18
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.moveFilesOrDirectories
|
package org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories
|
||||||
@@ -31,10 +20,14 @@ class FqNameFixingMoveJavaFileHandler : MoveFileHandler() {
|
|||||||
private val delegate = MoveJavaFileHandler()
|
private val delegate = MoveJavaFileHandler()
|
||||||
|
|
||||||
override fun canProcessElement(element: PsiFile) =
|
override fun canProcessElement(element: PsiFile) =
|
||||||
delegate.canProcessElement(element)
|
delegate.canProcessElement(element)
|
||||||
|
|
||||||
override fun findUsages(psiFile: PsiFile, newParent: PsiDirectory?, searchInComments: Boolean, searchInNonJavaFiles: Boolean) =
|
override fun findUsages(
|
||||||
delegate.findUsages(psiFile, newParent, searchInComments, searchInNonJavaFiles)
|
psiFile: PsiFile,
|
||||||
|
newParent: PsiDirectory?,
|
||||||
|
searchInComments: Boolean,
|
||||||
|
searchInNonJavaFiles: Boolean
|
||||||
|
): MutableList<UsageInfo>? = delegate.findUsages(psiFile, newParent, searchInComments, searchInNonJavaFiles)
|
||||||
|
|
||||||
override fun prepareMovedFile(file: PsiFile, moveDestination: PsiDirectory, oldToNewMap: MutableMap<PsiElement, PsiElement>) {
|
override fun prepareMovedFile(file: PsiFile, moveDestination: PsiDirectory, oldToNewMap: MutableMap<PsiElement, PsiElement>) {
|
||||||
delegate.prepareMovedFile(file, moveDestination, oldToNewMap)
|
delegate.prepareMovedFile(file, moveDestination, oldToNewMap)
|
||||||
@@ -47,8 +40,8 @@ class FqNameFixingMoveJavaFileHandler : MoveFileHandler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun updateMovedFile(file: PsiFile) =
|
override fun updateMovedFile(file: PsiFile) =
|
||||||
delegate.updateMovedFile(file)
|
delegate.updateMovedFile(file)
|
||||||
|
|
||||||
override fun retargetUsages(usageInfos: MutableList<UsageInfo>, oldToNewMap: MutableMap<PsiElement, PsiElement>) =
|
override fun retargetUsages(usageInfos: MutableList<UsageInfo>, oldToNewMap: MutableMap<PsiElement, PsiElement>) =
|
||||||
delegate.retargetUsages(usageInfos, oldToNewMap)
|
delegate.retargetUsages(usageInfos, oldToNewMap)
|
||||||
}
|
}
|
||||||
+28
-39
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.moveFilesOrDirectories
|
package org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories
|
||||||
@@ -40,14 +29,14 @@ import java.util.*
|
|||||||
|
|
||||||
class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
||||||
private data class FileUsagesWrapper(
|
private data class FileUsagesWrapper(
|
||||||
val psiFile: KtFile,
|
val psiFile: KtFile,
|
||||||
val usages: List<UsageInfo>,
|
val usages: List<UsageInfo>,
|
||||||
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
||||||
) : UsageInfo(psiFile)
|
) : UsageInfo(psiFile)
|
||||||
|
|
||||||
private class MoveContext(
|
private class MoveContext(
|
||||||
val newParent: PsiDirectory,
|
val newParent: PsiDirectory,
|
||||||
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
val moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor?
|
||||||
)
|
)
|
||||||
|
|
||||||
private val fileHandler = MoveKotlinFileHandler()
|
private val fileHandler = MoveKotlinFileHandler()
|
||||||
@@ -62,23 +51,24 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun findUsages(
|
override fun findUsages(
|
||||||
filesToMove: MutableCollection<PsiFile>,
|
filesToMove: MutableCollection<PsiFile>,
|
||||||
directoriesToMove: Array<out PsiDirectory>,
|
directoriesToMove: Array<out PsiDirectory>,
|
||||||
result: MutableCollection<UsageInfo>,
|
result: MutableCollection<UsageInfo>,
|
||||||
searchInComments: Boolean,
|
searchInComments: Boolean,
|
||||||
searchInNonJavaFiles: Boolean,
|
searchInNonJavaFiles: Boolean,
|
||||||
project: Project) {
|
project: Project
|
||||||
|
) {
|
||||||
filesToMove
|
filesToMove
|
||||||
.filterIsInstance<KtFile>()
|
.filterIsInstance<KtFile>()
|
||||||
.mapTo(result) { FileUsagesWrapper(it, fileHandler.findUsages(it, null, false), null) }
|
.mapTo(result) { FileUsagesWrapper(it, fileHandler.findUsages(it, null, false), null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun preprocessUsages(
|
override fun preprocessUsages(
|
||||||
project: Project,
|
project: Project,
|
||||||
files: MutableSet<PsiFile>,
|
files: MutableSet<PsiFile>,
|
||||||
infos: Array<UsageInfo>,
|
infos: Array<UsageInfo>,
|
||||||
directory: PsiDirectory?,
|
directory: PsiDirectory?,
|
||||||
conflicts: MultiMap<PsiElement, String>
|
conflicts: MultiMap<PsiElement, String>
|
||||||
) {
|
) {
|
||||||
val psiPackage = directory?.getPackage() ?: return
|
val psiPackage = directory?.getPackage() ?: return
|
||||||
val moveTarget = KotlinDirectoryMoveTarget(FqName(psiPackage.qualifiedName), directory)
|
val moveTarget = KotlinDirectoryMoveTarget(FqName(psiPackage.qualifiedName), directory)
|
||||||
@@ -101,11 +91,11 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
|||||||
|
|
||||||
// Actual move logic is implemented in postProcessUsages since usages are not available here
|
// Actual move logic is implemented in postProcessUsages since usages are not available here
|
||||||
override fun move(
|
override fun move(
|
||||||
file: PsiFile,
|
file: PsiFile,
|
||||||
moveDestination: PsiDirectory,
|
moveDestination: PsiDirectory,
|
||||||
oldToNewElementsMapping: MutableMap<PsiElement, PsiElement>,
|
oldToNewElementsMapping: MutableMap<PsiElement, PsiElement>,
|
||||||
movedFiles: MutableList<PsiFile>,
|
movedFiles: MutableList<PsiFile>,
|
||||||
listener: RefactoringElementListener?
|
listener: RefactoringElementListener?
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (file !is KtFile) return false
|
if (file !is KtFile) return false
|
||||||
|
|
||||||
@@ -130,7 +120,7 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
|||||||
val usagesToProcess = ArrayList<FileUsagesWrapper>()
|
val usagesToProcess = ArrayList<FileUsagesWrapper>()
|
||||||
usages
|
usages
|
||||||
.filterIsInstance<FileUsagesWrapper>()
|
.filterIsInstance<FileUsagesWrapper>()
|
||||||
.forEach body@ {
|
.forEach body@{
|
||||||
val file = it.psiFile
|
val file = it.psiFile
|
||||||
val moveContext = fileToMoveContext[file] ?: return@body
|
val moveContext = fileToMoveContext[file] ?: return@body
|
||||||
|
|
||||||
@@ -142,8 +132,7 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
|
|||||||
usagesToProcess += FileUsagesWrapper(movedFile as KtFile, it.usages, moveDeclarationsProcessor)
|
usagesToProcess += FileUsagesWrapper(movedFile as KtFile, it.usages, moveDeclarationsProcessor)
|
||||||
}
|
}
|
||||||
usagesToProcess.forEach { fileHandler.retargetUsages(it.usages, it.moveDeclarationsProcessor!!) }
|
usagesToProcess.forEach { fileHandler.retargetUsages(it.usages, it.moveDeclarationsProcessor!!) }
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
this.fileToMoveContext = null
|
this.fileToMoveContext = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-18
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.moveFilesOrDirectories
|
package org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories
|
||||||
@@ -55,14 +44,20 @@ class KotlinMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandler() {
|
|||||||
if (!(targetContainer == null || targetContainer is PsiDirectory || targetContainer is PsiDirectoryContainer)) return
|
if (!(targetContainer == null || targetContainer is PsiDirectory || targetContainer is PsiDirectoryContainer)) return
|
||||||
|
|
||||||
moveFilesOrDirectories(
|
moveFilesOrDirectories(
|
||||||
project,
|
project,
|
||||||
adjustForMove(project, elements, targetContainer) ?: return,
|
adjustForMove(project, elements, targetContainer) ?: return,
|
||||||
targetContainer,
|
targetContainer,
|
||||||
callback?.let { MoveCallback { it.refactoringCompleted() } }
|
callback?.let { MoveCallback { it.refactoringCompleted() } }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tryToMove(element: PsiElement, project: Project, dataContext: DataContext?, reference: PsiReference?, editor: Editor?): Boolean {
|
override fun tryToMove(
|
||||||
|
element: PsiElement,
|
||||||
|
project: Project,
|
||||||
|
dataContext: DataContext?,
|
||||||
|
reference: PsiReference?,
|
||||||
|
editor: Editor?
|
||||||
|
): Boolean {
|
||||||
if (element is KtLightClassForFacade) {
|
if (element is KtLightClassForFacade) {
|
||||||
doMove(project, element.files.toTypedArray(), dataContext?.getData(LangDataKeys.TARGET_PSI_ELEMENT), null)
|
doMove(project, element.files.toTypedArray(), dataContext?.getData(LangDataKeys.TARGET_PSI_ELEMENT), null)
|
||||||
return true
|
return true
|
||||||
|
|||||||
+20
-29
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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.moveFilesOrDirectories
|
package org.jetbrains.kotlin.idea.refactoring.move.moveFilesOrDirectories
|
||||||
@@ -48,9 +37,9 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
|||||||
// This is special 'PsiElement' whose purpose is to wrap MoveKotlinTopLevelDeclarationsProcessor
|
// This is special 'PsiElement' whose purpose is to wrap MoveKotlinTopLevelDeclarationsProcessor
|
||||||
// so that it can be kept in the usage info list
|
// so that it can be kept in the usage info list
|
||||||
private class MoveContext(
|
private class MoveContext(
|
||||||
val file: PsiFile,
|
val file: PsiFile,
|
||||||
val declarationMoveProcessor: MoveKotlinDeclarationsProcessor
|
val declarationMoveProcessor: MoveKotlinDeclarationsProcessor
|
||||||
): LightElement(file.manager, KotlinLanguage.INSTANCE) {
|
) : LightElement(file.manager, KotlinLanguage.INSTANCE) {
|
||||||
override fun toString() = ""
|
override fun toString() = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,12 +50,15 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
|||||||
if (!shouldUpdatePackageDirective) return null
|
if (!shouldUpdatePackageDirective) return null
|
||||||
|
|
||||||
val oldPackageName = packageFqName
|
val oldPackageName = packageFqName
|
||||||
val newPackage = newParent?.getPackage() ?: return ContainerChangeInfo(ContainerInfo.Package(oldPackageName),
|
val newPackage = newParent?.getPackage() ?: return ContainerChangeInfo(
|
||||||
ContainerInfo.UnknownPackage)
|
ContainerInfo.Package(oldPackageName),
|
||||||
|
ContainerInfo.UnknownPackage
|
||||||
|
)
|
||||||
|
|
||||||
val newPackageName = FqNameUnsafe(newPackage.qualifiedName)
|
val newPackageName = FqNameUnsafe(newPackage.qualifiedName)
|
||||||
if (oldPackageName.asString() == newPackageName.asString()
|
if (oldPackageName.asString() == newPackageName.asString()
|
||||||
&& ModuleUtilCore.findModuleForPsiElement(this) == ModuleUtilCore.findModuleForPsiElement(newParent)) return null
|
&& ModuleUtilCore.findModuleForPsiElement(this) == ModuleUtilCore.findModuleForPsiElement(newParent)
|
||||||
|
) return null
|
||||||
if (!newPackageName.hasIdentifiersOnly()) return null
|
if (!newPackageName.hasIdentifiersOnly()) return null
|
||||||
|
|
||||||
return ContainerChangeInfo(ContainerInfo.Package(oldPackageName), ContainerInfo.Package(newPackageName.toSafe()))
|
return ContainerChangeInfo(ContainerInfo.Package(oldPackageName), ContainerInfo.Package(newPackageName.toSafe()))
|
||||||
@@ -78,8 +70,7 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
|||||||
|
|
||||||
val project = psiFile.project
|
val project = psiFile.project
|
||||||
|
|
||||||
val newPackage = packageNameInfo.newContainer
|
val moveTarget = when (val newPackage = packageNameInfo.newContainer) {
|
||||||
val moveTarget = when (newPackage) {
|
|
||||||
ContainerInfo.UnknownPackage -> EmptyKotlinMoveTarget
|
ContainerInfo.UnknownPackage -> EmptyKotlinMoveTarget
|
||||||
|
|
||||||
else -> KotlinMoveTargetForDeferredFile(newPackage.fqName!!, newParent) {
|
else -> KotlinMoveTargetForDeferredFile(newPackage.fqName!!, newParent) {
|
||||||
@@ -108,18 +99,18 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun findUsages(
|
override fun findUsages(
|
||||||
psiFile: PsiFile,
|
psiFile: PsiFile,
|
||||||
newParent: PsiDirectory?,
|
newParent: PsiDirectory?,
|
||||||
searchInComments: Boolean,
|
searchInComments: Boolean,
|
||||||
searchInNonJavaFiles: Boolean
|
searchInNonJavaFiles: Boolean
|
||||||
): List<UsageInfo> {
|
): List<UsageInfo> {
|
||||||
return findUsages(psiFile, newParent, true)
|
return findUsages(psiFile, newParent, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findUsages(
|
fun findUsages(
|
||||||
psiFile: PsiFile,
|
psiFile: PsiFile,
|
||||||
newParent: PsiDirectory?,
|
newParent: PsiDirectory?,
|
||||||
withConflicts: Boolean
|
withConflicts: Boolean
|
||||||
): List<UsageInfo> {
|
): List<UsageInfo> {
|
||||||
if (psiFile !is KtFile) return emptyList()
|
if (psiFile !is KtFile) return emptyList()
|
||||||
|
|
||||||
@@ -149,7 +140,7 @@ class MoveKotlinFileHandler : MoveFileHandler() {
|
|||||||
|
|
||||||
override fun retargetUsages(usageInfos: List<UsageInfo>?, oldToNewMap: Map<PsiElement, PsiElement>) {
|
override fun retargetUsages(usageInfos: List<UsageInfo>?, oldToNewMap: Map<PsiElement, PsiElement>) {
|
||||||
val currentFile = (usageInfos?.firstOrNull() as? FileInfo)?.element
|
val currentFile = (usageInfos?.firstOrNull() as? FileInfo)?.element
|
||||||
val moveContext = oldToNewMap.keys.firstOrNull { it is MoveContext && it.file == currentFile} as? MoveContext ?: return
|
val moveContext = oldToNewMap.keys.firstOrNull { it is MoveContext && it.file == currentFile } as? MoveContext ?: return
|
||||||
retargetUsages(usageInfos, moveContext.declarationMoveProcessor)
|
retargetUsages(usageInfos, moveContext.declarationMoveProcessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
*
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
* 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
|
package org.jetbrains.kotlin.idea.refactoring.move
|
||||||
@@ -64,11 +53,11 @@ sealed class ContainerInfo {
|
|||||||
abstract fun matches(descriptor: DeclarationDescriptor): Boolean
|
abstract fun matches(descriptor: DeclarationDescriptor): Boolean
|
||||||
|
|
||||||
object UnknownPackage : ContainerInfo() {
|
object UnknownPackage : ContainerInfo() {
|
||||||
override val fqName = null
|
override val fqName: FqName? = null
|
||||||
override fun matches(descriptor: DeclarationDescriptor) = descriptor is PackageViewDescriptor
|
override fun matches(descriptor: DeclarationDescriptor) = descriptor is PackageViewDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
class Package(override val fqName: FqName): ContainerInfo() {
|
class Package(override val fqName: FqName) : ContainerInfo() {
|
||||||
override fun matches(descriptor: DeclarationDescriptor): Boolean {
|
override fun matches(descriptor: DeclarationDescriptor): Boolean {
|
||||||
return descriptor is PackageFragmentDescriptor && descriptor.fqName == fqName
|
return descriptor is PackageFragmentDescriptor && descriptor.fqName == fqName
|
||||||
}
|
}
|
||||||
@@ -100,8 +89,8 @@ fun KtElement.getInternalReferencesToUpdateOnPackageNameChange(containerChangeIn
|
|||||||
private typealias UsageInfoFactory = (KtSimpleNameExpression) -> UsageInfo?
|
private typealias UsageInfoFactory = (KtSimpleNameExpression) -> UsageInfo?
|
||||||
|
|
||||||
fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
|
fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
|
||||||
containerChangeInfo: ContainerChangeInfo,
|
containerChangeInfo: ContainerChangeInfo,
|
||||||
body: (originalRefExpr: KtSimpleNameExpression, usageFactory: UsageInfoFactory) -> Unit
|
body: (originalRefExpr: KtSimpleNameExpression, usageFactory: UsageInfoFactory) -> Unit
|
||||||
) {
|
) {
|
||||||
val file = containingFile as? KtFile ?: return
|
val file = containingFile as? KtFile ?: return
|
||||||
|
|
||||||
@@ -111,8 +100,7 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
val fqName = DescriptorUtils.getFqName(descriptor).let { if (it.isSafe) it.toSafe() else return@isImported false }
|
val fqName = DescriptorUtils.getFqName(descriptor).let { if (it.isSafe) it.toSafe() else return@isImported false }
|
||||||
if (importPaths.any { fqName.isImported(it, false) }) return true
|
if (importPaths.any { fqName.isImported(it, false) }) return true
|
||||||
|
|
||||||
val containingDescriptor = descriptor.containingDeclaration
|
return when (val containingDescriptor = descriptor.containingDeclaration) {
|
||||||
return when (containingDescriptor) {
|
|
||||||
is ClassDescriptor, is PackageViewDescriptor -> isImported(containingDescriptor)
|
is ClassDescriptor, is PackageViewDescriptor -> isImported(containingDescriptor)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
@@ -138,7 +126,8 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
var result = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return@lazy null
|
var result = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return@lazy null
|
||||||
|
|
||||||
if (descriptor.isCompanionObject()
|
if (descriptor.isCompanionObject()
|
||||||
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null) {
|
&& bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, refExpr] != null
|
||||||
|
) {
|
||||||
result = (result as KtObjectDeclaration).containingClassOrObject ?: result
|
result = (result as KtObjectDeclaration).containingClassOrObject ?: result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +139,8 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
if (isExtension && containingDescriptor is ClassDescriptor) {
|
if (isExtension && containingDescriptor is ClassDescriptor) {
|
||||||
val dispatchReceiver = refExpr.getResolvedCall(bindingContext)?.dispatchReceiver
|
val dispatchReceiver = refExpr.getResolvedCall(bindingContext)?.dispatchReceiver
|
||||||
val implicitClass = (dispatchReceiver as? ImplicitClassReceiver)?.classDescriptor
|
val implicitClass = (dispatchReceiver as? ImplicitClassReceiver)?.classDescriptor
|
||||||
if (implicitClass?.isCompanionObject ?: false) {
|
if (implicitClass?.isCompanionObject == true) {
|
||||||
return { ImplicitCompanionAsDispatchReceiverUsageInfo(it, implicitClass!!) }
|
return { ImplicitCompanionAsDispatchReceiverUsageInfo(it, implicitClass) }
|
||||||
}
|
}
|
||||||
if (dispatchReceiver != null || containingDescriptor.kind != ClassKind.OBJECT) return null
|
if (dispatchReceiver != null || containingDescriptor.kind != ClassKind.OBJECT) return null
|
||||||
}
|
}
|
||||||
@@ -159,8 +148,9 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
|
|
||||||
if (!isExtension) {
|
if (!isExtension) {
|
||||||
if (!(containingDescriptor is PackageFragmentDescriptor
|
if (!(containingDescriptor is PackageFragmentDescriptor
|
||||||
|| containingDescriptor is ClassDescriptor && containingDescriptor.kind == ClassKind.OBJECT
|
|| containingDescriptor is ClassDescriptor && containingDescriptor.kind == ClassKind.OBJECT
|
||||||
|| descriptor is JavaCallableMemberDescriptor && ((declaration as? PsiMember)?.hasModifierProperty(PsiModifier.STATIC) ?: false))) return null
|
|| descriptor is JavaCallableMemberDescriptor && ((declaration as? PsiMember)?.hasModifierProperty(PsiModifier.STATIC) == true))
|
||||||
|
) return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,15 +159,15 @@ fun KtElement.processInternalReferencesToUpdateOnPackageNameChange(
|
|||||||
val (oldContainer, newContainer) = containerChangeInfo
|
val (oldContainer, newContainer) = containerChangeInfo
|
||||||
|
|
||||||
val containerFqName = descriptor
|
val containerFqName = descriptor
|
||||||
.parents
|
.parents
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
when {
|
when {
|
||||||
oldContainer.matches(it) -> oldContainer.fqName
|
oldContainer.matches(it) -> oldContainer.fqName
|
||||||
newContainer.matches(it) -> newContainer.fqName
|
newContainer.matches(it) -> newContainer.fqName
|
||||||
else -> null
|
else -> null
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.firstOrNull()
|
}
|
||||||
|
.firstOrNull()
|
||||||
|
|
||||||
val isImported = isImported(descriptor)
|
val isImported = isImported(descriptor)
|
||||||
if (isImported && this is KtFile) return null
|
if (isImported && this is KtFile) return null
|
||||||
@@ -207,9 +197,9 @@ internal fun markInternalUsages(usages: Collection<UsageInfo>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun restoreInternalUsages(
|
internal fun restoreInternalUsages(
|
||||||
scope: KtElement,
|
scope: KtElement,
|
||||||
oldToNewElementsMapping: Map<PsiElement, PsiElement>,
|
oldToNewElementsMapping: Map<PsiElement, PsiElement>,
|
||||||
forcedRestore: Boolean = false
|
forcedRestore: Boolean = false
|
||||||
): List<UsageInfo> {
|
): List<UsageInfo> {
|
||||||
return scope.collectDescendantsOfType<KtSimpleNameExpression>().mapNotNull {
|
return scope.collectDescendantsOfType<KtSimpleNameExpression>().mapNotNull {
|
||||||
val usageInfo = it.internalUsageInfo
|
val usageInfo = it.internalUsageInfo
|
||||||
@@ -226,8 +216,8 @@ internal fun cleanUpInternalUsages(usages: Collection<UsageInfo>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ImplicitCompanionAsDispatchReceiverUsageInfo(
|
class ImplicitCompanionAsDispatchReceiverUsageInfo(
|
||||||
callee: KtSimpleNameExpression,
|
callee: KtSimpleNameExpression,
|
||||||
val companionDescriptor: ClassDescriptor
|
val companionDescriptor: ClassDescriptor
|
||||||
) : UsageInfo(callee)
|
) : UsageInfo(callee)
|
||||||
|
|
||||||
interface KotlinMoveUsage {
|
interface KotlinMoveUsage {
|
||||||
@@ -237,25 +227,46 @@ interface KotlinMoveUsage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UnqualifiableMoveRenameUsageInfo(
|
class UnqualifiableMoveRenameUsageInfo(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
reference: PsiReference,
|
reference: PsiReference,
|
||||||
referencedElement: PsiElement,
|
referencedElement: PsiElement,
|
||||||
val originalFile: PsiFile,
|
val originalFile: PsiFile,
|
||||||
val addImportToOriginalFile: Boolean,
|
val addImportToOriginalFile: Boolean,
|
||||||
override val isInternal: Boolean
|
override val isInternal: Boolean
|
||||||
): MoveRenameUsageInfo(element, reference, reference.rangeInElement.startOffset, reference.rangeInElement.endOffset, referencedElement, false), KotlinMoveUsage {
|
) : MoveRenameUsageInfo(
|
||||||
|
element,
|
||||||
|
reference,
|
||||||
|
reference.rangeInElement.startOffset,
|
||||||
|
reference.rangeInElement.endOffset,
|
||||||
|
referencedElement,
|
||||||
|
false
|
||||||
|
), KotlinMoveUsage {
|
||||||
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
||||||
return UnqualifiableMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, originalFile, addImportToOriginalFile, isInternal)
|
return UnqualifiableMoveRenameUsageInfo(
|
||||||
|
refExpr,
|
||||||
|
refExpr.mainReference,
|
||||||
|
referencedElement,
|
||||||
|
originalFile,
|
||||||
|
addImportToOriginalFile,
|
||||||
|
isInternal
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class QualifiableMoveRenameUsageInfo(
|
class QualifiableMoveRenameUsageInfo(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
reference: PsiReference,
|
reference: PsiReference,
|
||||||
referencedElement: PsiElement,
|
referencedElement: PsiElement,
|
||||||
override val isInternal: Boolean
|
override val isInternal: Boolean
|
||||||
): MoveRenameUsageInfo(element, reference, reference.rangeInElement.startOffset, reference.rangeInElement.endOffset, referencedElement, false),
|
) : MoveRenameUsageInfo(
|
||||||
KotlinMoveUsage {
|
element,
|
||||||
|
reference,
|
||||||
|
reference.rangeInElement.startOffset,
|
||||||
|
reference.rangeInElement.endOffset,
|
||||||
|
referencedElement,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
KotlinMoveUsage {
|
||||||
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
||||||
return QualifiableMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, isInternal)
|
return QualifiableMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, isInternal)
|
||||||
}
|
}
|
||||||
@@ -272,9 +283,23 @@ class CallableReferenceMoveRenameUsageInfo(
|
|||||||
val originalFile: PsiFile,
|
val originalFile: PsiFile,
|
||||||
val addImportToOriginalFile: Boolean,
|
val addImportToOriginalFile: Boolean,
|
||||||
override val isInternal: Boolean
|
override val isInternal: Boolean
|
||||||
) : MoveRenameUsageInfo(element, reference, reference.rangeInElement.startOffset, reference.rangeInElement.endOffset, referencedElement, false), DeferredKotlinMoveUsage {
|
) : MoveRenameUsageInfo(
|
||||||
|
element,
|
||||||
|
reference,
|
||||||
|
reference.rangeInElement.startOffset,
|
||||||
|
reference.rangeInElement.endOffset,
|
||||||
|
referencedElement,
|
||||||
|
false
|
||||||
|
), DeferredKotlinMoveUsage {
|
||||||
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
override fun refresh(refExpr: KtSimpleNameExpression, referencedElement: PsiElement): UsageInfo? {
|
||||||
return CallableReferenceMoveRenameUsageInfo(refExpr, refExpr.mainReference, referencedElement, originalFile, addImportToOriginalFile, isInternal)
|
return CallableReferenceMoveRenameUsageInfo(
|
||||||
|
refExpr,
|
||||||
|
refExpr.mainReference,
|
||||||
|
referencedElement,
|
||||||
|
originalFile,
|
||||||
|
addImportToOriginalFile,
|
||||||
|
isInternal
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resolve(newElement: PsiElement): UsageInfo? {
|
override fun resolve(newElement: PsiElement): UsageInfo? {
|
||||||
@@ -284,28 +309,35 @@ class CallableReferenceMoveRenameUsageInfo(
|
|||||||
val referencedElement = referencedElement ?: return null
|
val referencedElement = referencedElement ?: return null
|
||||||
if (target != null && target.isTopLevelKtOrJavaMember()) {
|
if (target != null && target.isTopLevelKtOrJavaMember()) {
|
||||||
element.getStrictParentOfType<KtCallableReferenceExpression>()?.receiverExpression?.delete()
|
element.getStrictParentOfType<KtCallableReferenceExpression>()?.receiverExpression?.delete()
|
||||||
return UnqualifiableMoveRenameUsageInfo(element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal)
|
return UnqualifiableMoveRenameUsageInfo(
|
||||||
|
element,
|
||||||
|
reference,
|
||||||
|
referencedElement,
|
||||||
|
element.containingFile!!,
|
||||||
|
addImportToOriginalFile,
|
||||||
|
isInternal
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return QualifiableMoveRenameUsageInfo(element, reference, referencedElement, isInternal)
|
return QualifiableMoveRenameUsageInfo(element, reference, referencedElement, isInternal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createMoveUsageInfoIfPossible(
|
fun createMoveUsageInfoIfPossible(
|
||||||
reference: PsiReference,
|
reference: PsiReference,
|
||||||
referencedElement: PsiElement,
|
referencedElement: PsiElement,
|
||||||
addImportToOriginalFile: Boolean,
|
addImportToOriginalFile: Boolean,
|
||||||
isInternal: Boolean
|
isInternal: Boolean
|
||||||
): UsageInfo? {
|
): UsageInfo? {
|
||||||
val element = reference.element
|
val element = reference.element
|
||||||
return when (getReferenceKind(reference, referencedElement)) {
|
return when (getReferenceKind(reference, referencedElement)) {
|
||||||
ReferenceKind.QUALIFIABLE -> QualifiableMoveRenameUsageInfo(
|
ReferenceKind.QUALIFIABLE -> QualifiableMoveRenameUsageInfo(
|
||||||
element, reference, referencedElement, isInternal
|
element, reference, referencedElement, isInternal
|
||||||
)
|
)
|
||||||
ReferenceKind.UNQUALIFIABLE -> UnqualifiableMoveRenameUsageInfo(
|
ReferenceKind.UNQUALIFIABLE -> UnqualifiableMoveRenameUsageInfo(
|
||||||
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal
|
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal
|
||||||
)
|
)
|
||||||
ReferenceKind.CALLABLE_REFERENCE -> CallableReferenceMoveRenameUsageInfo(
|
ReferenceKind.CALLABLE_REFERENCE -> CallableReferenceMoveRenameUsageInfo(
|
||||||
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal
|
element, reference, referencedElement, element.containingFile!!, addImportToOriginalFile, isInternal
|
||||||
)
|
)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@@ -349,14 +381,14 @@ private fun getReferenceKind(reference: PsiReference, referencedElement: PsiElem
|
|||||||
|
|
||||||
private fun isCallableReference(reference: PsiReference): Boolean {
|
private fun isCallableReference(reference: PsiReference): Boolean {
|
||||||
return reference is KtSimpleNameReference
|
return reference is KtSimpleNameReference
|
||||||
&& reference.element.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } != null
|
&& reference.element.getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun guessNewFileName(declarationsToMove: Collection<KtNamedDeclaration>): String? {
|
fun guessNewFileName(declarationsToMove: Collection<KtNamedDeclaration>): String? {
|
||||||
if (declarationsToMove.isEmpty()) return null
|
if (declarationsToMove.isEmpty()) return null
|
||||||
|
|
||||||
val representative = declarationsToMove.singleOrNull()
|
val representative = declarationsToMove.singleOrNull()
|
||||||
?: declarationsToMove.filterIsInstance<KtClassOrObject>().singleOrNull()
|
?: declarationsToMove.filterIsInstance<KtClassOrObject>().singleOrNull()
|
||||||
representative?.let { return "${it.name}.${KotlinFileType.EXTENSION}" }
|
representative?.let { return "${it.name}.${KotlinFileType.EXTENSION}" }
|
||||||
|
|
||||||
return declarationsToMove.first().containingFile.name
|
return declarationsToMove.first().containingFile.name
|
||||||
@@ -384,7 +416,8 @@ private fun updateJavaReference(reference: PsiReferenceExpression, oldElement: P
|
|||||||
if (newClass != null && reference.qualifierExpression != null) {
|
if (newClass != null && reference.qualifierExpression != null) {
|
||||||
val mockMoveMembersOptions = MockMoveMembersOptions(newClass.qualifiedName, arrayOf(newElement))
|
val mockMoveMembersOptions = MockMoveMembersOptions(newClass.qualifiedName, arrayOf(newElement))
|
||||||
val moveMembersUsageInfo = MoveMembersProcessor.MoveMembersUsageInfo(
|
val moveMembersUsageInfo = MoveMembersProcessor.MoveMembersUsageInfo(
|
||||||
newElement, reference.element, newClass, reference.qualifierExpression, reference)
|
newElement, reference.element, newClass, reference.qualifierExpression, reference
|
||||||
|
)
|
||||||
val moveMemberHandler = MoveMemberHandler.EP_NAME.forLanguage(reference.element.language)
|
val moveMemberHandler = MoveMemberHandler.EP_NAME.forLanguage(reference.element.language)
|
||||||
if (moveMemberHandler != null) {
|
if (moveMemberHandler != null) {
|
||||||
moveMemberHandler.changeExternalUsage(mockMoveMembersOptions, moveMembersUsageInfo)
|
moveMemberHandler.changeExternalUsage(mockMoveMembersOptions, moveMembersUsageInfo)
|
||||||
@@ -398,10 +431,10 @@ private fun updateJavaReference(reference: PsiReferenceExpression, oldElement: P
|
|||||||
internal fun mapToNewOrThis(e: PsiElement, oldToNewElementsMapping: Map<PsiElement, PsiElement>) = oldToNewElementsMapping[e] ?: e
|
internal fun mapToNewOrThis(e: PsiElement, oldToNewElementsMapping: Map<PsiElement, PsiElement>) = oldToNewElementsMapping[e] ?: e
|
||||||
|
|
||||||
private fun postProcessMoveUsage(
|
private fun postProcessMoveUsage(
|
||||||
usage: UsageInfo,
|
usage: UsageInfo,
|
||||||
oldToNewElementsMapping: Map<PsiElement, PsiElement>,
|
oldToNewElementsMapping: Map<PsiElement, PsiElement>,
|
||||||
nonCodeUsages: ArrayList<NonCodeUsageInfo>,
|
nonCodeUsages: ArrayList<NonCodeUsageInfo>,
|
||||||
shorteningMode: ShorteningMode
|
shorteningMode: ShorteningMode
|
||||||
) {
|
) {
|
||||||
if (usage is NonCodeUsageInfo) {
|
if (usage is NonCodeUsageInfo) {
|
||||||
nonCodeUsages.add(usage)
|
nonCodeUsages.add(usage)
|
||||||
@@ -415,12 +448,17 @@ private fun postProcessMoveUsage(
|
|||||||
|
|
||||||
when (usage) {
|
when (usage) {
|
||||||
is DeferredKotlinMoveUsage -> {
|
is DeferredKotlinMoveUsage -> {
|
||||||
val newUsage = usage.resolve(newElement) ?: return
|
val newUsage = usage.resolve(newElement) ?: return
|
||||||
postProcessMoveUsage(newUsage, oldToNewElementsMapping, nonCodeUsages, shorteningMode)
|
postProcessMoveUsage(newUsage, oldToNewElementsMapping, nonCodeUsages, shorteningMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
is UnqualifiableMoveRenameUsageInfo -> {
|
is UnqualifiableMoveRenameUsageInfo -> {
|
||||||
val file = with(usage) { if (addImportToOriginalFile) originalFile else mapToNewOrThis(originalFile, oldToNewElementsMapping) } as KtFile
|
val file = with(usage) {
|
||||||
|
if (addImportToOriginalFile) originalFile else mapToNewOrThis(
|
||||||
|
originalFile,
|
||||||
|
oldToNewElementsMapping
|
||||||
|
)
|
||||||
|
} as KtFile
|
||||||
addDelayedImportRequest(newElement, file)
|
addDelayedImportRequest(newElement, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,8 +476,7 @@ private fun processReference(reference: PsiReference?, newElement: PsiElement, s
|
|||||||
reference is PsiReferenceExpression && updateJavaReference(reference, oldElement, newElement) -> return
|
reference is PsiReferenceExpression && updateJavaReference(reference, oldElement, newElement) -> return
|
||||||
else -> reference?.bindToElement(newElement)
|
else -> reference?.bindToElement(newElement)
|
||||||
}
|
}
|
||||||
}
|
} catch (e: IncorrectOperationException) {
|
||||||
catch (e: IncorrectOperationException) {
|
|
||||||
// Suppress exception if bindToElement is not implemented
|
// Suppress exception if bindToElement is not implemented
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,31 +485,31 @@ private fun processReference(reference: PsiReference?, newElement: PsiElement, s
|
|||||||
* Perform usage postprocessing and return non-code usages
|
* Perform usage postprocessing and return non-code usages
|
||||||
*/
|
*/
|
||||||
fun postProcessMoveUsages(
|
fun postProcessMoveUsages(
|
||||||
usages: Collection<UsageInfo>,
|
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> {
|
||||||
val sortedUsages = usages.sortedWith(
|
val sortedUsages = usages.sortedWith(
|
||||||
Comparator<UsageInfo> { o1, o2 ->
|
Comparator { o1, o2 ->
|
||||||
val file1 = o1.virtualFile
|
val file1 = o1.virtualFile
|
||||||
val file2 = o2.virtualFile
|
val file2 = o2.virtualFile
|
||||||
if (Comparing.equal(file1, file2)) {
|
if (Comparing.equal(file1, file2)) {
|
||||||
val rangeInElement1 = o1.rangeInElement
|
val rangeInElement1 = o1.rangeInElement
|
||||||
val rangeInElement2 = o2.rangeInElement
|
val rangeInElement2 = o2.rangeInElement
|
||||||
if (rangeInElement1 != null && rangeInElement2 != null) {
|
if (rangeInElement1 != null && rangeInElement2 != null) {
|
||||||
return@Comparator rangeInElement2.startOffset - rangeInElement1.startOffset
|
return@Comparator rangeInElement2.startOffset - rangeInElement1.startOffset
|
||||||
}
|
|
||||||
return@Comparator 0
|
|
||||||
}
|
}
|
||||||
if (file1 == null) return@Comparator -1
|
return@Comparator 0
|
||||||
if (file2 == null) return@Comparator 1
|
|
||||||
Comparing.compare(file1.path, file2.path)
|
|
||||||
}
|
}
|
||||||
|
if (file1 == null) return@Comparator -1
|
||||||
|
if (file2 == null) return@Comparator 1
|
||||||
|
Comparing.compare(file1.path, file2.path)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val nonCodeUsages = ArrayList<NonCodeUsageInfo>()
|
val nonCodeUsages = ArrayList<NonCodeUsageInfo>()
|
||||||
|
|
||||||
val progressStep = 1.0/sortedUsages.size
|
val progressStep = 1.0 / sortedUsages.size
|
||||||
val progressIndicator = ProgressManager.getInstance().progressIndicator
|
val progressIndicator = ProgressManager.getInstance().progressIndicator
|
||||||
progressIndicator?.text = "Updating usages..."
|
progressIndicator?.text = "Updating usages..."
|
||||||
usageLoop@ for ((i, usage) in sortedUsages.withIndex()) {
|
usageLoop@ for ((i, usage) in sortedUsages.withIndex()) {
|
||||||
@@ -499,17 +536,17 @@ sealed class OuterInstanceReferenceUsageInfo(element: PsiElement, private val is
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ExplicitThis(
|
class ExplicitThis(
|
||||||
expression: KtThisExpression,
|
expression: KtThisExpression,
|
||||||
isIndirectOuter: Boolean
|
isIndirectOuter: Boolean
|
||||||
) : OuterInstanceReferenceUsageInfo(expression, isIndirectOuter) {
|
) : OuterInstanceReferenceUsageInfo(expression, isIndirectOuter) {
|
||||||
val expression: KtThisExpression?
|
val expression: KtThisExpression?
|
||||||
get() = element as? KtThisExpression
|
get() = element as? KtThisExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImplicitReceiver(
|
class ImplicitReceiver(
|
||||||
callElement: KtElement,
|
callElement: KtElement,
|
||||||
isIndirectOuter: Boolean,
|
isIndirectOuter: Boolean,
|
||||||
private val isDoubleReceiver: Boolean
|
private val isDoubleReceiver: Boolean
|
||||||
) : OuterInstanceReferenceUsageInfo(callElement, isIndirectOuter) {
|
) : OuterInstanceReferenceUsageInfo(callElement, isIndirectOuter) {
|
||||||
val callElement: KtElement?
|
val callElement: KtElement?
|
||||||
get() = element as? KtElement
|
get() = element as? KtElement
|
||||||
@@ -535,7 +572,11 @@ sealed class OuterInstanceReferenceUsageInfo(element: PsiElement, private val is
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun traverseOuterInstanceReferences(member: KtNamedDeclaration, stopAtFirst: Boolean, body: (OuterInstanceReferenceUsageInfo) -> Unit = {}): Boolean {
|
fun traverseOuterInstanceReferences(
|
||||||
|
member: KtNamedDeclaration,
|
||||||
|
stopAtFirst: Boolean,
|
||||||
|
body: (OuterInstanceReferenceUsageInfo) -> Unit = {}
|
||||||
|
): Boolean {
|
||||||
if (member is KtObjectDeclaration || member is KtClass && !member.isInner()) return false
|
if (member is KtObjectDeclaration || member is KtClass && !member.isInner()) return false
|
||||||
|
|
||||||
val context = member.analyzeWithContent()
|
val context = member.analyzeWithContent()
|
||||||
@@ -543,53 +584,53 @@ fun traverseOuterInstanceReferences(member: KtNamedDeclaration, stopAtFirst: Boo
|
|||||||
val outerClassDescriptor = containingClassOrObject.unsafeResolveToDescriptor() as ClassDescriptor
|
val outerClassDescriptor = containingClassOrObject.unsafeResolveToDescriptor() as ClassDescriptor
|
||||||
var found = false
|
var found = false
|
||||||
member.accept(
|
member.accept(
|
||||||
object : PsiRecursiveElementWalkingVisitor() {
|
object : PsiRecursiveElementWalkingVisitor() {
|
||||||
private fun getOuterInstanceReference(element: PsiElement): OuterInstanceReferenceUsageInfo? {
|
private fun getOuterInstanceReference(element: PsiElement): OuterInstanceReferenceUsageInfo? {
|
||||||
return when (element) {
|
return when (element) {
|
||||||
is KtThisExpression -> {
|
is KtThisExpression -> {
|
||||||
val descriptor = context[BindingContext.REFERENCE_TARGET, element.instanceReference]
|
val descriptor = context[BindingContext.REFERENCE_TARGET, element.instanceReference]
|
||||||
val isIndirect = when {
|
val isIndirect = when {
|
||||||
descriptor == outerClassDescriptor -> false
|
descriptor == outerClassDescriptor -> false
|
||||||
descriptor?.isAncestorOf(outerClassDescriptor, true) ?: false -> true
|
descriptor?.isAncestorOf(outerClassDescriptor, true) ?: false -> true
|
||||||
else -> return null
|
else -> return null
|
||||||
}
|
|
||||||
OuterInstanceReferenceUsageInfo.ExplicitThis(element, isIndirect)
|
|
||||||
}
|
}
|
||||||
is KtSimpleNameExpression -> {
|
OuterInstanceReferenceUsageInfo.ExplicitThis(element, isIndirect)
|
||||||
val resolvedCall = element.getResolvedCall(context) ?: return null
|
}
|
||||||
val dispatchReceiver = resolvedCall.dispatchReceiver as? ImplicitReceiver
|
is KtSimpleNameExpression -> {
|
||||||
val extensionReceiver = resolvedCall.extensionReceiver as? ImplicitReceiver
|
val resolvedCall = element.getResolvedCall(context) ?: return null
|
||||||
var isIndirect = false
|
val dispatchReceiver = resolvedCall.dispatchReceiver as? ImplicitReceiver
|
||||||
val isDoubleReceiver = when (outerClassDescriptor) {
|
val extensionReceiver = resolvedCall.extensionReceiver as? ImplicitReceiver
|
||||||
dispatchReceiver?.declarationDescriptor -> extensionReceiver != null
|
var isIndirect = false
|
||||||
extensionReceiver?.declarationDescriptor -> dispatchReceiver != null
|
val isDoubleReceiver = when (outerClassDescriptor) {
|
||||||
else -> {
|
dispatchReceiver?.declarationDescriptor -> extensionReceiver != null
|
||||||
isIndirect = true
|
extensionReceiver?.declarationDescriptor -> dispatchReceiver != null
|
||||||
when {
|
else -> {
|
||||||
dispatchReceiver?.declarationDescriptor?.isAncestorOf(outerClassDescriptor, true) ?: false ->
|
isIndirect = true
|
||||||
extensionReceiver != null
|
when {
|
||||||
extensionReceiver?.declarationDescriptor?.isAncestorOf(outerClassDescriptor, true) ?: false ->
|
dispatchReceiver?.declarationDescriptor?.isAncestorOf(outerClassDescriptor, true) ?: false ->
|
||||||
dispatchReceiver != null
|
extensionReceiver != null
|
||||||
else -> return null
|
extensionReceiver?.declarationDescriptor?.isAncestorOf(outerClassDescriptor, true) ?: false ->
|
||||||
}
|
dispatchReceiver != null
|
||||||
|
else -> return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OuterInstanceReferenceUsageInfo.ImplicitReceiver(resolvedCall.call.callElement, isIndirect, isDoubleReceiver)
|
|
||||||
}
|
}
|
||||||
else -> 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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitElement(element: PsiElement) {
|
||||||
|
getOuterInstanceReference(element)?.let {
|
||||||
|
body(it)
|
||||||
|
found = true
|
||||||
|
if (stopAtFirst) stopWalking()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
super.visitElement(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,12 @@ import org.jetbrains.kotlin.idea.core.util.toPsiDirectory
|
|||||||
import org.jetbrains.kotlin.idea.core.util.toPsiFile
|
import org.jetbrains.kotlin.idea.core.util.toPsiFile
|
||||||
import org.jetbrains.kotlin.idea.jsonUtils.getNullableString
|
import org.jetbrains.kotlin.idea.jsonUtils.getNullableString
|
||||||
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
import org.jetbrains.kotlin.idea.jsonUtils.getString
|
||||||
import org.jetbrains.kotlin.idea.refactoring.*
|
import org.jetbrains.kotlin.idea.refactoring.AbstractMultifileRefactoringTest
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.changePackage.KotlinChangePackageRefactoring
|
import org.jetbrains.kotlin.idea.refactoring.move.changePackage.KotlinChangePackageRefactoring
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveClassesOrPackages.KotlinAwareDelegatingMoveDestination
|
import org.jetbrains.kotlin.idea.refactoring.move.moveClassesOrPackages.KotlinAwareDelegatingMoveDestination
|
||||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.runRefactoringTest
|
||||||
import org.jetbrains.kotlin.idea.search.allScope
|
import org.jetbrains.kotlin.idea.search.allScope
|
||||||
import org.jetbrains.kotlin.idea.search.projectScope
|
import org.jetbrains.kotlin.idea.search.projectScope
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
|
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
|
||||||
@@ -69,12 +71,12 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
val targetPackage = config.getString("targetPackage")
|
val targetPackage = config.getString("targetPackage")
|
||||||
|
|
||||||
MoveClassesOrPackagesProcessor(
|
MoveClassesOrPackagesProcessor(
|
||||||
mainFile.project,
|
mainFile.project,
|
||||||
classesToMove.toTypedArray(),
|
classesToMove.toTypedArray(),
|
||||||
MultipleRootsMoveDestination(PackageWrapper(mainFile.manager, targetPackage)),
|
MultipleRootsMoveDestination(PackageWrapper(mainFile.manager, targetPackage)),
|
||||||
/* searchInComments = */ false,
|
/* searchInComments = */ false,
|
||||||
/* searchInNonJavaFiles = */ true,
|
/* searchInNonJavaFiles = */ true,
|
||||||
/* moveCallback = */ null
|
/* moveCallback = */ null
|
||||||
).run()
|
).run()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -93,22 +95,21 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
val moveDestination = if (targetDirectory != null) {
|
val moveDestination = if (targetDirectory != null) {
|
||||||
val targetSourceRoot = ProjectRootManager.getInstance(project).fileIndex.getSourceRootForFile(targetDirectory.virtualFile)!!
|
val targetSourceRoot = ProjectRootManager.getInstance(project).fileIndex.getSourceRootForFile(targetDirectory.virtualFile)!!
|
||||||
KotlinAwareDelegatingMoveDestination(
|
KotlinAwareDelegatingMoveDestination(
|
||||||
AutocreatingSingleSourceRootMoveDestination(targetPackageWrapper, targetSourceRoot),
|
AutocreatingSingleSourceRootMoveDestination(targetPackageWrapper, targetSourceRoot),
|
||||||
targetPackage,
|
targetPackage,
|
||||||
targetDirectory
|
targetDirectory
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
MultipleRootsMoveDestination(targetPackageWrapper)
|
MultipleRootsMoveDestination(targetPackageWrapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveClassesOrPackagesProcessor(
|
MoveClassesOrPackagesProcessor(
|
||||||
project,
|
project,
|
||||||
arrayOf(sourcePackage),
|
arrayOf(sourcePackage),
|
||||||
moveDestination,
|
moveDestination,
|
||||||
/* searchInComments = */ false,
|
/* searchInComments = */ false,
|
||||||
/* searchInNonJavaFiles = */ true,
|
/* searchInNonJavaFiles = */ true,
|
||||||
/* moveCallback = */ null
|
/* moveCallback = */ null
|
||||||
).run()
|
).run()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -121,12 +122,12 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
val targetClass = config.getString("targetClass")
|
val targetClass = config.getString("targetClass")
|
||||||
|
|
||||||
MoveClassToInnerProcessor(
|
MoveClassToInnerProcessor(
|
||||||
project,
|
project,
|
||||||
classesToMove.toTypedArray(),
|
classesToMove.toTypedArray(),
|
||||||
JavaPsiFacade.getInstance(project).findClass(targetClass, project.allScope())!!,
|
JavaPsiFacade.getInstance(project).findClass(targetClass, project.allScope())!!,
|
||||||
/* searchInComments = */ false,
|
/* searchInComments = */ false,
|
||||||
/* searchInNonJavaFiles = */ true,
|
/* searchInNonJavaFiles = */ true,
|
||||||
/* moveCallback = */ null
|
/* moveCallback = */ null
|
||||||
).run()
|
).run()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -141,12 +142,12 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
val targetPackage = config.getString("targetPackage")
|
val targetPackage = config.getString("targetPackage")
|
||||||
|
|
||||||
MoveInnerProcessor(
|
MoveInnerProcessor(
|
||||||
project,
|
project,
|
||||||
classToMove,
|
classToMove,
|
||||||
newClassName,
|
newClassName,
|
||||||
outerInstanceParameterName != null,
|
outerInstanceParameterName != null,
|
||||||
outerInstanceParameterName,
|
outerInstanceParameterName,
|
||||||
JavaPsiFacade.getInstance(project).findPackage(targetPackage)!!.directories[0]
|
JavaPsiFacade.getInstance(project).findPackage(targetPackage)!!.directories[0]
|
||||||
).run()
|
).run()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -161,29 +162,27 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
ActionRunner.runInsideWriteAction { VfsUtil.createDirectoryIfMissing(rootDir, targetDirPath) }
|
ActionRunner.runInsideWriteAction { VfsUtil.createDirectoryIfMissing(rootDir, targetDirPath) }
|
||||||
val newParent = if (targetPackage != null) {
|
val newParent = if (targetPackage != null) {
|
||||||
JavaPsiFacade.getInstance(project).findPackage(targetPackage)!!.directories[0]
|
JavaPsiFacade.getInstance(project).findPackage(targetPackage)!!.directories[0]
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
rootDir.findFileByRelativePath(targetDirPath)!!.toPsiDirectory(project)!!
|
rootDir.findFileByRelativePath(targetDirPath)!!.toPsiDirectory(project)!!
|
||||||
}
|
}
|
||||||
MoveFilesOrDirectoriesProcessor(
|
MoveFilesOrDirectoriesProcessor(
|
||||||
project,
|
project,
|
||||||
arrayOf(mainFile),
|
arrayOf(mainFile),
|
||||||
newParent,
|
newParent,
|
||||||
/* searchInComments = */ false,
|
/* searchInComments = */ false,
|
||||||
/* searchInNonJavaFiles = */ true,
|
/* searchInNonJavaFiles = */ true,
|
||||||
/* moveCallback = */ null,
|
/* moveCallback = */ null,
|
||||||
/* prepareSuccessfulCallback = */ null
|
/* prepareSuccessfulCallback = */ null
|
||||||
).run()
|
).run()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val targetFile = config.getString("targetFile")
|
val targetFile = config.getString("targetFile")
|
||||||
|
|
||||||
MoveHandler.doMove(
|
MoveHandler.doMove(
|
||||||
project,
|
project,
|
||||||
arrayOf(mainFile),
|
arrayOf(mainFile),
|
||||||
PsiManager.getInstance(project).findFile(rootDir.findFileByRelativePath(targetFile)!!)!!,
|
PsiManager.getInstance(project).findFile(rootDir.findFileByRelativePath(targetFile)!!)!!,
|
||||||
/* dataContext = */ null,
|
/* dataContext = */ null,
|
||||||
/* callback = */ null
|
/* callback = */ null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,13 +198,13 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
val targetDirPath = config.getString("targetDirectory")
|
val targetDirPath = config.getString("targetDirectory")
|
||||||
val targetDir = rootDir.findFileByRelativePath(targetDirPath)!!.toPsiDirectory(project)!!
|
val targetDir = rootDir.findFileByRelativePath(targetDirPath)!!.toPsiDirectory(project)!!
|
||||||
KotlinAwareMoveFilesOrDirectoriesProcessor(
|
KotlinAwareMoveFilesOrDirectoriesProcessor(
|
||||||
project,
|
project,
|
||||||
elementsToMove,
|
elementsToMove,
|
||||||
targetDir,
|
targetDir,
|
||||||
true,
|
true,
|
||||||
searchInComments = true,
|
searchInComments = true,
|
||||||
searchInNonJavaFiles = true,
|
searchInNonJavaFiles = true,
|
||||||
moveCallback = null
|
moveCallback = null
|
||||||
).run()
|
).run()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -251,7 +250,7 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
val project = mainFile.project
|
val project = mainFile.project
|
||||||
val sourceDir = rootDir.findFileByRelativePath(config.getString("sourceDir"))!!.toPsiDirectory(project)!!
|
val sourceDir = rootDir.findFileByRelativePath(config.getString("sourceDir"))!!.toPsiDirectory(project)!!
|
||||||
val targetDir = rootDir.findFileByRelativePath(config.getString("targetDir"))!!.toPsiDirectory(project)!!
|
val targetDir = rootDir.findFileByRelativePath(config.getString("targetDir"))!!.toPsiDirectory(project)!!
|
||||||
MoveDirectoryWithClassesProcessor(project, arrayOf(sourceDir), targetDir, true, true, true, {}).run()
|
MoveDirectoryWithClassesProcessor(project, arrayOf(sourceDir), targetDir, true, true, true) {}.run()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -261,24 +260,24 @@ enum class MoveAction : AbstractMultifileRefactoringTest.RefactoringAction {
|
|||||||
val elementToMove = elementsAtCaret.single().getNonStrictParentOfType<KtClassOrObject>()!!
|
val elementToMove = elementsAtCaret.single().getNonStrictParentOfType<KtClassOrObject>()!!
|
||||||
val targetClassName = config.getNullableString("targetClass")
|
val targetClassName = config.getNullableString("targetClass")
|
||||||
val targetClass =
|
val targetClass =
|
||||||
if (targetClassName != null) {
|
if (targetClassName != null) {
|
||||||
KotlinFullClassNameIndex.getInstance().get(targetClassName, project, project.projectScope()).first()!!
|
KotlinFullClassNameIndex.getInstance().get(targetClassName, project, project.projectScope()).first()!!
|
||||||
}
|
} else null
|
||||||
else null
|
val delegate = MoveDeclarationsDelegate.NestedClass(
|
||||||
val delegate = MoveDeclarationsDelegate.NestedClass(config.getNullableString("newName"),
|
config.getNullableString("newName"),
|
||||||
config.getNullableString("outerInstanceParameter"))
|
config.getNullableString("outerInstanceParameter")
|
||||||
|
)
|
||||||
val moveTarget =
|
val moveTarget =
|
||||||
if (targetClass != null) {
|
if (targetClass != null) {
|
||||||
KotlinMoveTargetForExistingElement(targetClass)
|
KotlinMoveTargetForExistingElement(targetClass)
|
||||||
}
|
} else {
|
||||||
else {
|
val fileName = (delegate.newClassName ?: elementToMove.name!!) + ".kt"
|
||||||
val fileName = (delegate.newClassName ?: elementToMove.name!!) + ".kt"
|
val targetPackageFqName = (mainFile as KtFile).packageFqName
|
||||||
val targetPackageFqName = (mainFile as KtFile).packageFqName
|
val targetDir = mainFile.containingDirectory!!
|
||||||
val targetDir = mainFile.containingDirectory!!
|
KotlinMoveTargetForDeferredFile(targetPackageFqName, targetDir, null) {
|
||||||
KotlinMoveTargetForDeferredFile(targetPackageFqName, targetDir, null) {
|
createKotlinFile(fileName, targetDir, targetPackageFqName.asString())
|
||||||
createKotlinFile(fileName, targetDir, targetPackageFqName.asString())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
val descriptor = MoveDeclarationsDescriptor(project, MoveSource(elementToMove), moveTarget, delegate)
|
val descriptor = MoveDeclarationsDescriptor(project, MoveSource(elementToMove), moveTarget, delegate)
|
||||||
MoveKotlinDeclarationsProcessor(descriptor).run()
|
MoveKotlinDeclarationsProcessor(descriptor).run()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user