From 0a8490a068e51e06bc3309cd55ecf5e991d0c018 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Tue, 19 Jul 2016 18:08:29 +0300 Subject: [PATCH] Introduce Type Alias: Suggest initial name based on extracted type --- .../kotlin/idea/core/KotlinNameSuggester.kt | 21 +++++++++++++++++++ .../introduceTypeAliasImpl.kt | 8 ++++++- .../ui/KotlinIntroduceTypeAliasDialog.java | 3 +-- .../introduceTypeAlias/suggestedName.kt | 4 ++++ .../introduceTypeAlias/suggestedName.kt.after | 6 ++++++ .../introduce/AbstractExtractionTest.kt | 4 ++-- .../introduce/ExtractionTestGenerated.java | 6 ++++++ 7 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 idea/testData/refactoring/introduceTypeAlias/suggestedName.kt create mode 100644 idea/testData/refactoring/introduceTypeAlias/suggestedName.kt.after diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt index 5407673fc9d..61813f73574 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinNameSuggester.kt @@ -114,6 +114,27 @@ object KotlinNameSuggester { return result } + fun suggestTypeAliasNameByPsi(typeElement: KtTypeElement, validator: (String) -> Boolean): String { + fun KtTypeElement.render(): String { + return when (this) { + is KtNullableType -> "Nullable${innerType?.render() ?: ""}" + is KtFunctionType -> { + val arguments = listOf(receiverTypeReference).filterNotNull() + parameters.mapNotNull { it.typeReference } + val argText = arguments.joinToString(separator = "") { it.typeElement?.render() ?: "" } + val returnText = returnTypeReference?.typeElement?.render() ?: "Unit" + "${argText}To$returnText" + } + is KtUserType -> { + val argText = typeArguments.joinToString(separator = "") { it.typeReference?.typeElement?.render() ?: "" } + "$argText${referenceExpression?.text ?: ""}" + } + else -> text.capitalize() + } + } + + return suggestNameByName(typeElement.render(), validator) + } + /** * Validates name, and slightly improves it by adding number to name in case of conflicts * @param name to check it in scope diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/introduceTypeAliasImpl.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/introduceTypeAliasImpl.kt index 4d9bb0ea764..9df389d3d97 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/introduceTypeAliasImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/introduceTypeAliasImpl.kt @@ -105,7 +105,13 @@ fun IntroduceTypeAliasData.analyze(): IntroduceTypeAliasAnalysisResult { return IntroduceTypeAliasAnalysisResult.Error("Type alias cannot refer to types which aren't accessible in the scope where it's defined") } - return IntroduceTypeAliasAnalysisResult.Success(IntroduceTypeAliasDescriptor(this, "", null, typeParameters)) + val descriptor = IntroduceTypeAliasDescriptor(this, "Dummy", null, typeParameters) + + val initialName = KotlinNameSuggester.suggestTypeAliasNameByPsi(descriptor.generateTypeAlias(true).getTypeReference()!!.typeElement!!) { + targetScope.findClassifier(Name.identifier(it), NoLookupLocation.FROM_IDE) == null + } + + return IntroduceTypeAliasAnalysisResult.Success(descriptor.copy(name = initialName)) } fun IntroduceTypeAliasData.getApplicableVisibilities(): List{ diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/ui/KotlinIntroduceTypeAliasDialog.java b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/ui/KotlinIntroduceTypeAliasDialog.java index 96dbf5b278c..788c49c3c6a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/ui/KotlinIntroduceTypeAliasDialog.java +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceTypeAlias/ui/KotlinIntroduceTypeAliasDialog.java @@ -21,7 +21,6 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.psi.PsiElement; import com.intellij.refactoring.ui.NameSuggestionsField; import com.intellij.ui.TitledSeparator; -import com.intellij.util.ArrayUtil; import com.intellij.util.containers.MultiMap; import kotlin.Unit; import kotlin.jvm.functions.Function0; @@ -143,7 +142,7 @@ public class KotlinIntroduceTypeAliasDialog extends DialogWrapper { } ); - aliasNameField = new NameSuggestionsField(ArrayUtil.EMPTY_STRING_ARRAY, project, KotlinFileType.INSTANCE); + aliasNameField = new NameSuggestionsField(new String[]{originalDescriptor.getName()}, project, KotlinFileType.INSTANCE); aliasNameField.addDataChangedListener( new NameSuggestionsField.DataChanged() { @Override diff --git a/idea/testData/refactoring/introduceTypeAlias/suggestedName.kt b/idea/testData/refactoring/introduceTypeAlias/suggestedName.kt new file mode 100644 index 00000000000..34dd4ea39df --- /dev/null +++ b/idea/testData/refactoring/introduceTypeAlias/suggestedName.kt @@ -0,0 +1,4 @@ +// SIBLING: +fun foo(list: List<(String?) -> Boolean>) { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/introduceTypeAlias/suggestedName.kt.after b/idea/testData/refactoring/introduceTypeAlias/suggestedName.kt.after new file mode 100644 index 00000000000..e8aa6b15298 --- /dev/null +++ b/idea/testData/refactoring/introduceTypeAlias/suggestedName.kt.after @@ -0,0 +1,6 @@ +typealias NullableStringToBooleanList = List<(String?) -> Boolean> + +// SIBLING: +fun foo(list: NullableStringToBooleanList) { + +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/AbstractExtractionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/AbstractExtractionTest.kt index 7c542b224cf..f27b6105cd5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/AbstractExtractionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/AbstractExtractionTest.kt @@ -320,14 +320,14 @@ abstract class AbstractExtractionTest() : KotlinLightCodeInsightFixtureTestCase( val explicitPreviousSibling = file.findElementByCommentPrefix("// SIBLING:") val fileText = file.text - val aliasName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// NAME:")!! + val aliasName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// NAME:") val aliasVisibility = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// VISIBILITY:")?.let { KtPsiFactory(project).createModifierList(it).firstChild.node.elementType as KtModifierKeywordToken } val editor = fixture.editor KotlinIntroduceTypeAliasHandler.selectElements(editor, file) { elements, previousSibling -> KotlinIntroduceTypeAliasHandler.doInvoke(project, editor, elements, explicitPreviousSibling ?: previousSibling) { - it.copy(name = aliasName, visibility = aliasVisibility ?: it.visibility) + it.copy(name = aliasName ?: it.name, visibility = aliasVisibility ?: it.visibility) } } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java index 625f983dd8e..1bb94bf9265 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java @@ -4078,6 +4078,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest { doIntroduceTypeAliasTest(fileName); } + @TestMetadata("suggestedName.kt") + public void testSuggestedName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceTypeAlias/suggestedName.kt"); + doIntroduceTypeAliasTest(fileName); + } + @TestMetadata("topLevelTypeAlias.kt") public void testTopLevelTypeAlias() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceTypeAlias/topLevelTypeAlias.kt");