Add FUS support to move refactoring
This commit is contained in:
committed by
Igor Yakovlev
parent
f489eda0e7
commit
8877559c02
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.statistics
|
||||
|
||||
object MoveRefactoringFUSCollector {
|
||||
|
||||
/**
|
||||
* @param isDefault is something changed in Move Refactoring Dialog check-boxes state
|
||||
*/
|
||||
fun log(
|
||||
timeStarted: Long,
|
||||
timeFinished: Long,
|
||||
numberOfEntities: Int,
|
||||
entity: MovedEntity,
|
||||
destination: MoveRefactoringDestination,
|
||||
isDefault: Boolean,
|
||||
isSucceeded: Boolean
|
||||
) {
|
||||
|
||||
val data = mapOf(
|
||||
"lagging" to (timeFinished - timeStarted).toString(),
|
||||
"entity" to entity.toString(),
|
||||
"destination" to destination.toString(),
|
||||
"number_of_entities" to numberOfEntities.toString(),
|
||||
"are_settings_changed" to isDefault.toString(),
|
||||
"succeeded" to isSucceeded.toString()
|
||||
)
|
||||
|
||||
KotlinFUSLogger.log(FUSEventGroups.Refactoring, "Move", data)
|
||||
}
|
||||
|
||||
enum class MoveRefactoringDestination {
|
||||
PACKAGE, FILE, DECLARATION
|
||||
}
|
||||
|
||||
enum class MovedEntity {
|
||||
FUNCTIONS, CLASSES, MIXED, MPPCLASSES, MPPFUNCTIONS, MPPMIXED, PACKAGE, FILES
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
<statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.action.refactoring" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.refactoring" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
|
||||
|
||||
@@ -108,7 +108,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
<statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.action.refactoring" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.refactoring" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
|
||||
|
||||
@@ -108,7 +108,7 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
<statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.action.refactoring" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.refactoring" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
|
||||
<statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
|
||||
|
||||
+4
-4
@@ -104,7 +104,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
|
||||
|
||||
caseDataKeeper.caseData = model.testDataString()
|
||||
|
||||
model.computeModelResult(throwOnConflicts = true).run()
|
||||
model.computeModelResult(throwOnConflicts = true).processor.run()
|
||||
}
|
||||
|
||||
private fun doWithMoveKotlinNestedClassesToUpperLevelModel(nestedClass: KtClassOrObject, targetContainer: PsiElement?) {
|
||||
@@ -135,7 +135,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
|
||||
|
||||
caseDataKeeper.caseData = model.testDataString()
|
||||
|
||||
model.computeModelResult(throwOnConflicts = true).run()
|
||||
model.computeModelResult(throwOnConflicts = true).processor.run()
|
||||
}
|
||||
|
||||
override fun invokeMoveKotlinNestedClassesRefactoring(
|
||||
@@ -188,7 +188,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
|
||||
|
||||
caseDataKeeper.caseData = model.testDataString()
|
||||
|
||||
model.computeModelResult(throwOnConflicts = true).run()
|
||||
model.computeModelResult(throwOnConflicts = true).processor.run()
|
||||
}
|
||||
|
||||
override fun invokeKotlinSelectNestedClassChooser(nestedClass: KtClassOrObject, targetContainer: PsiElement?) {
|
||||
@@ -236,7 +236,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
|
||||
caseDataKeeper.caseData = model.testDataString()
|
||||
|
||||
project.executeCommand(MoveHandler.REFACTORING_NAME) {
|
||||
model.computeModelResult().run()
|
||||
model.computeModelResult().processor.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-3
@@ -6,11 +6,21 @@
|
||||
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui
|
||||
|
||||
import com.intellij.openapi.options.ConfigurationException
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MovedEntity
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MoveRefactoringDestination
|
||||
|
||||
internal interface Model<out T> {
|
||||
internal class ModelResultWithFUSData(
|
||||
val processor: BaseRefactoringProcessor,
|
||||
val elementsCount: Int,
|
||||
val entityToMove: MovedEntity,
|
||||
val destination: MoveRefactoringDestination
|
||||
)
|
||||
|
||||
internal interface Model {
|
||||
@Throws(ConfigurationException::class)
|
||||
fun computeModelResult(throwOnConflicts: Boolean = false): T
|
||||
fun computeModelResult(throwOnConflicts: Boolean = false): ModelResultWithFUSData
|
||||
|
||||
@Throws(ConfigurationException::class)
|
||||
fun computeModelResult(): T
|
||||
fun computeModelResult(): ModelResultWithFUSData
|
||||
}
|
||||
+28
-7
@@ -18,7 +18,10 @@ import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.openapi.ui.TextComponentAccessor
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.PsiDirectory
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiFileSystemItem
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesDialog
|
||||
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler
|
||||
@@ -34,9 +37,10 @@ import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.core.packageMatchesDirectoryOrImplicit
|
||||
import org.jetbrains.kotlin.idea.core.util.onTextChange
|
||||
import org.jetbrains.kotlin.idea.refactoring.isInKotlinAwareSourceRoot
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinAwareMoveFilesOrDirectoriesProcessor
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.logFusForMoveRefactoring
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.*
|
||||
import javax.swing.JComponent
|
||||
|
||||
class KotlinAwareMoveFilesOrDirectoriesDialog(
|
||||
@@ -69,6 +73,7 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
||||
}
|
||||
private val openInEditorCb = NonFocusableCheckBox(KotlinBundle.message("checkbox.text.open.moved.files.in.editor"))
|
||||
private val updatePackageDirectiveCb = NonFocusableCheckBox()
|
||||
private val initializedCheckBoxesState: BitSet
|
||||
|
||||
override fun getHelpId() = HELP_ID
|
||||
|
||||
@@ -76,6 +81,14 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
||||
title = RefactoringBundle.message("move.title")
|
||||
init()
|
||||
initializeData()
|
||||
|
||||
initializedCheckBoxesState = getCheckboxesState(applyDefaults = true)
|
||||
}
|
||||
|
||||
private fun getCheckboxesState(applyDefaults: Boolean) = BitSet(3).apply {
|
||||
set(0, applyDefaults || searchReferencesCb.isSelected) //searchReferencesCb is true by default
|
||||
set(1, !applyDefaults && openInEditorCb.isSelected) //openInEditorCb is false by default
|
||||
set(2, updatePackageDirectiveCb.isSelected)
|
||||
}
|
||||
|
||||
override fun createActions() = arrayOf(okAction, cancelAction, helpAction)
|
||||
@@ -163,7 +176,7 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getModel(): Model<KotlinAwareMoveFilesOrDirectoriesProcessor> {
|
||||
private fun getModel(): Model {
|
||||
|
||||
val directory = LocalFileSystem.getInstance().findFileByPath(selectedDirectoryName)?.let {
|
||||
PsiManager.getInstance(project).findDirectory(it)
|
||||
@@ -188,20 +201,28 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
|
||||
|
||||
override fun doOKAction() {
|
||||
|
||||
val processor: KotlinAwareMoveFilesOrDirectoriesProcessor
|
||||
val modelResult: ModelResultWithFUSData
|
||||
try {
|
||||
processor = getModel().computeModelResult()
|
||||
modelResult = getModel().computeModelResult()
|
||||
} catch (e: ConfigurationException) {
|
||||
setErrorText(e.message)
|
||||
return
|
||||
}
|
||||
|
||||
project.executeCommand(MoveHandler.REFACTORING_NAME) {
|
||||
processor.run()
|
||||
with(modelResult) {
|
||||
logFusForMoveRefactoring(
|
||||
elementsCount,
|
||||
entityToMove,
|
||||
destination,
|
||||
getCheckboxesState(applyDefaults = false) == initializedCheckBoxesState,
|
||||
Runnable { processor.run() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
setConfigurationValue(id = MOVE_FILES_OPEN_IN_EDITOR, value = openInEditorCb.isSelected, defaultValue = false)
|
||||
setConfigurationValue(id = MOVE_FILES_SEARCH_REFERENCES, value = searchReferencesCb.isSelected, defaultValue = true)
|
||||
setConfigurationValue(id = MOVE_FILES_OPEN_IN_EDITOR, value = openInEditorCb.isSelected, defaultValue = false)
|
||||
|
||||
RecentsManager.getInstance(project).registerRecentEntry(RECENT_KEYS, targetDirectoryField.childComponent.text)
|
||||
|
||||
|
||||
+15
-5
@@ -20,19 +20,20 @@ import org.jetbrains.kotlin.idea.refactoring.isInKotlinAwareSourceRoot
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.getOrCreateDirectory
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinAwareMoveFilesOrDirectoriesProcessor
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.updatePackageDirective
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.nio.file.InvalidPathException
|
||||
import java.nio.file.Paths
|
||||
|
||||
class KotlinAwareMoveFilesOrDirectoriesModel(
|
||||
internal class KotlinAwareMoveFilesOrDirectoriesModel(
|
||||
val project: Project,
|
||||
val elementsToMove: List<PsiFileSystemItem>,
|
||||
val targetDirectoryName: String,
|
||||
val updatePackageDirective: Boolean,
|
||||
val searchReferences: Boolean,
|
||||
val moveCallback: MoveCallback?
|
||||
) : Model<KotlinAwareMoveFilesOrDirectoriesProcessor> {
|
||||
) : Model {
|
||||
|
||||
private fun checkedGetElementsToMove(selectedDirectory: PsiDirectory): List<PsiElement> {
|
||||
|
||||
@@ -94,20 +95,29 @@ class KotlinAwareMoveFilesOrDirectoriesModel(
|
||||
}
|
||||
|
||||
@Throws(ConfigurationException::class)
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): KotlinAwareMoveFilesOrDirectoriesProcessor {
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
|
||||
|
||||
checkModel()
|
||||
|
||||
val selectedDir = checkedGetTargetDirectory()
|
||||
|
||||
return KotlinAwareMoveFilesOrDirectoriesProcessor(
|
||||
val elementsToMove = checkedGetElementsToMove(selectedDir)
|
||||
|
||||
val processor = KotlinAwareMoveFilesOrDirectoriesProcessor(
|
||||
project,
|
||||
checkedGetElementsToMove(selectedDir),
|
||||
elementsToMove,
|
||||
selectedDir,
|
||||
searchReferences = searchReferences,
|
||||
searchInComments = false,
|
||||
searchInNonJavaFiles = false,
|
||||
moveCallback = moveCallback
|
||||
)
|
||||
|
||||
return ModelResultWithFUSData(
|
||||
processor,
|
||||
elementsToMove.size,
|
||||
MoveRefactoringFUSCollector.MovedEntity.FILES,
|
||||
MoveRefactoringFUSCollector.MoveRefactoringDestination.PACKAGE
|
||||
)
|
||||
}
|
||||
}
|
||||
+18
-5
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtilKt;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
|
||||
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.MoveUtilsKt;
|
||||
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinTypeReferenceEditorComboWithBrowseButton;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import javax.swing.*;
|
||||
@@ -82,6 +82,13 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
||||
validateButtons();
|
||||
|
||||
myHelpAction.setEnabled(false);
|
||||
|
||||
initializedCheckBoxesState = getCheckboxesState();
|
||||
}
|
||||
|
||||
private final int initializedCheckBoxesState;
|
||||
private int getCheckboxesState() {
|
||||
return openInEditorCheckBox.isSelected() ? 1 : 0;
|
||||
}
|
||||
|
||||
private void initClassChooser(@NotNull KtClassOrObject initialTargetClass) {
|
||||
@@ -217,7 +224,7 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
||||
return "#" + getClass().getName();
|
||||
}
|
||||
|
||||
private Model<MoveKotlinDeclarationsProcessor> getModel() {
|
||||
private Model getModel() {
|
||||
return new MoveKotlinNestedClassesModel(
|
||||
myProject,
|
||||
openInEditorCheckBox.isSelected(),
|
||||
@@ -230,16 +237,22 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
|
||||
@Override
|
||||
protected void doAction() {
|
||||
|
||||
MoveKotlinDeclarationsProcessor processor;
|
||||
ModelResultWithFUSData modelResult;
|
||||
try {
|
||||
processor = getModel().computeModelResult();
|
||||
modelResult = getModel().computeModelResult();
|
||||
}
|
||||
catch (ConfigurationException e) {
|
||||
setErrorText(e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
invokeRefactoring(processor);
|
||||
MoveUtilsKt.logFusForMoveRefactoring(
|
||||
modelResult.getElementsCount(),
|
||||
modelResult.getEntityToMove(),
|
||||
modelResult.getDestination(),
|
||||
getCheckboxesState() == initializedCheckBoxesState,
|
||||
() -> invokeRefactoring(modelResult.getProcessor())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-3
@@ -13,6 +13,8 @@ import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.move.MoveCallback
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MoveRefactoringDestination
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MovedEntity
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
|
||||
@@ -23,7 +25,7 @@ internal class MoveKotlinNestedClassesModel(
|
||||
val originalClass: KtClassOrObject,
|
||||
val targetClass: PsiElement?,
|
||||
val moveCallback: MoveCallback?
|
||||
) : Model<MoveKotlinDeclarationsProcessor> {
|
||||
) : Model {
|
||||
|
||||
private fun getCheckedTargetClass(): KtElement {
|
||||
val targetClass = this.targetClass ?: throw ConfigurationException(RefactoringBundle.message("no.destination.class.specified"))
|
||||
@@ -51,7 +53,7 @@ internal class MoveKotlinNestedClassesModel(
|
||||
override fun computeModelResult() = computeModelResult(throwOnConflicts = false)
|
||||
|
||||
@Throws(ConfigurationException::class)
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): MoveKotlinDeclarationsProcessor {
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
|
||||
val elementsToMove = selectedElementsToMove
|
||||
val target = KotlinMoveTargetForExistingElement(getCheckedTargetClass())
|
||||
val delegate = MoveDeclarationsDelegate.NestedClass()
|
||||
@@ -67,6 +69,13 @@ internal class MoveKotlinNestedClassesModel(
|
||||
openInEditor = openInEditorCheckBox
|
||||
)
|
||||
|
||||
return MoveKotlinDeclarationsProcessor(descriptor, Mover.Default, throwOnConflicts)
|
||||
val processor = MoveKotlinDeclarationsProcessor(descriptor, Mover.Default, throwOnConflicts)
|
||||
|
||||
return ModelResultWithFUSData(
|
||||
processor,
|
||||
elementsToMove.size,
|
||||
MovedEntity.CLASSES,
|
||||
MoveRefactoringDestination.DECLARATION
|
||||
)
|
||||
}
|
||||
}
|
||||
+26
-5
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.idea.core.KotlinNameSuggester;
|
||||
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator;
|
||||
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringSettings;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.MoveUtilsKt;
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.KtClass;
|
||||
import org.jetbrains.kotlin.psi.KtClassBody;
|
||||
@@ -41,6 +40,7 @@ import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -126,6 +126,19 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||
return ((ClassDescriptor) innerClassDescriptor.getContainingDeclaration()).getDefaultType();
|
||||
}
|
||||
|
||||
private BitSet initializedCheckBoxesState;
|
||||
private BitSet getCheckboxesState(boolean applyDefaults) {
|
||||
|
||||
BitSet state = new BitSet(3);
|
||||
|
||||
state.set(0, !applyDefaults && searchInCommentsCheckBox.isSelected()); //searchInCommentsCheckBox default is false
|
||||
state.set(1, !applyDefaults && searchForTextOccurrencesCheckBox.isSelected()); //searchForTextOccurrencesCheckBox default is false
|
||||
state.set(2, passOuterClassCheckBox.isSelected());
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
classNameField.setText(innerClass.getName());
|
||||
@@ -182,6 +195,8 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||
searchInCommentsCheckBox.setSelected(settings.MOVE_TO_UPPER_LEVEL_SEARCH_IN_COMMENTS);
|
||||
|
||||
super.init();
|
||||
|
||||
initializedCheckBoxesState = getCheckboxesState(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,7 +248,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||
}
|
||||
}
|
||||
|
||||
private Model<MoveKotlinDeclarationsProcessor> getModel() {
|
||||
private Model getModel() {
|
||||
return new MoveKotlinNestedClassesToUpperLevelModelWithUIChooser(
|
||||
project,
|
||||
innerClass,
|
||||
@@ -251,9 +266,9 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||
@Override
|
||||
protected void doAction() {
|
||||
|
||||
MoveKotlinDeclarationsProcessor processor;
|
||||
ModelResultWithFUSData modelResult;
|
||||
try {
|
||||
processor = getModel().computeModelResult();
|
||||
modelResult = getModel().computeModelResult();
|
||||
}
|
||||
catch (ConfigurationException e) {
|
||||
setErrorText(e.getMessage());
|
||||
@@ -266,6 +281,12 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
|
||||
|
||||
saveOpenInEditorOption();
|
||||
|
||||
invokeRefactoring(processor);
|
||||
MoveUtilsKt.logFusForMoveRefactoring(
|
||||
modelResult.getElementsCount(),
|
||||
modelResult.getEntityToMove(),
|
||||
modelResult.getDestination(),
|
||||
getCheckboxesState(false).equals(initializedCheckBoxesState),
|
||||
() -> invokeRefactoring(modelResult.getProcessor())
|
||||
);
|
||||
}
|
||||
}
|
||||
+19
-8
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.getTargetPackageFqName
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.roots.getSuitableDestinationSourceRoots
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MovedEntity
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MoveRefactoringDestination
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
@@ -48,7 +50,7 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
|
||||
val isSearchInNonJavaFiles: Boolean,
|
||||
val packageName: String,
|
||||
val isOpenInEditor: Boolean
|
||||
) : Model<MoveKotlinDeclarationsProcessor> {
|
||||
) : Model {
|
||||
|
||||
protected abstract fun chooseSourceRoot(
|
||||
newPackage: PackageWrapper,
|
||||
@@ -157,9 +159,9 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
|
||||
}
|
||||
|
||||
@Throws(ConfigurationException::class)
|
||||
private fun getMoveTarget(): KotlinMoveTarget {
|
||||
private fun getMoveTarget(): Pair<KotlinMoveTarget, MoveRefactoringDestination> {
|
||||
val target = getTargetContainerWithValidation()
|
||||
if (target is PsiDirectory) {
|
||||
return if (target is PsiDirectory) {
|
||||
val targetPackageFqName = getTargetPackageFqName(target)
|
||||
?: throw ConfigurationException(KotlinBundle.message("text.cannot.find.target.package.name"))
|
||||
|
||||
@@ -169,13 +171,15 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
|
||||
|
||||
val targetFileName = suggestedName + "." + KotlinFileType.EXTENSION
|
||||
|
||||
return KotlinMoveTargetForDeferredFile(
|
||||
val target = KotlinMoveTargetForDeferredFile(
|
||||
targetPackageFqName,
|
||||
target,
|
||||
targetFile = null
|
||||
) { createKotlinFile(targetFileName, target, targetPackageFqName.asString()) }
|
||||
|
||||
target to MoveRefactoringDestination.FILE
|
||||
} else {
|
||||
return KotlinMoveTargetForExistingElement(target as KtElement)
|
||||
KotlinMoveTargetForExistingElement(target as KtElement) to MoveRefactoringDestination.DECLARATION
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +187,7 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
|
||||
override fun computeModelResult() = computeModelResult(throwOnConflicts = false)
|
||||
|
||||
@Throws(ConfigurationException::class)
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): MoveKotlinDeclarationsProcessor {
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
|
||||
|
||||
val moveTarget = getMoveTarget()
|
||||
|
||||
@@ -192,7 +196,7 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
|
||||
val moveDescriptor = MoveDeclarationsDescriptor(
|
||||
project,
|
||||
MoveSource(innerClass),
|
||||
moveTarget,
|
||||
moveTarget.first,
|
||||
delegate,
|
||||
searchInComments,
|
||||
isSearchInNonJavaFiles,
|
||||
@@ -201,6 +205,13 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
|
||||
openInEditor = isOpenInEditor
|
||||
)
|
||||
|
||||
return MoveKotlinDeclarationsProcessor(moveDescriptor, Mover.Default, throwOnConflicts)
|
||||
val processor = MoveKotlinDeclarationsProcessor(moveDescriptor, Mover.Default, throwOnConflicts)
|
||||
|
||||
return ModelResultWithFUSData(
|
||||
processor = processor,
|
||||
elementsCount = 1,
|
||||
entityToMove = MovedEntity.CLASSES,
|
||||
destination = moveTarget.second
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+32
-10
@@ -12,7 +12,6 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton;
|
||||
import com.intellij.openapi.util.Pass;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel;
|
||||
import com.intellij.refactoring.classMembers.MemberInfoBase;
|
||||
@@ -42,7 +41,6 @@ import org.jetbrains.kotlin.idea.refactoring.move.MoveUtilsKt;
|
||||
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinDestinationFolderComboBox;
|
||||
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinFileChooserDialog;
|
||||
import org.jetbrains.kotlin.idea.util.ExpectActualUtilKt;
|
||||
import org.jetbrains.kotlin.psi.KtElement;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration;
|
||||
import org.jetbrains.kotlin.psi.KtPureElement;
|
||||
@@ -51,10 +49,8 @@ import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.idea.roots.ProjectRootUtilsKt.getSuitableDestinationSourceRoots;
|
||||
|
||||
@@ -148,6 +144,24 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
initMemberInfo(elementsToMove, sourceFiles);
|
||||
|
||||
updateControls();
|
||||
|
||||
initializedCheckBoxesState = getCheckboxesState(true);
|
||||
}
|
||||
|
||||
private final BitSet initializedCheckBoxesState;
|
||||
private BitSet getCheckboxesState(boolean applyDefaults) {
|
||||
|
||||
BitSet state = new BitSet(7);
|
||||
|
||||
state.set(0, applyDefaults || cbSearchInComments.isSelected()); //cbSearchInComments default is true
|
||||
state.set(1, applyDefaults || cbSearchTextOccurrences.isSelected()); //cbSearchTextOccurrences default is true
|
||||
state.set(2, applyDefaults || cbDeleteEmptySourceFiles.isSelected()); //cbDeleteEmptySourceFiles default is true
|
||||
state.set(3, applyDefaults || cbApplyMPPDeclarationsMove.isSelected()); //cbApplyMPPDeclarationsMove default is true
|
||||
state.set(4, cbSpecifyFileNameInPackage.isSelected());
|
||||
state.set(5, cbUpdatePackageDirective.isSelected());
|
||||
state.set(6, cbSearchReferences.isSelected());
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private static List<KtFile> getSourceFiles(@NotNull Collection<KtNamedDeclaration> elementsToMove) {
|
||||
@@ -427,16 +441,18 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
return elementsToMove;
|
||||
}
|
||||
|
||||
private Model<BaseRefactoringProcessor> getModel() throws ConfigurationException {
|
||||
private MoveKotlinTopLevelDeclarationsModel getModel() throws ConfigurationException {
|
||||
|
||||
DirectoryChooser.ItemWrapper selectedItem = (DirectoryChooser.ItemWrapper) destinationFolderCB.getComboBox().getSelectedItem();
|
||||
PsiDirectory selectedPsiDirectory = selectedItem != null ? selectedItem.getDirectory() : initialTargetDirectory;
|
||||
|
||||
boolean mppDeclarationSelected = cbApplyMPPDeclarationsMove.isSelected() && isMppDeclarationSelected();
|
||||
|
||||
List<KtNamedDeclaration> selectedElements = getSelectedElementsToMoveChecked();
|
||||
|
||||
return new MoveKotlinTopLevelDeclarationsModel(
|
||||
myProject,
|
||||
getSelectedElementsToMoveChecked(),
|
||||
selectedElements,
|
||||
getTargetPackage(),
|
||||
selectedPsiDirectory,
|
||||
tfFileNameInPackage.getText(),
|
||||
@@ -456,9 +472,9 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
@Override
|
||||
protected void doAction() {
|
||||
|
||||
BaseRefactoringProcessor processor;
|
||||
ModelResultWithFUSData modelResult;
|
||||
try {
|
||||
processor = getModel().computeModelResult();
|
||||
modelResult = getModel().computeModelResult();
|
||||
}
|
||||
catch (ConfigurationException e) {
|
||||
setErrorText(e.getMessage());
|
||||
@@ -468,7 +484,13 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
|
||||
saveRefactoringSettings();
|
||||
|
||||
try {
|
||||
invokeRefactoring(processor);
|
||||
MoveUtilsKt.logFusForMoveRefactoring(
|
||||
modelResult.getElementsCount(),
|
||||
modelResult.getEntityToMove(),
|
||||
modelResult.getDestination(),
|
||||
getCheckboxesState(false).equals(initializedCheckBoxesState),
|
||||
() -> invokeRefactoring(modelResult.getProcessor())
|
||||
);
|
||||
} catch (IncorrectOperationException e) {
|
||||
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.getMessage(), null, myProject);
|
||||
}
|
||||
|
||||
+22
-4
@@ -27,11 +27,15 @@ import org.jetbrains.kotlin.idea.refactoring.getOrCreateKotlinFile
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.getOrCreateDirectory
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.updatePackageDirective
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MovedEntity
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector.MoveRefactoringDestination
|
||||
import org.jetbrains.kotlin.idea.util.collectAllExpectAndActualDeclaration
|
||||
import org.jetbrains.kotlin.idea.util.isEffectivelyActual
|
||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtFunction
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import java.io.File
|
||||
import java.nio.file.InvalidPathException
|
||||
@@ -53,7 +57,7 @@ internal class MoveKotlinTopLevelDeclarationsModel(
|
||||
val isFullFileMove: Boolean,
|
||||
val applyMPPDeclarations: Boolean,
|
||||
val moveCallback: MoveCallback?
|
||||
) : Model<BaseRefactoringProcessor> {
|
||||
) : Model {
|
||||
|
||||
private inline fun <T, K> Set<T>.mapToSingleOrNull(transform: (T) -> K?): K? =
|
||||
mapTo(mutableSetOf(), transform).singleOrNull()
|
||||
@@ -217,15 +221,29 @@ internal class MoveKotlinTopLevelDeclarationsModel(
|
||||
override fun computeModelResult() = computeModelResult(throwOnConflicts = false)
|
||||
|
||||
@Throws(ConfigurationException::class)
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): BaseRefactoringProcessor {
|
||||
override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
|
||||
|
||||
verifyBeforeRun()
|
||||
|
||||
val classType = if (elementsToMoveHasMPP) MovedEntity.MPPCLASSES else MovedEntity.CLASSES
|
||||
val functionType = if (elementsToMoveHasMPP) MovedEntity.MPPFUNCTIONS else MovedEntity.FUNCTIONS
|
||||
val mixedType = if (elementsToMoveHasMPP) MovedEntity.MPPMIXED else MovedEntity.MIXED
|
||||
|
||||
val allClasses = elementsToMove.any { element -> element is KtClassOrObject }
|
||||
val allFunctions = elementsToMove.any { element -> element is KtFunction }
|
||||
val entity = if (allClasses && allFunctions) mixedType else
|
||||
if (allClasses) classType else functionType
|
||||
|
||||
val destination = if (isMoveToPackage) MoveRefactoringDestination.PACKAGE else MoveRefactoringDestination.FILE
|
||||
|
||||
if (isFullFileMove && isMoveToPackage) {
|
||||
tryMoveFile(throwOnConflicts)?.let { return it }
|
||||
tryMoveFile(throwOnConflicts)?.let {
|
||||
return ModelResultWithFUSData(it, elementsToMove.size, entity, destination)
|
||||
}
|
||||
}
|
||||
|
||||
return moveDeclaration(throwOnConflicts)
|
||||
val processor = moveDeclaration(throwOnConflicts)
|
||||
return ModelResultWithFUSData(processor, elementsToMove.size, entity, destination)
|
||||
}
|
||||
|
||||
private fun tryMoveFile(throwOnConflicts: Boolean): BaseRefactoringProcessor? {
|
||||
|
||||
+16
-2
@@ -16,6 +16,7 @@ import com.intellij.refactoring.move.MoveHandler
|
||||
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.MoveFilesOrDirectoriesHandlerCompat
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.logFusForMoveRefactoring
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesDialog
|
||||
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesModel
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
@@ -60,7 +61,8 @@ class KotlinMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandlerCompat(
|
||||
|
||||
val initialTargetDirectory = MoveFilesOrDirectoriesUtil.getInitialTargetDirectory(targetDirectory, elements)
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode && initialTargetDirectory !== null) {
|
||||
val isTestUnitMode = ApplicationManager.getApplication().isUnitTestMode
|
||||
if (isTestUnitMode && initialTargetDirectory !== null) {
|
||||
KotlinAwareMoveFilesOrDirectoriesModel(
|
||||
project,
|
||||
adjustedElementsToMove,
|
||||
@@ -70,7 +72,19 @@ class KotlinMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandlerCompat(
|
||||
moveCallback = callback
|
||||
).run {
|
||||
project.executeCommand(MoveHandler.REFACTORING_NAME) {
|
||||
computeModelResult().run()
|
||||
with(computeModelResult()) {
|
||||
if (!isTestUnitMode) {
|
||||
logFusForMoveRefactoring(
|
||||
elementsCount,
|
||||
entityToMove,
|
||||
destination,
|
||||
true,
|
||||
Runnable { processor.run() }
|
||||
)
|
||||
} else {
|
||||
processor.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.statistics.MoveRefactoringFUSCollector
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
@@ -55,7 +56,9 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.File
|
||||
import java.lang.System.currentTimeMillis
|
||||
import java.util.*
|
||||
import javax.swing.JCheckBox
|
||||
|
||||
sealed class ContainerInfo {
|
||||
abstract val fqName: FqName?
|
||||
@@ -679,4 +682,30 @@ internal fun getTargetPackageFqName(targetContainer: PsiElement): FqName? {
|
||||
return if (targetPackage != null) FqName(targetPackage.qualifiedName) else null
|
||||
}
|
||||
return if (targetContainer is KtFile) targetContainer.packageFqName else null
|
||||
}
|
||||
|
||||
internal fun logFusForMoveRefactoring(
|
||||
numberOfEntities: Int,
|
||||
entity: MoveRefactoringFUSCollector.MovedEntity,
|
||||
destination: MoveRefactoringFUSCollector.MoveRefactoringDestination,
|
||||
isDefault: Boolean,
|
||||
body: Runnable
|
||||
) {
|
||||
val timeStarted = currentTimeMillis()
|
||||
|
||||
var succeeded = false
|
||||
try {
|
||||
body.run()
|
||||
succeeded = true
|
||||
} finally {
|
||||
MoveRefactoringFUSCollector.log(
|
||||
timeStarted = timeStarted,
|
||||
timeFinished = currentTimeMillis(),
|
||||
numberOfEntities = numberOfEntities,
|
||||
destination = destination,
|
||||
isDefault = isDefault,
|
||||
entity = entity,
|
||||
isSucceeded = succeeded,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user