Refactor Move refactoring

This commit is contained in:
Igor Yakovlev
2020-03-30 15:49:31 +03:00
parent a9de0a219b
commit 5414b9dfb3
7 changed files with 40 additions and 32 deletions
@@ -930,6 +930,8 @@ text.member.extension.call.will.not.be.processed.0=Member extension call won''t
text.move.declaration.no.support.for.companion.objects=Move declaration is not supported for companion objects text.move.declaration.no.support.for.companion.objects=Move declaration is not supported for companion objects
text.move.declaration.no.support.for.enums=Move declaration is not supported for enum entries text.move.declaration.no.support.for.enums=Move declaration is not supported for enum entries
text.move.declaration.supports.only.top.levels.and.nested.classes=Move declaration is only supported for top-level declarations and nested classes text.move.declaration.supports.only.top.levels.and.nested.classes=Move declaration is only supported for top-level declarations and nested classes
text.move.declaration.proceed.move.without.mpp.counterparts.text=This refactoring will move selected declaration without it's expect/actual counterparts that may lead to compilation errors.\nDo you wish to proceed?
text.move.declaration.proceed.move.without.mpp.counterparts.title=MPP declarations does not supported by this refactoring.
text.move.declarations=Move declarations text.move.declarations=Move declarations
text.move.file.0=Move {0} text.move.file.0=Move {0}
text.move.refactoring.not.available.during.indexing=Move refactoring is not available while indexing is in progress text.move.refactoring.not.available.during.indexing=Move refactoring is not available while indexing is in progress
@@ -172,11 +172,11 @@ class MoveKotlinDeclarationsHandler internal constructor(private val handlerActi
} }
val initialTargetDirectory = MoveFilesOrDirectoriesUtil.resolveToDirectory(project, initialTargetElement) val initialTargetDirectory = MoveFilesOrDirectoriesUtil.resolveToDirectory(project, initialTargetElement)
if (!ApplicationManager.getApplication().isUnitTestMode && elementsToSearch.any { it.isExpectDeclaration() || it.isEffectivelyActual() } if (!ApplicationManager.getApplication().isUnitTestMode &&
elementsToSearch.any { it.isExpectDeclaration() || it.isEffectivelyActual() }
) { ) {
val message = RefactoringBundle.getCannotRefactorMessage( val message = RefactoringBundle.getCannotRefactorMessage(KotlinBundle.message("text.move.declaration.proceed.move.without.mpp.counterparts.text"))
"This refactoring will move selected declaration without it's expect/actual counterparts that may lead to compilation errors.\n\"Do you wish to proceed?\"") val title = RefactoringBundle.getCannotRefactorMessage(KotlinBundle.message("text.move.declaration.proceed.move.without.mpp.counterparts.title"))
val title = RefactoringBundle.getCannotRefactorMessage("MPP declarations does not supported by this refactoring.")
val proceedWithIncompleteRefactoring = Messages.showYesNoDialog(project, message, title, Messages.getWarningIcon()) val proceedWithIncompleteRefactoring = Messages.showYesNoDialog(project, message, title, Messages.getWarningIcon())
if (proceedWithIncompleteRefactoring != Messages.YES) return true if (proceedWithIncompleteRefactoring != Messages.YES) return true
} }
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.idea.refactoring.isInKotlinAwareSourceRoot
import org.jetbrains.kotlin.idea.refactoring.move.logFusForMoveRefactoring import org.jetbrains.kotlin.idea.refactoring.move.logFusForMoveRefactoring
import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import java.util.*
import javax.swing.JComponent import javax.swing.JComponent
class KotlinAwareMoveFilesOrDirectoriesDialog( class KotlinAwareMoveFilesOrDirectoriesDialog(
@@ -66,6 +65,12 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
!ApplicationManager.getApplication().isUnitTestMode && PropertiesComponent.getInstance().getBoolean(id, defaultValue) !ApplicationManager.getApplication().isUnitTestMode && PropertiesComponent.getInstance().getBoolean(id, defaultValue)
} }
private data class CheckboxesState(
val searchReferences: Boolean,
val openInEditor: Boolean,
val updatePackageDirective: Boolean
)
private val nameLabel = JBLabelDecorator.createJBLabelDecorator().setBold(true) private val nameLabel = JBLabelDecorator.createJBLabelDecorator().setBold(true)
private val targetDirectoryField = TextFieldWithHistoryWithBrowseButton() private val targetDirectoryField = TextFieldWithHistoryWithBrowseButton()
private val searchReferencesCb = NonFocusableCheckBox(KotlinBundle.message("checkbox.text.search.references")).apply { private val searchReferencesCb = NonFocusableCheckBox(KotlinBundle.message("checkbox.text.search.references")).apply {
@@ -73,7 +78,7 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
} }
private val openInEditorCb = NonFocusableCheckBox(KotlinBundle.message("checkbox.text.open.moved.files.in.editor")) private val openInEditorCb = NonFocusableCheckBox(KotlinBundle.message("checkbox.text.open.moved.files.in.editor"))
private val updatePackageDirectiveCb = NonFocusableCheckBox() private val updatePackageDirectiveCb = NonFocusableCheckBox()
private val initializedCheckBoxesState: BitSet private val initializedCheckBoxesState: CheckboxesState
override fun getHelpId() = HELP_ID override fun getHelpId() = HELP_ID
@@ -85,11 +90,11 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
initializedCheckBoxesState = getCheckboxesState(applyDefaults = true) initializedCheckBoxesState = getCheckboxesState(applyDefaults = true)
} }
private fun getCheckboxesState(applyDefaults: Boolean) = BitSet(3).apply { private fun getCheckboxesState(applyDefaults: Boolean) = CheckboxesState(
set(0, applyDefaults || searchReferencesCb.isSelected) //searchReferencesCb is true by default searchReferences = applyDefaults || searchReferencesCb.isSelected, //searchReferencesCb is true by default
set(1, !applyDefaults && openInEditorCb.isSelected) //openInEditorCb is false by default openInEditor = !applyDefaults && openInEditorCb.isSelected, //openInEditorCb is false by default
set(2, updatePackageDirectiveCb.isSelected) updatePackageDirective = updatePackageDirectiveCb.isSelected
} )
override fun createActions() = arrayOf(okAction, cancelAction, helpAction) override fun createActions() = arrayOf(okAction, cancelAction, helpAction)
@@ -212,11 +217,11 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
project.executeCommand(MoveHandler.REFACTORING_NAME) { project.executeCommand(MoveHandler.REFACTORING_NAME) {
with(modelResult) { with(modelResult) {
logFusForMoveRefactoring( logFusForMoveRefactoring(
elementsCount, numberOfEntities = elementsCount,
entityToMove, entity = entityToMove,
destination, destination = destination,
getCheckboxesState(applyDefaults = false) == initializedCheckBoxesState, isDefault = getCheckboxesState(applyDefaults = false) == initializedCheckBoxesState,
Runnable { processor.run() } body = processor
) )
} }
} }
@@ -180,7 +180,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
@NotNull Set<KtNamedDeclaration> elementsToMove, @NotNull Set<KtNamedDeclaration> elementsToMove,
@NotNull List<KtNamedDeclaration> declarations @NotNull List<KtNamedDeclaration> declarations
) { ) {
////KotlinMemberInfo run resolve on declaration so it is good to place it to the process //KotlinMemberInfo run resolve on declaration so it is good to place it to the process
List<KotlinMemberInfo> memberInfos = MoveUtilsKt.mapWithReadActionInProcess(declarations, myProject, MoveHandler.REFACTORING_NAME, (declaration) -> { List<KotlinMemberInfo> memberInfos = MoveUtilsKt.mapWithReadActionInProcess(declarations, myProject, MoveHandler.REFACTORING_NAME, (declaration) -> {
KotlinMemberInfo memberInfo = new KotlinMemberInfo(declaration, false); KotlinMemberInfo memberInfo = new KotlinMemberInfo(declaration, false);
memberInfo.setChecked(elementsToMove.contains(declaration)); memberInfo.setChecked(elementsToMove.contains(declaration));
@@ -336,7 +336,7 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
} }
private boolean isMPPDeclarationInList(List<KtNamedDeclaration> declarations) { private boolean isMPPDeclarationInList(List<KtNamedDeclaration> declarations) {
for(KtNamedDeclaration element : declarations) { for (KtNamedDeclaration element : declarations) {
if (ExpectActualUtilKt.isEffectivelyActual(element, true) || if (ExpectActualUtilKt.isEffectivelyActual(element, true) ||
ExpectActualUtilKt.isExpectDeclaration(element)) { ExpectActualUtilKt.isExpectDeclaration(element)) {
return true; return true;
@@ -219,14 +219,16 @@ internal class MoveKotlinTopLevelDeclarationsModel(
} }
private fun getFUSParameters(): Pair<MovedEntity, MoveRefactoringDestination> { private fun getFUSParameters(): Pair<MovedEntity, MoveRefactoringDestination> {
val classType = if (elementsToMoveHasMPP) MovedEntity.MPPCLASSES else MovedEntity.CLASSES val (classType, functionType, mixedType) =
val functionType = if (elementsToMoveHasMPP) MovedEntity.MPPFUNCTIONS else MovedEntity.FUNCTIONS if (elementsToMoveHasMPP)
val mixedType = if (elementsToMoveHasMPP) MovedEntity.MPPMIXED else MovedEntity.MIXED Triple(MovedEntity.MPPCLASSES, MovedEntity.MPPFUNCTIONS, MovedEntity.MPPMIXED)
else
Triple(MovedEntity.CLASSES, MovedEntity.FUNCTIONS, MovedEntity.MIXED)
val allClasses = elementsToMove.any { element -> element is KtClassOrObject } val classesAreGoingToMove = elementsToMove.any { it is KtClassOrObject }
val allFunctions = elementsToMove.any { element -> element is KtFunction } val functionsAreGoingToMove = elementsToMove.any { it is KtFunction }
val entity = if (allClasses && allFunctions) mixedType else val entity = if (classesAreGoingToMove && functionsAreGoingToMove) mixedType else
if (allClasses) classType else functionType if (classesAreGoingToMove) classType else functionType
val destination = if (isMoveToPackage) MoveRefactoringDestination.PACKAGE else MoveRefactoringDestination.FILE val destination = if (isMoveToPackage) MoveRefactoringDestination.PACKAGE else MoveRefactoringDestination.FILE
@@ -79,7 +79,7 @@ class KotlinMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandlerCompat(
entityToMove, entityToMove,
destination, destination,
true, true,
Runnable { processor.run() } processor
) )
} else { } else {
processor.run() processor.run()
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.idea.refactoring.move package org.jetbrains.kotlin.idea.refactoring.move
import com.intellij.ide.util.DirectoryUtil import com.intellij.ide.util.DirectoryUtil
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task import com.intellij.openapi.progress.Task
@@ -43,6 +42,7 @@ import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector
import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -720,15 +720,14 @@ internal fun <T> List<KtNamedDeclaration>.mapWithReadActionInProcess(
val result = mutableListOf<T>() val result = mutableListOf<T>()
val task: Task.Modal = object : Task.Modal(project, title, false) { val task: Task.Modal = object : Task.Modal(project, title, false) {
override fun run(indicator: ProgressIndicator) { override fun run(indicator: ProgressIndicator) {
val count = 0
val fraction: Double = 1.0 / declarations.size val fraction: Double = 1.0 / declarations.size
indicator.fraction = 0.0 indicator.fraction = 0.0
ApplicationManager.getApplication().runReadAction(Runnable { runReadAction {
for (declaration in declarations) { declarations.forEachIndexed { index, declaration ->
result.add(body(declaration)) result.add(body(declaration))
indicator.fraction = fraction * count indicator.fraction = fraction * index
} }
}) }
} }
} }
ProgressManager.getInstance().run(task) ProgressManager.getInstance().run(task)