Introduce Type Alias: Suggest initial name based on extracted type

This commit is contained in:
Alexey Sedunov
2016-07-19 18:08:29 +03:00
parent 0769d47f4b
commit 0a8490a068
7 changed files with 47 additions and 5 deletions
@@ -114,6 +114,27 @@ object KotlinNameSuggester {
return result 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 * Validates name, and slightly improves it by adding number to name in case of conflicts
* @param name to check it in scope * @param name to check it in scope
@@ -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.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<KtModifierKeywordToken>{ fun IntroduceTypeAliasData.getApplicableVisibilities(): List<KtModifierKeywordToken>{
@@ -21,7 +21,6 @@ import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.refactoring.ui.NameSuggestionsField; import com.intellij.refactoring.ui.NameSuggestionsField;
import com.intellij.ui.TitledSeparator; import com.intellij.ui.TitledSeparator;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.MultiMap;
import kotlin.Unit; import kotlin.Unit;
import kotlin.jvm.functions.Function0; 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( aliasNameField.addDataChangedListener(
new NameSuggestionsField.DataChanged() { new NameSuggestionsField.DataChanged() {
@Override @Override
@@ -0,0 +1,4 @@
// SIBLING:
fun foo(list: <caret>List<(String?) -> Boolean>) {
}
@@ -0,0 +1,6 @@
typealias NullableStringToBooleanList = List<(String?) -> Boolean>
// SIBLING:
fun foo(list: NullableStringToBooleanList) {
}
@@ -320,14 +320,14 @@ abstract class AbstractExtractionTest() : KotlinLightCodeInsightFixtureTestCase(
val explicitPreviousSibling = file.findElementByCommentPrefix("// SIBLING:") val explicitPreviousSibling = file.findElementByCommentPrefix("// SIBLING:")
val fileText = file.text val fileText = file.text
val aliasName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// NAME:")!! val aliasName = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// NAME:")
val aliasVisibility = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// VISIBILITY:")?.let { val aliasVisibility = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// VISIBILITY:")?.let {
KtPsiFactory(project).createModifierList(it).firstChild.node.elementType as KtModifierKeywordToken KtPsiFactory(project).createModifierList(it).firstChild.node.elementType as KtModifierKeywordToken
} }
val editor = fixture.editor val editor = fixture.editor
KotlinIntroduceTypeAliasHandler.selectElements(editor, file) { elements, previousSibling -> KotlinIntroduceTypeAliasHandler.selectElements(editor, file) { elements, previousSibling ->
KotlinIntroduceTypeAliasHandler.doInvoke(project, editor, elements, explicitPreviousSibling ?: 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)
} }
} }
} }
@@ -4078,6 +4078,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest {
doIntroduceTypeAliasTest(fileName); 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") @TestMetadata("topLevelTypeAlias.kt")
public void testTopLevelTypeAlias() throws Exception { public void testTopLevelTypeAlias() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceTypeAlias/topLevelTypeAlias.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceTypeAlias/topLevelTypeAlias.kt");