Add FUS support to move refactoring

This commit is contained in:
Anton Yalyshev
2020-02-03 09:37:02 +03:00
committed by Igor Yakovlev
parent f489eda0e7
commit 8877559c02
16 changed files with 279 additions and 59 deletions
@@ -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
}
}
+1 -1
View File
@@ -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.maven.target" version="3"/>
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/> <statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/> <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.newFileTempl" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/> <statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/> <statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
+1 -1
View File
@@ -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.maven.target" version="3"/>
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/> <statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/> <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.newFileTempl" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/> <statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/> <statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
+1 -1
View File
@@ -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.maven.target" version="3"/>
<statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/> <statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
<statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/> <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.newFileTempl" version="1"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/> <statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="2"/>
<statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/> <statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
@@ -104,7 +104,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
caseDataKeeper.caseData = model.testDataString() caseDataKeeper.caseData = model.testDataString()
model.computeModelResult(throwOnConflicts = true).run() model.computeModelResult(throwOnConflicts = true).processor.run()
} }
private fun doWithMoveKotlinNestedClassesToUpperLevelModel(nestedClass: KtClassOrObject, targetContainer: PsiElement?) { private fun doWithMoveKotlinNestedClassesToUpperLevelModel(nestedClass: KtClassOrObject, targetContainer: PsiElement?) {
@@ -135,7 +135,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
caseDataKeeper.caseData = model.testDataString() caseDataKeeper.caseData = model.testDataString()
model.computeModelResult(throwOnConflicts = true).run() model.computeModelResult(throwOnConflicts = true).processor.run()
} }
override fun invokeMoveKotlinNestedClassesRefactoring( override fun invokeMoveKotlinNestedClassesRefactoring(
@@ -188,7 +188,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
caseDataKeeper.caseData = model.testDataString() caseDataKeeper.caseData = model.testDataString()
model.computeModelResult(throwOnConflicts = true).run() model.computeModelResult(throwOnConflicts = true).processor.run()
} }
override fun invokeKotlinSelectNestedClassChooser(nestedClass: KtClassOrObject, targetContainer: PsiElement?) { override fun invokeKotlinSelectNestedClassChooser(nestedClass: KtClassOrObject, targetContainer: PsiElement?) {
@@ -236,7 +236,7 @@ internal class MoveKotlinDeclarationsHandlerTestActions(private val caseDataKeep
caseDataKeeper.caseData = model.testDataString() caseDataKeeper.caseData = model.testDataString()
project.executeCommand(MoveHandler.REFACTORING_NAME) { project.executeCommand(MoveHandler.REFACTORING_NAME) {
model.computeModelResult().run() model.computeModelResult().processor.run()
} }
} }
} }
@@ -6,11 +6,21 @@
package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui package org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui
import com.intellij.openapi.options.ConfigurationException 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) @Throws(ConfigurationException::class)
fun computeModelResult(throwOnConflicts: Boolean = false): T fun computeModelResult(throwOnConflicts: Boolean = false): ModelResultWithFUSData
@Throws(ConfigurationException::class) @Throws(ConfigurationException::class)
fun computeModelResult(): T fun computeModelResult(): ModelResultWithFUSData
} }
@@ -18,7 +18,10 @@ import com.intellij.openapi.ui.DialogWrapper
import com.intellij.openapi.ui.TextComponentAccessor import com.intellij.openapi.ui.TextComponentAccessor
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import com.intellij.openapi.vfs.LocalFileSystem 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.RefactoringBundle
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesDialog import com.intellij.refactoring.copy.CopyFilesOrDirectoriesDialog
import com.intellij.refactoring.copy.CopyFilesOrDirectoriesHandler 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.packageMatchesDirectoryOrImplicit
import org.jetbrains.kotlin.idea.core.util.onTextChange import org.jetbrains.kotlin.idea.core.util.onTextChange
import org.jetbrains.kotlin.idea.refactoring.isInKotlinAwareSourceRoot 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.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(
@@ -69,6 +73,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
override fun getHelpId() = HELP_ID override fun getHelpId() = HELP_ID
@@ -76,6 +81,14 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
title = RefactoringBundle.message("move.title") title = RefactoringBundle.message("move.title")
init() init()
initializeData() 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) 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 { val directory = LocalFileSystem.getInstance().findFileByPath(selectedDirectoryName)?.let {
PsiManager.getInstance(project).findDirectory(it) PsiManager.getInstance(project).findDirectory(it)
@@ -188,20 +201,28 @@ class KotlinAwareMoveFilesOrDirectoriesDialog(
override fun doOKAction() { override fun doOKAction() {
val processor: KotlinAwareMoveFilesOrDirectoriesProcessor val modelResult: ModelResultWithFUSData
try { try {
processor = getModel().computeModelResult() modelResult = getModel().computeModelResult()
} catch (e: ConfigurationException) { } catch (e: ConfigurationException) {
setErrorText(e.message) setErrorText(e.message)
return return
} }
project.executeCommand(MoveHandler.REFACTORING_NAME) { 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_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) RecentsManager.getInstance(project).registerRecentEntry(RECENT_KEYS, targetDirectoryField.childComponent.text)
@@ -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.getOrCreateDirectory
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinAwareMoveFilesOrDirectoriesProcessor import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinAwareMoveFilesOrDirectoriesProcessor
import org.jetbrains.kotlin.idea.refactoring.move.updatePackageDirective 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.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import java.nio.file.InvalidPathException import java.nio.file.InvalidPathException
import java.nio.file.Paths import java.nio.file.Paths
class KotlinAwareMoveFilesOrDirectoriesModel( internal class KotlinAwareMoveFilesOrDirectoriesModel(
val project: Project, val project: Project,
val elementsToMove: List<PsiFileSystemItem>, val elementsToMove: List<PsiFileSystemItem>,
val targetDirectoryName: String, val targetDirectoryName: String,
val updatePackageDirective: Boolean, val updatePackageDirective: Boolean,
val searchReferences: Boolean, val searchReferences: Boolean,
val moveCallback: MoveCallback? val moveCallback: MoveCallback?
) : Model<KotlinAwareMoveFilesOrDirectoriesProcessor> { ) : Model {
private fun checkedGetElementsToMove(selectedDirectory: PsiDirectory): List<PsiElement> { private fun checkedGetElementsToMove(selectedDirectory: PsiDirectory): List<PsiElement> {
@@ -94,20 +95,29 @@ class KotlinAwareMoveFilesOrDirectoriesModel(
} }
@Throws(ConfigurationException::class) @Throws(ConfigurationException::class)
override fun computeModelResult(throwOnConflicts: Boolean): KotlinAwareMoveFilesOrDirectoriesProcessor { override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
checkModel() checkModel()
val selectedDir = checkedGetTargetDirectory() val selectedDir = checkedGetTargetDirectory()
return KotlinAwareMoveFilesOrDirectoriesProcessor( val elementsToMove = checkedGetElementsToMove(selectedDir)
val processor = KotlinAwareMoveFilesOrDirectoriesProcessor(
project, project,
checkedGetElementsToMove(selectedDir), elementsToMove,
selectedDir, selectedDir,
searchReferences = searchReferences, searchReferences = searchReferences,
searchInComments = false, searchInComments = false,
searchInNonJavaFiles = false, searchInNonJavaFiles = false,
moveCallback = moveCallback moveCallback = moveCallback
) )
return ModelResultWithFUSData(
processor,
elementsToMove.size,
MoveRefactoringFUSCollector.MovedEntity.FILES,
MoveRefactoringFUSCollector.MoveRefactoringDestination.PACKAGE
)
} }
} }
@@ -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.KotlinMemberInfo;
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel; import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel;
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionTable; 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.idea.refactoring.ui.KotlinTypeReferenceEditorComboWithBrowseButton;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import javax.swing.*; import javax.swing.*;
@@ -82,6 +82,13 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
validateButtons(); validateButtons();
myHelpAction.setEnabled(false); myHelpAction.setEnabled(false);
initializedCheckBoxesState = getCheckboxesState();
}
private final int initializedCheckBoxesState;
private int getCheckboxesState() {
return openInEditorCheckBox.isSelected() ? 1 : 0;
} }
private void initClassChooser(@NotNull KtClassOrObject initialTargetClass) { private void initClassChooser(@NotNull KtClassOrObject initialTargetClass) {
@@ -217,7 +224,7 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
return "#" + getClass().getName(); return "#" + getClass().getName();
} }
private Model<MoveKotlinDeclarationsProcessor> getModel() { private Model getModel() {
return new MoveKotlinNestedClassesModel( return new MoveKotlinNestedClassesModel(
myProject, myProject,
openInEditorCheckBox.isSelected(), openInEditorCheckBox.isSelected(),
@@ -230,16 +237,22 @@ public class MoveKotlinNestedClassesDialog extends RefactoringDialog {
@Override @Override
protected void doAction() { protected void doAction() {
MoveKotlinDeclarationsProcessor processor; ModelResultWithFUSData modelResult;
try { try {
processor = getModel().computeModelResult(); modelResult = getModel().computeModelResult();
} }
catch (ConfigurationException e) { catch (ConfigurationException e) {
setErrorText(e.getMessage()); setErrorText(e.getMessage());
return; return;
} }
invokeRefactoring(processor); MoveUtilsKt.logFusForMoveRefactoring(
modelResult.getElementsCount(),
modelResult.getEntityToMove(),
modelResult.getDestination(),
getCheckboxesState() == initializedCheckBoxesState,
() -> invokeRefactoring(modelResult.getProcessor())
);
} }
@Override @Override
@@ -13,6 +13,8 @@ import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.move.MoveCallback import com.intellij.refactoring.move.MoveCallback
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.* 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.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
@@ -23,7 +25,7 @@ internal class MoveKotlinNestedClassesModel(
val originalClass: KtClassOrObject, val originalClass: KtClassOrObject,
val targetClass: PsiElement?, val targetClass: PsiElement?,
val moveCallback: MoveCallback? val moveCallback: MoveCallback?
) : Model<MoveKotlinDeclarationsProcessor> { ) : Model {
private fun getCheckedTargetClass(): KtElement { private fun getCheckedTargetClass(): KtElement {
val targetClass = this.targetClass ?: throw ConfigurationException(RefactoringBundle.message("no.destination.class.specified")) 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) override fun computeModelResult() = computeModelResult(throwOnConflicts = false)
@Throws(ConfigurationException::class) @Throws(ConfigurationException::class)
override fun computeModelResult(throwOnConflicts: Boolean): MoveKotlinDeclarationsProcessor { override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
val elementsToMove = selectedElementsToMove val elementsToMove = selectedElementsToMove
val target = KotlinMoveTargetForExistingElement(getCheckedTargetClass()) val target = KotlinMoveTargetForExistingElement(getCheckedTargetClass())
val delegate = MoveDeclarationsDelegate.NestedClass() val delegate = MoveDeclarationsDelegate.NestedClass()
@@ -67,6 +69,13 @@ internal class MoveKotlinNestedClassesModel(
openInEditor = openInEditorCheckBox openInEditor = openInEditorCheckBox
) )
return MoveKotlinDeclarationsProcessor(descriptor, Mover.Default, throwOnConflicts) val processor = MoveKotlinDeclarationsProcessor(descriptor, Mover.Default, throwOnConflicts)
return ModelResultWithFUSData(
processor,
elementsToMove.size,
MovedEntity.CLASSES,
MoveRefactoringDestination.DECLARATION
)
} }
} }
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.idea.core.KotlinNameSuggester;
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator; import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator;
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringSettings; import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringSettings;
import org.jetbrains.kotlin.idea.refactoring.move.MoveUtilsKt; 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.name.FqName;
import org.jetbrains.kotlin.psi.KtClass; import org.jetbrains.kotlin.psi.KtClass;
import org.jetbrains.kotlin.psi.KtClassBody; import org.jetbrains.kotlin.psi.KtClassBody;
@@ -41,6 +40,7 @@ import org.jetbrains.kotlin.types.KotlinType;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -126,6 +126,19 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
return ((ClassDescriptor) innerClassDescriptor.getContainingDeclaration()).getDefaultType(); 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 @Override
protected void init() { protected void init() {
classNameField.setText(innerClass.getName()); classNameField.setText(innerClass.getName());
@@ -182,6 +195,8 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
searchInCommentsCheckBox.setSelected(settings.MOVE_TO_UPPER_LEVEL_SEARCH_IN_COMMENTS); searchInCommentsCheckBox.setSelected(settings.MOVE_TO_UPPER_LEVEL_SEARCH_IN_COMMENTS);
super.init(); super.init();
initializedCheckBoxesState = getCheckboxesState(true);
} }
@Override @Override
@@ -233,7 +248,7 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
} }
} }
private Model<MoveKotlinDeclarationsProcessor> getModel() { private Model getModel() {
return new MoveKotlinNestedClassesToUpperLevelModelWithUIChooser( return new MoveKotlinNestedClassesToUpperLevelModelWithUIChooser(
project, project,
innerClass, innerClass,
@@ -251,9 +266,9 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
@Override @Override
protected void doAction() { protected void doAction() {
MoveKotlinDeclarationsProcessor processor; ModelResultWithFUSData modelResult;
try { try {
processor = getModel().computeModelResult(); modelResult = getModel().computeModelResult();
} }
catch (ConfigurationException e) { catch (ConfigurationException e) {
setErrorText(e.getMessage()); setErrorText(e.getMessage());
@@ -266,6 +281,12 @@ public class MoveKotlinNestedClassesToUpperLevelDialog extends MoveDialogBase {
saveOpenInEditorOption(); saveOpenInEditorOption();
invokeRefactoring(processor); MoveUtilsKt.logFusForMoveRefactoring(
modelResult.getElementsCount(),
modelResult.getEntityToMove(),
modelResult.getDestination(),
getCheckboxesState(false).equals(initializedCheckBoxesState),
() -> invokeRefactoring(modelResult.getProcessor())
);
} }
} }
@@ -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.getTargetPackageFqName
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.* import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.roots.getSuitableDestinationSourceRoots 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.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -48,7 +50,7 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
val isSearchInNonJavaFiles: Boolean, val isSearchInNonJavaFiles: Boolean,
val packageName: String, val packageName: String,
val isOpenInEditor: Boolean val isOpenInEditor: Boolean
) : Model<MoveKotlinDeclarationsProcessor> { ) : Model {
protected abstract fun chooseSourceRoot( protected abstract fun chooseSourceRoot(
newPackage: PackageWrapper, newPackage: PackageWrapper,
@@ -157,9 +159,9 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
} }
@Throws(ConfigurationException::class) @Throws(ConfigurationException::class)
private fun getMoveTarget(): KotlinMoveTarget { private fun getMoveTarget(): Pair<KotlinMoveTarget, MoveRefactoringDestination> {
val target = getTargetContainerWithValidation() val target = getTargetContainerWithValidation()
if (target is PsiDirectory) { return if (target is PsiDirectory) {
val targetPackageFqName = getTargetPackageFqName(target) val targetPackageFqName = getTargetPackageFqName(target)
?: throw ConfigurationException(KotlinBundle.message("text.cannot.find.target.package.name")) ?: throw ConfigurationException(KotlinBundle.message("text.cannot.find.target.package.name"))
@@ -169,13 +171,15 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
val targetFileName = suggestedName + "." + KotlinFileType.EXTENSION val targetFileName = suggestedName + "." + KotlinFileType.EXTENSION
return KotlinMoveTargetForDeferredFile( val target = KotlinMoveTargetForDeferredFile(
targetPackageFqName, targetPackageFqName,
target, target,
targetFile = null targetFile = null
) { createKotlinFile(targetFileName, target, targetPackageFqName.asString()) } ) { createKotlinFile(targetFileName, target, targetPackageFqName.asString()) }
target to MoveRefactoringDestination.FILE
} else { } 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) override fun computeModelResult() = computeModelResult(throwOnConflicts = false)
@Throws(ConfigurationException::class) @Throws(ConfigurationException::class)
override fun computeModelResult(throwOnConflicts: Boolean): MoveKotlinDeclarationsProcessor { override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
val moveTarget = getMoveTarget() val moveTarget = getMoveTarget()
@@ -192,7 +196,7 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
val moveDescriptor = MoveDeclarationsDescriptor( val moveDescriptor = MoveDeclarationsDescriptor(
project, project,
MoveSource(innerClass), MoveSource(innerClass),
moveTarget, moveTarget.first,
delegate, delegate,
searchInComments, searchInComments,
isSearchInNonJavaFiles, isSearchInNonJavaFiles,
@@ -201,6 +205,13 @@ internal abstract class MoveKotlinNestedClassesToUpperLevelModel(
openInEditor = isOpenInEditor 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
)
} }
} }
@@ -12,7 +12,6 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.Pass;
import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel; import com.intellij.refactoring.classMembers.AbstractMemberInfoModel;
import com.intellij.refactoring.classMembers.MemberInfoBase; 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.KotlinDestinationFolderComboBox;
import org.jetbrains.kotlin.idea.refactoring.ui.KotlinFileChooserDialog; import org.jetbrains.kotlin.idea.refactoring.ui.KotlinFileChooserDialog;
import org.jetbrains.kotlin.idea.util.ExpectActualUtilKt; import org.jetbrains.kotlin.idea.util.ExpectActualUtilKt;
import org.jetbrains.kotlin.psi.KtElement;
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.KtPureElement;
@@ -51,10 +49,8 @@ import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.util.Collection; import java.util.*;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.kotlin.idea.roots.ProjectRootUtilsKt.getSuitableDestinationSourceRoots; import static org.jetbrains.kotlin.idea.roots.ProjectRootUtilsKt.getSuitableDestinationSourceRoots;
@@ -148,6 +144,24 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
initMemberInfo(elementsToMove, sourceFiles); initMemberInfo(elementsToMove, sourceFiles);
updateControls(); 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) { private static List<KtFile> getSourceFiles(@NotNull Collection<KtNamedDeclaration> elementsToMove) {
@@ -427,16 +441,18 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
return elementsToMove; return elementsToMove;
} }
private Model<BaseRefactoringProcessor> getModel() throws ConfigurationException { private MoveKotlinTopLevelDeclarationsModel getModel() throws ConfigurationException {
DirectoryChooser.ItemWrapper selectedItem = (DirectoryChooser.ItemWrapper) destinationFolderCB.getComboBox().getSelectedItem(); DirectoryChooser.ItemWrapper selectedItem = (DirectoryChooser.ItemWrapper) destinationFolderCB.getComboBox().getSelectedItem();
PsiDirectory selectedPsiDirectory = selectedItem != null ? selectedItem.getDirectory() : initialTargetDirectory; PsiDirectory selectedPsiDirectory = selectedItem != null ? selectedItem.getDirectory() : initialTargetDirectory;
boolean mppDeclarationSelected = cbApplyMPPDeclarationsMove.isSelected() && isMppDeclarationSelected(); boolean mppDeclarationSelected = cbApplyMPPDeclarationsMove.isSelected() && isMppDeclarationSelected();
List<KtNamedDeclaration> selectedElements = getSelectedElementsToMoveChecked();
return new MoveKotlinTopLevelDeclarationsModel( return new MoveKotlinTopLevelDeclarationsModel(
myProject, myProject,
getSelectedElementsToMoveChecked(), selectedElements,
getTargetPackage(), getTargetPackage(),
selectedPsiDirectory, selectedPsiDirectory,
tfFileNameInPackage.getText(), tfFileNameInPackage.getText(),
@@ -456,9 +472,9 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
@Override @Override
protected void doAction() { protected void doAction() {
BaseRefactoringProcessor processor; ModelResultWithFUSData modelResult;
try { try {
processor = getModel().computeModelResult(); modelResult = getModel().computeModelResult();
} }
catch (ConfigurationException e) { catch (ConfigurationException e) {
setErrorText(e.getMessage()); setErrorText(e.getMessage());
@@ -468,7 +484,13 @@ public class MoveKotlinTopLevelDeclarationsDialog extends RefactoringDialog {
saveRefactoringSettings(); saveRefactoringSettings();
try { try {
invokeRefactoring(processor); MoveUtilsKt.logFusForMoveRefactoring(
modelResult.getElementsCount(),
modelResult.getEntityToMove(),
modelResult.getDestination(),
getCheckboxesState(false).equals(initializedCheckBoxesState),
() -> invokeRefactoring(modelResult.getProcessor())
);
} catch (IncorrectOperationException e) { } catch (IncorrectOperationException e) {
CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.getMessage(), null, myProject); CommonRefactoringUtil.showErrorMessage(RefactoringBundle.message("error.title"), e.getMessage(), null, myProject);
} }
@@ -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.getOrCreateDirectory
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.* import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.*
import org.jetbrains.kotlin.idea.refactoring.move.updatePackageDirective 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.collectAllExpectAndActualDeclaration
import org.jetbrains.kotlin.idea.util.isEffectivelyActual import org.jetbrains.kotlin.idea.util.isEffectivelyActual
import org.jetbrains.kotlin.idea.util.isExpectDeclaration import org.jetbrains.kotlin.idea.util.isExpectDeclaration
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
import java.io.File import java.io.File
import java.nio.file.InvalidPathException import java.nio.file.InvalidPathException
@@ -53,7 +57,7 @@ internal class MoveKotlinTopLevelDeclarationsModel(
val isFullFileMove: Boolean, val isFullFileMove: Boolean,
val applyMPPDeclarations: Boolean, val applyMPPDeclarations: Boolean,
val moveCallback: MoveCallback? val moveCallback: MoveCallback?
) : Model<BaseRefactoringProcessor> { ) : Model {
private inline fun <T, K> Set<T>.mapToSingleOrNull(transform: (T) -> K?): K? = private inline fun <T, K> Set<T>.mapToSingleOrNull(transform: (T) -> K?): K? =
mapTo(mutableSetOf(), transform).singleOrNull() mapTo(mutableSetOf(), transform).singleOrNull()
@@ -217,15 +221,29 @@ internal class MoveKotlinTopLevelDeclarationsModel(
override fun computeModelResult() = computeModelResult(throwOnConflicts = false) override fun computeModelResult() = computeModelResult(throwOnConflicts = false)
@Throws(ConfigurationException::class) @Throws(ConfigurationException::class)
override fun computeModelResult(throwOnConflicts: Boolean): BaseRefactoringProcessor { override fun computeModelResult(throwOnConflicts: Boolean): ModelResultWithFUSData {
verifyBeforeRun() 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) { 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? { private fun tryMoveFile(throwOnConflicts: Boolean): BaseRefactoringProcessor? {
@@ -16,6 +16,7 @@ import com.intellij.refactoring.move.MoveHandler
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.idea.refactoring.move.MoveFilesOrDirectoriesHandlerCompat 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.KotlinAwareMoveFilesOrDirectoriesDialog
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesModel import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.ui.KotlinAwareMoveFilesOrDirectoriesModel
import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.executeCommand
@@ -60,7 +61,8 @@ class KotlinMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandlerCompat(
val initialTargetDirectory = MoveFilesOrDirectoriesUtil.getInitialTargetDirectory(targetDirectory, elements) val initialTargetDirectory = MoveFilesOrDirectoriesUtil.getInitialTargetDirectory(targetDirectory, elements)
if (ApplicationManager.getApplication().isUnitTestMode && initialTargetDirectory !== null) { val isTestUnitMode = ApplicationManager.getApplication().isUnitTestMode
if (isTestUnitMode && initialTargetDirectory !== null) {
KotlinAwareMoveFilesOrDirectoriesModel( KotlinAwareMoveFilesOrDirectoriesModel(
project, project,
adjustedElementsToMove, adjustedElementsToMove,
@@ -70,7 +72,19 @@ class KotlinMoveFilesOrDirectoriesHandler : MoveFilesOrDirectoriesHandlerCompat(
moveCallback = callback moveCallback = callback
).run { ).run {
project.executeCommand(MoveHandler.REFACTORING_NAME) { project.executeCommand(MoveHandler.REFACTORING_NAME) {
computeModelResult().run() with(computeModelResult()) {
if (!isTestUnitMode) {
logFusForMoveRefactoring(
elementsCount,
entityToMove,
destination,
true,
Runnable { processor.run() }
)
} else {
processor.run()
}
}
} }
} }
return 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
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode 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.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.executeCommand
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
@@ -55,7 +56,9 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.File import java.io.File
import java.lang.System.currentTimeMillis
import java.util.* import java.util.*
import javax.swing.JCheckBox
sealed class ContainerInfo { sealed class ContainerInfo {
abstract val fqName: FqName? abstract val fqName: FqName?
@@ -680,3 +683,29 @@ internal fun getTargetPackageFqName(targetContainer: PsiElement): FqName? {
} }
return if (targetContainer is KtFile) targetContainer.packageFqName 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,
)
}
}