Extract Function: Show possible types for receiver in Extract Function/Introduce Lambda Parameter dialogs

#KT-7578 Fixed
This commit is contained in:
Alexey Sedunov
2015-05-22 14:15:07 +03:00
parent cb9b1019b2
commit 72205540d6
6 changed files with 78 additions and 14 deletions
@@ -28,6 +28,7 @@ import kotlin.Unit;
import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.JetFileType; import org.jetbrains.kotlin.idea.JetFileType;
import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester; import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester;
import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage; import org.jetbrains.kotlin.idea.core.refactoring.RefactoringPackage;
@@ -120,8 +121,10 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
protected void init() { protected void init() {
super.init(); super.init();
ExtractableCodeDescriptor extractableCodeDescriptor = originalDescriptor.getDescriptor();
functionNameField = new NameSuggestionsField( functionNameField = new NameSuggestionsField(
ArrayUtil.toStringArray(originalDescriptor.getDescriptor().getSuggestedNames()), ArrayUtil.toStringArray(extractableCodeDescriptor.getSuggestedNames()),
project, project,
JetFileType.INSTANCE JetFileType.INSTANCE
); );
@@ -139,7 +142,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
boolean enableVisibility = isVisibilitySectionAvailable(); boolean enableVisibility = isVisibilitySectionAvailable();
visibilityBox.setEnabled(enableVisibility); visibilityBox.setEnabled(enableVisibility);
if (enableVisibility) { if (enableVisibility) {
visibilityBox.setSelectedItem(originalDescriptor.getDescriptor().getVisibility()); visibilityBox.setSelectedItem(extractableCodeDescriptor.getVisibility());
} }
visibilityBox.addItemListener( visibilityBox.addItemListener(
new ItemListener() { new ItemListener() {
@@ -166,7 +169,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
doCancelAction(); doCancelAction();
} }
}; };
parameterTablePanel.init(originalDescriptor.getDescriptor().getParameters()); parameterTablePanel.init(extractableCodeDescriptor.getReceiverParameter(), extractableCodeDescriptor.getParameters());
inputParametersPanel.setText("&Parameters"); inputParametersPanel.setText("&Parameters");
inputParametersPanel.setLabelFor(parameterTablePanel.getTable()); inputParametersPanel.setLabelFor(parameterTablePanel.getTable());
@@ -213,6 +216,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
return createNewDescriptor(originalDescriptor.getDescriptor(), return createNewDescriptor(originalDescriptor.getDescriptor(),
getFunctionName(), getFunctionName(),
getVisibility(), getVisibility(),
parameterTablePanel.getReceiverInfo(),
parameterTablePanel.getParameterInfos()); parameterTablePanel.getParameterInfos());
} }
@@ -225,12 +229,20 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
@NotNull ExtractableCodeDescriptor originalDescriptor, @NotNull ExtractableCodeDescriptor originalDescriptor,
@NotNull String newName, @NotNull String newName,
@NotNull String newVisibility, @NotNull String newVisibility,
@Nullable KotlinParameterTablePanel.ParameterInfo newReceiverInfo,
@NotNull List<KotlinParameterTablePanel.ParameterInfo> newParameterInfos @NotNull List<KotlinParameterTablePanel.ParameterInfo> newParameterInfos
) { ) {
Map<Parameter, Parameter> oldToNewParameters = ContainerUtil.newLinkedHashMap(); Map<Parameter, Parameter> oldToNewParameters = ContainerUtil.newLinkedHashMap();
for (KotlinParameterTablePanel.ParameterInfo parameterInfo : newParameterInfos) { for (KotlinParameterTablePanel.ParameterInfo parameterInfo : newParameterInfos) {
oldToNewParameters.put(parameterInfo.getOriginalParameter(), parameterInfo.toParameter()); oldToNewParameters.put(parameterInfo.getOriginalParameter(), parameterInfo.toParameter());
} }
ArrayList<Parameter> newParameters = ContainerUtil.newArrayList(oldToNewParameters.values());
Parameter originalReceiver = originalDescriptor.getReceiverParameter();
Parameter newReceiver = newReceiverInfo != null ? newReceiverInfo.toParameter() : null;
if (originalReceiver != null && newReceiver != null) {
oldToNewParameters.put(originalReceiver, newReceiver);
}
ControlFlow controlFlow = originalDescriptor.getControlFlow(); ControlFlow controlFlow = originalDescriptor.getControlFlow();
List<OutputValue> outputValues = new ArrayList<OutputValue>(controlFlow.getOutputValues()); List<OutputValue> outputValues = new ArrayList<OutputValue>(controlFlow.getOutputValues());
@@ -267,8 +279,8 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
originalDescriptor.getOriginalContext(), originalDescriptor.getOriginalContext(),
Collections.singletonList(newName), Collections.singletonList(newName),
newVisibility, newVisibility,
ContainerUtil.newArrayList(oldToNewParameters.values()), newParameters,
originalDescriptor.getReceiverParameter(), newReceiver,
originalDescriptor.getTypeParameters(), originalDescriptor.getTypeParameters(),
replacementMap, replacementMap,
controlFlow controlFlow
@@ -43,18 +43,21 @@ import javax.swing.table.TableColumn;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class KotlinParameterTablePanel extends JPanel { public class KotlinParameterTablePanel extends JPanel {
public static class ParameterInfo { public static class ParameterInfo {
private final Parameter originalParameter; private final Parameter originalParameter;
private final boolean receiver;
private String name; private String name;
private JetType type; private JetType type;
private boolean enabled = true; private boolean enabled = true;
public ParameterInfo(Parameter originalParameter) { public ParameterInfo(Parameter originalParameter, boolean receiver) {
this.originalParameter = originalParameter; this.originalParameter = originalParameter;
this.name = originalParameter.getName(); this.receiver = receiver;
this.name = receiver ? "<receiver>" : originalParameter.getName();
this.type = originalParameter.getParameterType(false); this.type = originalParameter.getParameterType(false);
} }
@@ -62,6 +65,10 @@ public class KotlinParameterTablePanel extends JPanel {
return originalParameter; return originalParameter;
} }
public boolean isReceiver() {
return receiver;
}
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
} }
@@ -100,13 +107,14 @@ public class KotlinParameterTablePanel extends JPanel {
super(new BorderLayout()); super(new BorderLayout());
} }
public void init(List<Parameter> parameters) { public void init(@Nullable Parameter receiver, @NotNull List<Parameter> parameters) {
parameterInfos = KotlinPackage.map( parameterInfos = KotlinPackage.mapTo(
parameters, parameters,
receiver != null ? KotlinPackage.arrayListOf(new ParameterInfo(receiver, true)) : new ArrayList<ParameterInfo>(),
new Function1<Parameter, ParameterInfo>() { new Function1<Parameter, ParameterInfo>() {
@Override @Override
public ParameterInfo invoke(Parameter parameter) { public ParameterInfo invoke(Parameter parameter) {
return new ParameterInfo(parameter); return new ParameterInfo(parameter, false);
} }
} }
); );
@@ -358,7 +366,7 @@ public class KotlinParameterTablePanel extends JPanel {
case CHECKMARK_COLUMN: case CHECKMARK_COLUMN:
return isEnabled(); return isEnabled();
case PARAMETER_NAME_COLUMN: case PARAMETER_NAME_COLUMN:
return isEnabled() && info.isEnabled(); return isEnabled() && info.isEnabled() && !info.isReceiver();
case PARAMETER_TYPE_COLUMN: case PARAMETER_TYPE_COLUMN:
return isEnabled() && info.isEnabled() && info.getOriginalParameter().getParameterTypeCandidates(false).size() > 1; return isEnabled() && info.isEnabled() && info.getOriginalParameter().getParameterTypeCandidates(false).size() > 1;
default: default:
@@ -376,13 +384,27 @@ public class KotlinParameterTablePanel extends JPanel {
} }
} }
@Nullable
public ParameterInfo getReceiverInfo() {
return KotlinPackage.singleOrNull(
parameterInfos,
new Function1<ParameterInfo, Boolean>() {
@Override
public Boolean invoke(ParameterInfo info) {
return info.isEnabled() && info.isReceiver();
}
}
);
}
@NotNull
public List<ParameterInfo> getParameterInfos() { public List<ParameterInfo> getParameterInfos() {
return KotlinPackage.filter( return KotlinPackage.filter(
parameterInfos, parameterInfos,
new Function1<ParameterInfo, Boolean>() { new Function1<ParameterInfo, Boolean>() {
@Override @Override
public Boolean invoke(ParameterInfo info) { public Boolean invoke(ParameterInfo info) {
return info.isEnabled(); return info.isEnabled() && !info.isReceiver();
} }
} }
); );
@@ -150,7 +150,8 @@ public class KotlinIntroduceParameterDialog private (
gbConstraints.fill = GridBagConstraints.BOTH gbConstraints.fill = GridBagConstraints.BOTH
panel.add(typeField, gbConstraints) panel.add(typeField, gbConstraints)
if (lambdaExtractionDescriptor != null && lambdaExtractionDescriptor.parameters.isNotEmpty()) { if (lambdaExtractionDescriptor != null
&& (lambdaExtractionDescriptor.parameters.isNotEmpty() || lambdaExtractionDescriptor.receiverParameter != null)) {
val parameterTablePanel = object : KotlinParameterTablePanel() { val parameterTablePanel = object : KotlinParameterTablePanel() {
override fun onEnterAction() { override fun onEnterAction() {
doOKAction() doOKAction()
@@ -160,7 +161,7 @@ public class KotlinIntroduceParameterDialog private (
doCancelAction() doCancelAction()
} }
} }
parameterTablePanel.init(lambdaExtractionDescriptor!!.parameters) parameterTablePanel.init(lambdaExtractionDescriptor!!.receiverParameter, lambdaExtractionDescriptor.parameters)
gbConstraints.insets = Insets(4, 4, 4, 8) gbConstraints.insets = Insets(4, 4, 4, 8)
gbConstraints.gridwidth = 1 gbConstraints.gridwidth = 1
@@ -273,6 +274,7 @@ public class KotlinIntroduceParameterDialog private (
oldDescriptor, oldDescriptor,
chosenName, chosenName,
"", "",
parameterTablePanel?.getReceiverInfo(),
parameterTablePanel?.getParameterInfos() ?: listOf() parameterTablePanel?.getParameterInfos() ?: listOf()
) )
val options = ExtractionGeneratorOptions.DEFAULT.copy( val options = ExtractionGeneratorOptions.DEFAULT.copy(
@@ -0,0 +1,9 @@
// PARAM_DESCRIPTOR: internal fun Bar.foo(): kotlin.Unit defined in root package
// PARAM_TYPES: Bar, Foo, kotlin.Any
open class Foo
class Bar : Foo()
fun Bar.foo() {
<selection>toString()</selection>
}
@@ -0,0 +1,13 @@
// PARAM_DESCRIPTOR: internal fun Bar.foo(): kotlin.Unit defined in root package
// PARAM_TYPES: Bar, Foo, kotlin.Any
open class Foo
class Bar : Foo()
fun Bar.foo() {
__dummyTestFun__()
}
private fun Bar.__dummyTestFun__() {
toString()
}
@@ -1571,6 +1571,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
doExtractFunctionTest(fileName); doExtractFunctionTest(fileName);
} }
@TestMetadata("receiverCandidateTypes.kt")
public void testReceiverCandidateTypes() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/receiverCandidateTypes.kt");
doExtractFunctionTest(fileName);
}
@TestMetadata("typeHierarchy1.kt") @TestMetadata("typeHierarchy1.kt")
public void testTypeHierarchy1() throws Exception { public void testTypeHierarchy1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/candidateTypes/typeHierarchy1.kt");