Extraction Engine: Suggest function names based on the name of the result variable (if applicable)
#KT-6291 Fixed
This commit is contained in:
+1
-1
@@ -103,7 +103,7 @@ fun getFunctionForExtractedFragment(
|
||||
|
||||
val config = ExtractionGeneratorConfiguration(
|
||||
validationResult.descriptor,
|
||||
ExtractionGeneratorOptions(inTempFile = true, flexibleTypesAllowed = true)
|
||||
ExtractionGeneratorOptions(inTempFile = true, flexibleTypesAllowed = true, allowDummyName = true)
|
||||
)
|
||||
return config.generateDeclaration()
|
||||
}
|
||||
|
||||
+4
-2
@@ -99,14 +99,16 @@
|
||||
<visible value="true"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="bee3c" class="com.intellij.ui.EditorTextField" binding="functionNameField">
|
||||
<grid id="d0f58" binding="functionNamePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<component id="71ee7" class="javax.swing.JComboBox" binding="visibilityBox">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false">
|
||||
|
||||
+17
-11
@@ -16,19 +16,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.introduce.extractFunction.ui;
|
||||
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.ui.EditorTextField;
|
||||
import com.intellij.refactoring.ui.NameSuggestionsField;
|
||||
import com.intellij.ui.TitledSeparator;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import kotlin.Function0;
|
||||
import kotlin.Function1;
|
||||
import kotlin.Unit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.idea.JetFileType;
|
||||
import org.jetbrains.kotlin.idea.refactoring.JetNameSuggester;
|
||||
import org.jetbrains.kotlin.idea.refactoring.JetRefactoringBundle;
|
||||
import org.jetbrains.kotlin.idea.refactoring.RefactoringPackage;
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*;
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
@@ -48,7 +49,8 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
private TitledSeparator inputParametersPanel;
|
||||
private JComboBox visibilityBox;
|
||||
private KotlinFunctionSignatureComponent signaturePreviewField;
|
||||
private EditorTextField functionNameField;
|
||||
private JPanel functionNamePanel;
|
||||
private NameSuggestionsField functionNameField;
|
||||
private JLabel functionNameLabel;
|
||||
private KotlinParameterTablePanel parameterTablePanel;
|
||||
|
||||
@@ -85,7 +87,7 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
}
|
||||
|
||||
private String getFunctionName() {
|
||||
return functionNameField.getText();
|
||||
return functionNameField.getEnteredName();
|
||||
}
|
||||
|
||||
private String getVisibility() {
|
||||
@@ -118,17 +120,21 @@ public class KotlinExtractFunctionDialog extends DialogWrapper {
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
functionNameLabel.setLabelFor(functionNameField);
|
||||
|
||||
functionNameField.setText(originalDescriptor.getDescriptor().getName());
|
||||
functionNameField.addDocumentListener(
|
||||
new DocumentAdapter() {
|
||||
functionNameField = new NameSuggestionsField(
|
||||
ArrayUtil.toStringArray(originalDescriptor.getDescriptor().getSuggestedNames()),
|
||||
project,
|
||||
JetFileType.INSTANCE
|
||||
);
|
||||
functionNameField.addDataChangedListener(
|
||||
new NameSuggestionsField.DataChanged() {
|
||||
@Override
|
||||
public void documentChanged(DocumentEvent event) {
|
||||
public void dataChanged() {
|
||||
update();
|
||||
}
|
||||
}
|
||||
);
|
||||
functionNamePanel.add(functionNameField, BorderLayout.CENTER);
|
||||
functionNameLabel.setLabelFor(functionNameField);
|
||||
|
||||
boolean enableVisibility = isVisibilitySectionAvailable();
|
||||
visibilityBox.setEnabled(enableVisibility);
|
||||
|
||||
+2
-1
@@ -363,7 +363,8 @@ val propertyTargets: List<ExtractionTarget> = listOf(ExtractionTarget.PROPERTY_W
|
||||
data class ExtractionGeneratorOptions(
|
||||
val inTempFile: Boolean = false,
|
||||
val target: ExtractionTarget = ExtractionTarget.FUNCTION,
|
||||
val flexibleTypesAllowed: Boolean = false
|
||||
val flexibleTypesAllowed: Boolean = false,
|
||||
val allowDummyName: Boolean = false
|
||||
) {
|
||||
default object {
|
||||
val DEFAULT = ExtractionGeneratorOptions()
|
||||
|
||||
+25
-15
@@ -72,8 +72,8 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.*
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import java.util.logging.*
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
||||
|
||||
private val DEFAULT_FUNCTION_NAME = "myFun"
|
||||
private val DEFAULT_RETURN_TYPE = KotlinBuiltIns.getInstance().getUnitType()
|
||||
private val DEFAULT_PARAMETER_TYPE = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
|
||||
@@ -804,19 +804,6 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
val enclosingDeclaration = commonParent.getStrictParentOfType<JetDeclaration>()!!
|
||||
checkDeclarationsMovingOutOfScope(enclosingDeclaration, controlFlow, bindingContext)?.let { messages.add(it) }
|
||||
|
||||
val functionNameValidator =
|
||||
JetNameValidatorImpl(
|
||||
targetSibling.getParent(),
|
||||
if (targetSibling is JetClassInitializer) targetSibling.getParent() else targetSibling,
|
||||
if (options.extractAsProperty) JetNameValidatorImpl.Target.PROPERTIES else JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES
|
||||
)
|
||||
val functionNames = if (returnType.isDefault()) {
|
||||
Collections.emptyList<String>()
|
||||
}
|
||||
else {
|
||||
JetNameSuggester.suggestNames(returnType, functionNameValidator, DEFAULT_FUNCTION_NAME).toList()
|
||||
}
|
||||
|
||||
controlFlow.jumpOutputValue?.elementToInsertAfterCall?.accept(
|
||||
object : JetTreeVisitorVoid() {
|
||||
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||
@@ -834,7 +821,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
ExtractableCodeDescriptor(
|
||||
this,
|
||||
bindingContext,
|
||||
functionNames,
|
||||
suggestFunctionNames(returnType),
|
||||
getDefaultVisibility(),
|
||||
adjustedParameters.sortBy { it.name },
|
||||
receiverParameter,
|
||||
@@ -847,6 +834,29 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
)
|
||||
}
|
||||
|
||||
private fun ExtractionData.suggestFunctionNames(returnType: JetType): List<String> {
|
||||
val functionNames = LinkedHashSet<String>()
|
||||
|
||||
val validator =
|
||||
JetNameValidatorImpl(
|
||||
targetSibling.getParent(),
|
||||
if (targetSibling is JetClassInitializer) targetSibling.getParent() else targetSibling,
|
||||
if (options.extractAsProperty) JetNameValidatorImpl.Target.PROPERTIES else JetNameValidatorImpl.Target.FUNCTIONS_AND_CLASSES
|
||||
)
|
||||
if (!returnType.isDefault()) {
|
||||
functionNames.addAll(JetNameSuggester.suggestNamesForType(returnType, validator))
|
||||
}
|
||||
|
||||
getExpressions().singleOrNull()?.let { expr ->
|
||||
val property = expr.getStrictParentOfType<JetProperty>()
|
||||
if (property?.getInitializer() == expr) {
|
||||
property?.getName()?.let { functionNames.add(validator.validateName("get" + it.capitalize())) }
|
||||
}
|
||||
}
|
||||
|
||||
return functionNames.toList()
|
||||
}
|
||||
|
||||
private fun JetNamedDeclaration.getGeneratedBody() =
|
||||
when (this) {
|
||||
is JetNamedFunction -> getBodyExpression()
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ fun ExtractionGeneratorConfiguration.getDeclarationText(
|
||||
builder.receiver(it.getParameterType(descriptor.extractionData.options.allowSpecialClassNames).typeAsString())
|
||||
}
|
||||
|
||||
builder.name(if (descriptor.name != "") descriptor.name else DEFAULT_FUNCTION_NAME)
|
||||
builder.name(if (descriptor.name == "" && generatorOptions.allowDummyName) "myFun" else descriptor.name)
|
||||
|
||||
descriptor.parameters.forEach { parameter ->
|
||||
builder.param(parameter.name,
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: pair, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: pair, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: pair, getT
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: pair, getT
|
||||
// WITH_RUNTIME
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: triple, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: triple, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in foo
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: i, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in test
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: i, getT
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_TYPES: kotlin.Int
|
||||
// PARAM_DESCRIPTOR: value-parameter val a: kotlin.Int defined in test
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getX
|
||||
class A {
|
||||
val x = <selection>1 + 1</selection>
|
||||
val y = 1 + 1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getX
|
||||
class A {
|
||||
val x = i()
|
||||
val y = i()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getY
|
||||
fun foo() {
|
||||
val x = 1 + 1
|
||||
val y = <selection>1 + 1</selection>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getY
|
||||
fun foo() {
|
||||
val x = i()
|
||||
val y = i()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getY
|
||||
// SIBLING:
|
||||
fun main(args: Array<String>) {
|
||||
val x = 1 + 1
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SUGGESTED_NAMES: i, getY
|
||||
// SIBLING:
|
||||
fun main(args: Array<String>) {
|
||||
val x = i()
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: i, getN
|
||||
// PARAM_TYPES: String?, String, kotlin.CharSequence?, CharSequence
|
||||
// PARAM_DESCRIPTOR: val property: (String..String?) defined in test
|
||||
fun test() {
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: i, getN
|
||||
// PARAM_TYPES: String?, String, kotlin.CharSequence?, CharSequence
|
||||
// PARAM_DESCRIPTOR: val property: (String..String?) defined in test
|
||||
fun test() {
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: i, getN
|
||||
// PARAM_TYPES: String, CharSequence
|
||||
// PARAM_DESCRIPTOR: val property: (String..String?) defined in test
|
||||
fun test() {
|
||||
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// SUGGESTED_NAMES: i, getN
|
||||
// PARAM_TYPES: String, CharSequence
|
||||
// PARAM_DESCRIPTOR: val property: (String..String?) defined in test
|
||||
fun test() {
|
||||
|
||||
+5
@@ -110,6 +110,7 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
)
|
||||
|
||||
val fileText = file.getText() ?: ""
|
||||
val expectedNames = InTextDirectivesUtils.findListWithPrefixes(fileText, "// SUGGESTED_NAMES: ")
|
||||
val expectedDescriptors =
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PARAM_DESCRIPTOR: ").joinToString()
|
||||
val expectedTypes =
|
||||
@@ -136,12 +137,16 @@ public abstract class AbstractJetExtractionTest() : JetLightCodeInsightFixtureTe
|
||||
descriptor: ExtractableCodeDescriptor,
|
||||
generatorOptions: ExtractionGeneratorOptions
|
||||
): ExtractionGeneratorConfiguration {
|
||||
val actualNames = descriptor.suggestedNames
|
||||
val allParameters = emptyOrSingletonList(descriptor.receiverParameter) + descriptor.parameters
|
||||
val actualDescriptors = allParameters.map { renderer.render(it.originalDescriptor) }.joinToString()
|
||||
val actualTypes = allParameters.map {
|
||||
it.getParameterTypeCandidates(false).map { renderer.renderType(it) }.joinToString(", ", "[", "]")
|
||||
}.joinToString()
|
||||
|
||||
if (actualNames.size() != 1 || expectedNames.isNotEmpty()) {
|
||||
assertEquals(expectedNames, actualNames, "Expected names mismatch.")
|
||||
}
|
||||
assertEquals(expectedDescriptors, actualDescriptors, "Expected descriptors mismatch.")
|
||||
assertEquals(expectedTypes, actualTypes, "Expected types mismatch.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user