diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.form b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.form
new file mode 100644
index 00000000000..eec0486252c
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.form
@@ -0,0 +1,88 @@
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.java
new file mode 100644
index 00000000000..7d1057456f4
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.java
@@ -0,0 +1,299 @@
+/*
+ * 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.refactoring.move.moveMethod;
+
+import com.intellij.ide.util.TreeClassChooser;
+import com.intellij.ide.util.TreeJavaClassChooserDialog;
+import com.intellij.openapi.ui.VerticalFlowLayout;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.refactoring.ui.RefactoringDialog;
+import com.intellij.ui.EditorTextField;
+import com.intellij.ui.ScrollPaneFactory;
+import com.intellij.ui.TitledSeparator;
+import com.intellij.ui.components.JBList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.asJava.LightClassUtilsKt;
+import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration;
+import org.jetbrains.kotlin.idea.KotlinBundle;
+import org.jetbrains.kotlin.idea.KotlinFileType;
+import org.jetbrains.kotlin.idea.KotlinIconProvider;
+import org.jetbrains.kotlin.idea.completion.CompletionUtilsKt;
+import org.jetbrains.kotlin.idea.core.KotlinNameSuggester;
+import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator;
+import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject;
+import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject;
+import org.jetbrains.kotlin.idea.projectView.KtClassOrObjectTreeNode;
+import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtilKt;
+import org.jetbrains.kotlin.idea.refactoring.ui.KotlinTypeReferenceEditorComboWithBrowseButton;
+import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
+import org.jetbrains.kotlin.psi.*;
+import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
+import org.jetbrains.kotlin.renderer.DescriptorRenderer;
+import org.jetbrains.kotlin.types.KotlinType;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import java.awt.*;
+import java.util.List;
+import java.util.*;
+
+import static org.jetbrains.kotlin.name.Name.isValidIdentifier;
+
+public class MoveKotlinMethodDialog extends RefactoringDialog {
+ private static final String RECENTS_KEY = MoveKotlinMethodDialog.class.getName() + ".RECENTS_KEY";
+ private final KtNamedFunction method;
+ private final Map variableToClassMap;
+ private final KtNamedDeclaration[] variables;
+ private final Map> thisClassesToMembers;
+ private final KtClassOrObject targetContainer;
+ private final Map oldClassParameterNameFields;
+ private KtNamedDeclaration selectedTarget;
+ private JPanel mainPanel;
+ private JRadioButton toClassRadioButton;
+ private JRadioButton toObjectRadioButton;
+ private JPanel targetObjectChooserPanel;
+ private KotlinTypeReferenceEditorComboWithBrowseButton targetObjectChooser;
+ private JList targetVariableList;
+ private JPanel targetVariableListPanel;
+ private JPanel parametersPanel;
+ private JCheckBox openInEditorCheckBox;
+
+ public MoveKotlinMethodDialog(
+ @NotNull KtNamedFunction method,
+ @NotNull Map variableToClassMap,
+ @Nullable KtClassOrObject targetContainer
+ ) {
+ super(method.getProject(), true);
+
+ this.method = method;
+ this.variableToClassMap = variableToClassMap;
+ this.targetContainer = targetContainer;
+ this.thisClassesToMembers = MoveKotlinMethodProcessorKt.getThisClassesToMembers(method);
+ this.variables = variableToClassMap.keySet().toArray(new KtNamedDeclaration[0]);
+ this.oldClassParameterNameFields = new HashMap<>();
+
+ init();
+ setTitle(KotlinBundle.message("title.move.method"));
+ initTargetObjectChooser();
+ initTargetVariableList();
+ initParametersPanel();
+ initButtons();
+ }
+
+ @Override
+ protected void doAction() {
+ if (toClassRadioButton.isSelected()) selectedTarget = targetVariableList.getSelectedValue();
+ if (toObjectRadioButton.isSelected() && selectedTarget == null) {
+ setErrorText(KotlinBundle.message("text.no.destination.object.specified"));
+ return;
+ }
+
+ Map oldClassParameterNames = new LinkedHashMap<>();
+ for (Map.Entry entry : oldClassParameterNameFields.entrySet()) {
+ EditorTextField field = entry.getValue();
+ if (!isValidIdentifier(field.getText())) {
+ setErrorText(KotlinBundle.message("parameter.name.is.invalid", field.getText()));
+ return;
+ }
+ if (field.isEnabled()) {
+ oldClassParameterNames.put(entry.getKey(), field.getText());
+ }
+ }
+
+ MoveKotlinMethodProcessor processor =
+ new MoveKotlinMethodProcessor(method, selectedTarget, oldClassParameterNames, openInEditorCheckBox.isSelected());
+ invokeRefactoring(processor);
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ return mainPanel;
+ }
+
+ private void initButtons() {
+ toClassRadioButton.addActionListener(e -> enableTargetChooser());
+ toObjectRadioButton.addActionListener(e -> enableTargetChooser());
+
+ if (variables.length != 0 && !(targetContainer instanceof KtObjectDeclaration)) {
+ toClassRadioButton.setSelected(true);
+ }
+ else {
+ toObjectRadioButton.setSelected(true);
+ if (variables.length == 0) {
+ toClassRadioButton.setEnabled(false);
+ }
+ }
+
+ enableTextFields();
+ enableTargetChooser();
+ }
+
+ private void initTargetVariableList() {
+ AbstractListModel listModel = new AbstractListModel() {
+ @Override
+ public int getSize() {
+ return variables.length;
+ }
+
+ @Override
+ public KtNamedDeclaration getElementAt(int index) {
+ return variables[index];
+ }
+ };
+ targetVariableList = new JBList<>(listModel);
+ DefaultListCellRenderer listCellRenderer = new DefaultListCellRenderer() {
+ private final DescriptorRenderer renderer = IdeDescriptorRenderers.SOURCE_CODE_TYPES_WITH_SHORT_NAMES;
+
+ @Override
+ public Component getListCellRendererComponent(
+ JList> list,
+ Object value,
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus
+ ) {
+ super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+ if (value instanceof KtNamedDeclaration) {
+ KtNamedDeclaration variable = (KtNamedDeclaration) value;
+ setIcon(KotlinIconProvider.Companion.getBaseIcon(variable));
+ setText(variable.getName());
+ KotlinType type = MoveKotlinMethodProcessorKt.type(variable);
+ if (type != null) {
+ setText(getText() + ": " + renderer.renderType(type));
+ }
+ }
+ return this;
+ }
+ };
+
+ targetVariableList.setCellRenderer(listCellRenderer);
+ targetVariableList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ int defaultVariableIndex = -1;
+ for (int i = 0; i < variables.length; i++) {
+ if (variableToClassMap.get(variables[i]) == targetContainer) {
+ defaultVariableIndex = i;
+ }
+ }
+ targetVariableList.setSelectedIndex(defaultVariableIndex != -1 ? defaultVariableIndex : 0);
+ targetVariableList.getSelectionModel().addListSelectionListener(e -> enableTextFields());
+
+ JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(targetVariableList);
+ targetVariableListPanel.add(scrollPane);
+ }
+
+ private void initTargetObjectChooser() {
+ targetObjectChooser = new KotlinTypeReferenceEditorComboWithBrowseButton(
+ e -> {
+ TreeClassChooser chooser = createTreeClassChooser();
+ chooser.selectDirectory(method.getContainingFile().getContainingDirectory());
+ chooser.showDialog();
+ PsiClass psiClass = chooser.getSelected();
+ if (psiClass instanceof KtLightClassForSourceDeclaration) {
+ selectedTarget = ((KtLightClassForSourceDeclaration) psiClass).getKotlinOrigin();
+ targetObjectChooser.setText(Objects.requireNonNull(psiClass.getQualifiedName()));
+ }
+ },
+ (targetContainer == null || targetContainer.getFqName() == null) ? null : targetContainer.getFqName().asString(),
+ targetContainer == null ? Objects.requireNonNull(KtPsiUtilKt.getContainingClassOrObject(method)) : targetContainer,
+ RECENTS_KEY
+ );
+ KtTypeCodeFragment codeFragment = targetObjectChooser.getCodeFragment();
+ if (codeFragment != null) {
+ CompletionUtilsKt.setExtraCompletionFilter(
+ codeFragment,
+ lookupElement -> {
+ Object lookupObject = lookupElement.getObject();
+ if (!(lookupObject instanceof DeclarationLookupObject)) return false;
+ PsiElement psiElement = ((DeclarationLookupObject) lookupObject).getPsiElement();
+ if (lookupObject instanceof PackageLookupObject) return true;
+ return (psiElement instanceof KtObjectDeclaration) && KotlinRefactoringUtilKt.canRefactor(psiElement);
+ }
+ );
+ }
+ targetObjectChooserPanel.add(targetObjectChooser);
+ }
+
+ private void enableTextFields() {
+ for (EditorTextField textField : oldClassParameterNameFields.values()) {
+ textField.setEnabled(true);
+ }
+ if (toClassRadioButton.isSelected()) {
+ KtNamedDeclaration variable = variables[targetVariableList.getSelectedIndex()];
+ KtClassOrObject containingClass = KtPsiUtilKt.getContainingClassOrObject(variable);
+ if (!(containingClass instanceof KtClass)) return;
+ if (!(variable instanceof KtParameter) || ((KtParameter) variable).hasValOrVar()) {
+ Set members = thisClassesToMembers.get(containingClass);
+ if (members != null && members.size() == 1 && members.contains(variable)) {
+ EditorTextField field = oldClassParameterNameFields.get(containingClass);
+ if (field != null) field.setEnabled(false);
+ }
+ }
+ }
+ }
+
+ private void enableTargetChooser() {
+ if (toClassRadioButton.isSelected()) {
+ targetVariableList.setEnabled(true);
+ targetObjectChooser.setEnabled(false);
+ }
+ else {
+ targetVariableList.setEnabled(false);
+ targetObjectChooser.setEnabled(true);
+ }
+ enableTextFields();
+ }
+
+ private void initParametersPanel() {
+ if (thisClassesToMembers.isEmpty()) return;
+ parametersPanel.setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, true));
+ NewDeclarationNameValidator validator =
+ new NewDeclarationNameValidator((PsiElement) method, null, NewDeclarationNameValidator.Target.VARIABLES, new ArrayList<>());
+
+ for (KtClass ktClass : thisClassesToMembers.keySet()) {
+ KotlinType type = MoveKotlinMethodProcessorKt.defaultType(ktClass);
+ if (type == null) continue;
+ String text = KotlinBundle.message("text.select.a.name.for.this.parameter", ktClass.getName());
+ parametersPanel.add(new TitledSeparator(text, null));
+ List suggestedNames = KotlinNameSuggester.INSTANCE.suggestNamesByType(type, validator, null);
+ String suggestedName = suggestedNames.isEmpty() ? "parameter" : suggestedNames.get(0);
+ EditorTextField field = new EditorTextField(suggestedName, myProject, KotlinFileType.INSTANCE);
+ oldClassParameterNameFields.put(ktClass, field);
+ parametersPanel.add(field);
+ }
+ }
+
+ private TreeJavaClassChooserDialog createTreeClassChooser() {
+ return new TreeJavaClassChooserDialog(
+ KotlinBundle.message("title.choose.destination.object"),
+ myProject,
+ GlobalSearchScope.projectScope(myProject),
+ aClass -> {
+ if (!(aClass instanceof KtLightClassForSourceDeclaration)) return false;
+ KtClassOrObject ktClassOrObject = ((KtLightClassForSourceDeclaration) aClass).getKotlinOrigin();
+ return ktClassOrObject instanceof KtObjectDeclaration && !((KtObjectDeclaration) ktClassOrObject).isObjectLiteral();
+ },
+ null,
+ null,
+ true
+ ) {
+ @Nullable
+ @Override
+ protected PsiClass getSelectedFromTreeUserObject(DefaultMutableTreeNode node) {
+ PsiClass psiClass = super.getSelectedFromTreeUserObject(node);
+ if (psiClass != null) return psiClass;
+ Object userObject = node.getUserObject();
+ if (!(userObject instanceof KtClassOrObjectTreeNode)) return null;
+ return LightClassUtilsKt.toLightClass(((KtClassOrObjectTreeNode) userObject).getValue());
+ }
+ };
+ }
+}
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.kt
deleted file mode 100644
index af34d7f14fa..00000000000
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodDialog.kt
+++ /dev/null
@@ -1,290 +0,0 @@
-package org.jetbrains.kotlin.idea.refactoring.move.moveMethod
-
-import com.intellij.codeInsight.lookup.LookupElement
-import com.intellij.ide.util.TreeClassChooser
-import com.intellij.ide.util.TreeJavaClassChooserDialog
-import com.intellij.openapi.ui.VerticalFlowLayout
-import com.intellij.psi.PsiClass
-import com.intellij.psi.search.GlobalSearchScope
-import com.intellij.refactoring.ui.RefactoringDialog
-import com.intellij.ui.EditorTextField
-import com.intellij.ui.ScrollPaneFactory
-import com.intellij.ui.TitledSeparator
-import com.intellij.ui.components.JBList
-import com.intellij.util.ui.JBUI
-import com.jetbrains.rd.util.firstOrNull
-import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
-import org.jetbrains.kotlin.asJava.toLightClass
-import org.jetbrains.kotlin.descriptors.CallableDescriptor
-import org.jetbrains.kotlin.idea.KotlinBundle
-import org.jetbrains.kotlin.idea.KotlinFileType
-import org.jetbrains.kotlin.idea.KotlinIconProvider.Companion.getBaseIcon
-import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
-import org.jetbrains.kotlin.idea.completion.extraCompletionFilter
-import org.jetbrains.kotlin.idea.core.KotlinNameSuggester.suggestNamesByType
-import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
-import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
-import org.jetbrains.kotlin.idea.core.completion.PackageLookupObject
-import org.jetbrains.kotlin.idea.projectView.KtClassOrObjectTreeNode
-import org.jetbrains.kotlin.idea.refactoring.canRefactor
-import org.jetbrains.kotlin.idea.refactoring.ui.KotlinTypeReferenceEditorComboWithBrowseButton
-import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
-import org.jetbrains.kotlin.name.Name.isValidIdentifier
-import org.jetbrains.kotlin.psi.*
-import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
-import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
-import java.awt.Component
-import java.awt.Dimension
-import java.awt.GridBagConstraints
-import java.awt.GridBagLayout
-import java.awt.event.ActionListener
-import javax.swing.*
-import javax.swing.tree.DefaultMutableTreeNode
-
-
-class MoveKotlinMethodDialog(
- private val method: KtNamedFunction,
- private val variableToClassMap: Map,
- private val targetContainer: KtClassOrObject?
-) : RefactoringDialog(method.project, true) {
- private val variables = variableToClassMap.keys.toList()
- private val targetVariableList = createTargetVariableChooser()
- private val thisClassesToMembers = getThisClassesToMembers(method)
- private val oldClassParameterNameFields = LinkedHashMap()
- private val targetObjectChooser = createTargetObjectChooser()
- private val toClassRadioButton = JRadioButton(KotlinBundle.message("label.text.to.class"))
- private val toObjectRadioButton = JRadioButton(KotlinBundle.message("label.text.to.object"))
- private var selectedTarget: KtNamedDeclaration? = null
- private val openInEditorCheckBox = JCheckBox(KotlinBundle.message("open.moved.method.in.editor"), true)
-
- init {
- super.init()
- title = KotlinBundle.message("title.move.method")
- }
-
- override fun doAction() {
- if (toClassRadioButton.isSelected) selectedTarget = targetVariableList.selectedValue
-
- if (toObjectRadioButton.isSelected && selectedTarget == null) {
- setErrorText(KotlinBundle.message("text.no.destination.object.specified"))
- return
- }
-
- val oldClassParameterNames = LinkedHashMap()
- for ((ktClass, field) in oldClassParameterNameFields) {
- if (!isValidIdentifier(field.text)) {
- setErrorText(KotlinBundle.message("parameter.name.is.invalid", field.text))
- return
- }
- if (field.isEnabled) {
- oldClassParameterNames[ktClass] = field.text
- }
- }
-
- val processor = MoveKotlinMethodProcessor(method, selectedTarget!!, oldClassParameterNames, openInEditorCheckBox.isSelected)
- invokeRefactoring(processor)
- }
-
- override fun createCenterPanel(): JComponent? {
- val mainPanel = JPanel(GridBagLayout())
- val buttonGroup = ButtonGroup()
-
- toClassRadioButton.addActionListener { enableTargetChooser() }
- toObjectRadioButton.addActionListener { enableTargetChooser() }
- buttonGroup.add(toClassRadioButton)
- buttonGroup.add(toObjectRadioButton)
-
- targetVariableList.addListSelectionListener { enableTextFields() }
- val scrollPane = ScrollPaneFactory.createScrollPane(targetVariableList)
- mainPanel.add(
- scrollPane, GridBagConstraints(
- 1, 0, 1, 1, 1.0, 1.0,
- GridBagConstraints.WEST, GridBagConstraints.BOTH, JBUI.emptyInsets(), 0, 0
- )
- )
-
- mainPanel.add(
- targetObjectChooser, GridBagConstraints(
- 1, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0,
- GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, JBUI.emptyInsets(), 0, 0
- )
- )
- mainPanel.add(
- toClassRadioButton, GridBagConstraints(
- 0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0,
- GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, JBUI.emptyInsets(), 0, 0
- )
- )
- mainPanel.add(
- toObjectRadioButton, GridBagConstraints(
- 0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0,
- GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, JBUI.emptyInsets(), 0, 0
- )
- )
-
- val parametersPanel: JPanel? = createParametersPanel()
- if (parametersPanel != null) {
- mainPanel.add(
- parametersPanel, GridBagConstraints(
- 0, GridBagConstraints.RELATIVE, 2, 1, 1.0, 0.0,
- GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, JBUI.emptyInsets(), 0, 0
- )
- )
- }
- mainPanel.add(
- openInEditorCheckBox, GridBagConstraints(
- 0, GridBagConstraints.RELATIVE, 2, 1, 0.0, 0.0,
- GridBagConstraints.WEST, GridBagConstraints.NONE, JBUI.emptyInsets(), 0, 0
- )
- )
-
- if (variables.isNotEmpty() && targetContainer !is KtObjectDeclaration) {
- toClassRadioButton.isSelected = true
- } else {
- toObjectRadioButton.isSelected = true
- if (variables.isEmpty()) {
- toClassRadioButton.isEnabled = false
- }
- }
-
- enableTextFields()
- enableTargetChooser()
- updateOnChanged(targetVariableList)
- return mainPanel
- }
-
- private fun createTargetVariableChooser(): JList {
- val listModel = object : AbstractListModel() {
- override fun getElementAt(index: Int): KtNamedDeclaration = variables[index]
- override fun getSize(): Int = variables.size
- }
- val list = JBList(listModel)
- val listCellRenderer = object : DefaultListCellRenderer() {
- private val renderer = IdeDescriptorRenderers.SOURCE_CODE_TYPES.withOptions {
- classifierNamePolicy = ClassifierNamePolicy.SHORT
- }
-
- override fun getListCellRendererComponent(
- list: JList<*>?, value: Any?, index: Int, isSelected: Boolean, cellHasFocus: Boolean
- ): Component {
- super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus)
- if (value is KtNamedDeclaration) {
- icon = value.getBaseIcon()
- text = value.nameAsSafeName.identifier
- (value.resolveToDescriptorIfAny() as? CallableDescriptor)?.returnType?.let { type ->
- text = "$text: ${renderer.renderType(type)}"
- }
- }
- return this
- }
- }
-
- list.cellRenderer = listCellRenderer
- list.selectionMode = ListSelectionModel.SINGLE_SELECTION
- val defaultVariableIndex = variables.indexOf(variableToClassMap.filter { it.value == targetContainer }.firstOrNull()?.key)
- list.selectedIndex = if (defaultVariableIndex != -1) defaultVariableIndex else 0
- list.selectionModel.addListSelectionListener { updateOnChanged(list) }
- return list
- }
-
- private fun createTargetObjectChooser(): KotlinTypeReferenceEditorComboWithBrowseButton {
- val targetObjectChooser = KotlinTypeReferenceEditorComboWithBrowseButton(
- ActionListener {
- val chooser: TreeClassChooser = object : TreeJavaClassChooserDialog(
- KotlinBundle.message("title.choose.destination.object"),
- project,
- GlobalSearchScope.projectScope(project),
- { psiClass ->
- if (psiClass !is KtLightClassForSourceDeclaration) {
- false
- } else {
- val ktClassOrObject = psiClass.kotlinOrigin
- ktClassOrObject is KtObjectDeclaration && !ktClassOrObject.isObjectLiteral()
- }
- },
- null,
- null,
- true
- ) {
- override fun getSelectedFromTreeUserObject(node: DefaultMutableTreeNode): PsiClass? {
- val psiClass = super.getSelectedFromTreeUserObject(node)
- if (psiClass != null) return psiClass
- val userObject = node.userObject
- return if (userObject !is KtClassOrObjectTreeNode) null else userObject.value.toLightClass()
- }
- }
- chooser.selectDirectory(method.containingFile.containingDirectory)
- chooser.showDialog()
- val psiClass = chooser.selected
- if (psiClass is KtLightClassForSourceDeclaration) {
- selectedTarget = psiClass.kotlinOrigin
- targetObjectChooser.text = psiClass.kotlinOrigin.fqName.toString()
- }
- },
- (targetContainer ?: method.containingClassOrObject as? KtObjectDeclaration)?.fqName?.asString(),
- targetContainer ?: method.containingClassOrObject!!,
- RECENTS_KEY
- )
- targetObjectChooser.codeFragment?.let { codeFragment ->
- codeFragment.extraCompletionFilter = { lookupElement: LookupElement ->
- val lookupObject = lookupElement.getObject() as? DeclarationLookupObject
- val psiElement = lookupObject?.psiElement
- lookupObject is PackageLookupObject || psiElement is KtObjectDeclaration && psiElement.canRefactor()
- }
- }
- return targetObjectChooser
- }
-
- private fun updateOnChanged(list: JList<*>) {
- okAction.isEnabled = !list.selectionModel.isSelectionEmpty
- }
-
- private fun enableTextFields() {
- for (textField in oldClassParameterNameFields.values) {
- textField.isEnabled = true
- }
- if (toClassRadioButton.isSelected) {
- val variable = variables[targetVariableList.selectedIndex]
- val containingClass = variable.containingClassOrObject as? KtClass ?: return
- if (variable !is KtParameter || variable.hasValOrVar()) {
- if (thisClassesToMembers[containingClass]?.size == 1
- && thisClassesToMembers[containingClass]?.contains(variable) == true
- ) {
- oldClassParameterNameFields[containingClass]?.isEnabled = false
- }
- }
- }
- }
-
- private fun enableTargetChooser() {
- if (toClassRadioButton.isSelected) {
- targetVariableList.isEnabled = true
- targetObjectChooser.isEnabled = false
- } else {
- targetVariableList.isEnabled = false
- targetObjectChooser.isEnabled = true
- }
- enableTextFields()
- }
-
- private fun createParametersPanel(): JPanel? {
- if (thisClassesToMembers.isEmpty()) return null
- val panel = JPanel(VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, true))
- val validator = NewDeclarationNameValidator(method, null, NewDeclarationNameValidator.Target.VARIABLES)
- for (ktClass in thisClassesToMembers.keys) {
- val text = KotlinBundle.message("text.select.a.name.for.this.parameter", ktClass.nameAsSafeName.identifier)
- panel.add(TitledSeparator(text, null))
- val suggestedName = suggestNamesByType(ktClass.resolveToDescriptorIfAny()!!.defaultType, validator).firstOrNull() ?: "parameter"
- val field = EditorTextField(suggestedName, project, KotlinFileType.INSTANCE)
- field.minimumSize = Dimension(field.preferredSize)
- oldClassParameterNameFields[ktClass] = field
- panel.add(field)
- }
- panel.border = BorderFactory.createEmptyBorder(5, 0, 5, 0)
- return panel
- }
-
- companion object {
- val RECENTS_KEY = "${MoveKotlinMethodDialog::class.java.name}.RECENTS_KEY"
- }
-}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodHandler.kt
index 903e04be004..3224d3bd950 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodHandler.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodHandler.kt
@@ -9,9 +9,7 @@ import com.intellij.psi.PsiReference
import com.intellij.refactoring.move.MoveCallback
import com.intellij.refactoring.move.MoveHandlerDelegate
import com.intellij.refactoring.util.CommonRefactoringUtil
-import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle
-import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.lexer.KtTokens
@@ -22,27 +20,38 @@ import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
class MoveKotlinMethodHandler : MoveHandlerDelegate() {
private fun showErrorHint(project: Project, dataContext: DataContext?, message: String) {
- val editor = if (dataContext == null) null else CommonDataKeys.EDITOR.getData(dataContext)
+ val editor = dataContext?.let { CommonDataKeys.EDITOR.getData(it) }
CommonRefactoringUtil.showErrorHint(project, editor, message, KotlinBundle.message("text.move.method"), null)
}
private fun invokeMoveMethodRefactoring(
- project: Project, method: KtNamedFunction, targetContainer: KtClassOrObject?, dataContext: DataContext?
+ project: Project,
+ method: KtNamedFunction,
+ targetContainer: KtClassOrObject?,
+ dataContext: DataContext?
) {
- var message: String? = null
if (method.containingClassOrObject == null) return
- if (!method.manager.isInProject(method)) {
- message = KotlinBundle.message("text.move.method.is.not.supported.for.non.project.methods")
- } else if (method.mentionsTypeParameters()) {
- message = KotlinBundle.message("text.move.method.is.not.supported.for.generic.classes")
- } else if (method.hasModifier(KtTokens.OVERRIDE_KEYWORD) || method.hasModifier(KtTokens.OPEN_KEYWORD)) {
- message = KotlinBundle.message("text.move.method.is.not.supported.when.method.is.a.part.of.inheritance.hierarchy")
+
+ val errorMessageKey = when {
+ !method.manager.isInProject(method) ->
+ "text.move.method.is.not.supported.for.non.project.methods"
+ method.mentionsTypeParameters() ->
+ "text.move.method.is.not.supported.for.generic.classes"
+ method.hasModifier(KtTokens.OVERRIDE_KEYWORD) || method.hasModifier(KtTokens.OPEN_KEYWORD) ->
+ "text.move.method.is.not.supported.when.method.is.a.part.of.inheritance.hierarchy"
+ else -> null
}
- message?.let {
- showErrorHint(project, dataContext, message)
+
+ if (errorMessageKey != null) {
+ showErrorHint(project, dataContext, KotlinBundle.message(errorMessageKey))
return
}
- MoveKotlinMethodDialog(method, collectSuitableVariables(method), targetContainer).show()
+
+ MoveKotlinMethodDialog(
+ method,
+ collectSuitableVariables(method),
+ targetContainer
+ ).show()
}
private fun collectSuitableVariables(method: KtNamedFunction): Map {
@@ -55,7 +64,7 @@ class MoveKotlinMethodHandler : MoveHandlerDelegate() {
val variableToClassMap = LinkedHashMap()
for (variable in allVariables) {
- (variable.resolveToDescriptorIfAny() as? CallableDescriptor)?.returnType?.let { type ->
+ variable.type()?.let { type ->
if (type.arguments.isEmpty()) {
val ktClass = type.constructor.declarationDescriptor?.findPsi() as? KtClass
if (ktClass != null && method.manager.isInProject(ktClass)) {
@@ -108,10 +117,7 @@ class MoveKotlinMethodHandler : MoveHandlerDelegate() {
typeParameters.addAll(ktClassOrObject.typeParameters)
ktClassOrObject = if (ktClassOrObject.hasModifier(KtTokens.INNER_KEYWORD)) ktClassOrObject.containingClassOrObject else null
}
- collectDescendantsOfType().forEach { userType ->
- if (userType.referenceExpression?.mainReference?.resolve() in typeParameters) return true
- }
- return false
+ return collectDescendantsOfType().any { userType -> userType.referenceExpression?.mainReference?.resolve() in typeParameters }
}
override fun getActionName(elements: Array): String = "${KotlinBundle.message("text.move.method")}.."
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodProcessor.kt
index 448153338a6..8cb55f35c5a 100644
--- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodProcessor.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveMethod/MoveKotlinMethodProcessor.kt
@@ -283,12 +283,16 @@ class MoveKotlinMethodProcessor(
internal fun getThisClassesToMembers(method: KtNamedFunction) = traverseOuterInstanceReferences(method)
+internal fun KtNamedDeclaration.type() = (resolveToDescriptorIfAny() as? CallableDescriptor)?.returnType
+
+internal fun KtClass.defaultType() = resolveToDescriptorIfAny()?.defaultType
+
private fun traverseOuterInstanceReferences(
method: KtNamedFunction,
body: (SourceInstanceReferenceUsageInfo) -> Unit = {}
-): LinkedHashMap> {
+): Map> {
val context = method.analyzeWithContent()
- val containingClassOrObject = method.containingClassOrObject ?: return LinkedHashMap()
+ val containingClassOrObject = method.containingClassOrObject ?: return emptyMap()
val descriptor = containingClassOrObject.unsafeResolveToDescriptor()
fun getClassOrObjectAndMemberReferencedBy(reference: KtExpression): Pair {
@@ -311,7 +315,7 @@ private fun traverseOuterInstanceReferences(
return classOrObjectDescriptor to memberDescriptor
}
- val thisClassesToMembers = LinkedHashMap>()
+ val thisClassesToMembers = mutableMapOf>()
method.bodyExpression?.forEachDescendantOfType { reference ->
val (classOrObjectDescriptor, memberDescriptor) = getClassOrObjectAndMemberReferencedBy(reference)
(classOrObjectDescriptor?.findPsi() as? KtClassOrObject)?.let { resolvedClassOrObject ->