From 41b6bcf8c350a570e7e80bc7ae9989821d02614f Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Tue, 8 Jan 2019 14:33:32 +0300 Subject: [PATCH] Converting object literal to class allows to choose a name (KT-19254) --- .../ConvertObjectLiteralToClassIntention.kt | 52 ++++++++++++------- .../inClass.kt.after | 4 +- .../inClassHasMethodReference.kt.after | 4 +- .../inClassHasPropertyReference.kt.after | 4 +- .../inFunction.kt.after | 4 +- .../objectLiteralNoCapture.kt.after | 4 +- .../objectLiteralNoSupers.kt.after | 4 +- .../objectLiteralWithCapture.kt.after | 4 +- 8 files changed, 47 insertions(+), 33 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertObjectLiteralToClassIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertObjectLiteralToClassIntention.kt index bb3fb5dd787..6f2ee45172f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertObjectLiteralToClassIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertObjectLiteralToClassIntention.kt @@ -16,13 +16,16 @@ package org.jetbrains.kotlin.idea.intentions +import com.intellij.codeInsight.CodeInsightUtilCore +import com.intellij.codeInsight.template.TemplateBuilderImpl +import com.intellij.codeInsight.template.TemplateManager import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiComment import com.intellij.psi.codeStyle.CodeStyleManager +import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.searches.ReferencesSearch -import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.refactoring.chooseContainerElementIfNecessary @@ -35,12 +38,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.allChildren -import org.jetbrains.kotlin.psi.psiUtil.containingClass -import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType -import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf -import org.jetbrains.kotlin.resolve.calls.callUtil.getType -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier class ConvertObjectLiteralToClassIntention : SelfTargetingRangeIntention( @@ -55,16 +53,14 @@ class ConvertObjectLiteralToClassIntention : SelfTargetingRangeIntention Boolean = { scope.findClassifier(Name.identifier(it), NoLookupLocation.FROM_IDE) == null } - val className = if (objectLiteralType != null) { - KotlinNameSuggester.suggestNamesByType(objectLiteralType, validator, "O").first() - } - else { - KotlinNameSuggester.suggestNameByName("O", validator) - } + val validator: (String) -> Boolean = { scope.findClassifier(Name.identifier(it), NoLookupLocation.FROM_IDE) == null } + val classNames = element.objectDeclaration.superTypeListEntries + .mapNotNull { it.typeReference?.typeElement?.let { KotlinNameSuggester.suggestTypeAliasNameByPsi(it, validator) } } + .takeIf { it.isNotEmpty() } + ?: listOf(KotlinNameSuggester.suggestNameByName("O", validator)) + + val className = classNames.first() val psiFactory = KtPsiFactory(element) val targetSibling = element.parentsWithSelf.first { it.parent == targetParent } @@ -102,8 +98,8 @@ class ConvertObjectLiteralToClassIntention : SelfTargetingRangeIntention + val functionDeclaration = extractionResult.declaration as KtFunction if (functionDeclaration.valueParameters.isNotEmpty()) { val valKeyword = psiFactory.createValKeyword() newClass @@ -115,10 +111,24 @@ class ConvertObjectLiteralToClassIntention : SelfTargetingRangeIntention + builder.replaceElement(introducedClass.nameIdentifier!!, NEW_CLASS_NAME, ChooseStringExpression(classNames), true) + for (psiReference in ReferencesSearch.search(introducedClass, LocalSearchScope(file), false)) { + builder.replaceElement(psiReference.element, USAGE_VARIABLE_NAME, NEW_CLASS_NAME, false) + } + builder.buildInlineTemplate() } + + editor.caretModel.moveToOffset(file.startOffset) + TemplateManager.getInstance(project).startTemplate(editor, template) } } } @@ -146,3 +156,7 @@ class ConvertObjectLiteralToClassIntention : SelfTargetingRangeIntentionO() + val x = K1() } -class O : K() { +class K1 : K() { fun bar() = 1 } \ No newline at end of file diff --git a/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralNoSupers.kt.after b/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralNoSupers.kt.after index a7e6a9c60dc..1db30e4d937 100644 --- a/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralNoSupers.kt.after +++ b/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralNoSupers.kt.after @@ -1,7 +1,7 @@ fun foo(n: Int) { - val x = O(n) + val x = O(n) } -class O(private val n: Int) { +class O(private val n: Int) { fun bar() = n } \ No newline at end of file diff --git a/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralWithCapture.kt.after b/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralWithCapture.kt.after index 8ac91c2d271..ae431d35191 100644 --- a/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralWithCapture.kt.after +++ b/idea/testData/intentions/convertObjectLiteralToClass/objectLiteralWithCapture.kt.after @@ -1,9 +1,9 @@ open class K fun foo(n: Int) { - val x = O(n) + val x = K1(n) } -class O(private val n: Int) : K() { +class K1(private val n: Int) : K() { fun bar() = n } \ No newline at end of file