diff --git a/ChangeLog.md b/ChangeLog.md index 89f7307a960..564276f458c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -117,6 +117,7 @@ These artifacts include extensions for the types available in the latter JDKs, s ###### Issues fixed +- [`KT-12294`](https://youtrack.jetbrains.com/issue/KT-12294) Introduce Property: Fix extraction of expressions referring to primary constructor parameters - [`KT-12413`](https://youtrack.jetbrains.com/issue/KT-12413) Change Signature: Fix bogus warning about unresolved type parameters/invalid functional type replacement ## 1.0.3 diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionEngine.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionEngine.kt index bf7b090f835..aac11cc0bfe 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionEngine.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionEngine.kt @@ -37,6 +37,8 @@ abstract class ExtractionEngineHelper(val operationName: String) { onFinish(project.executeWriteCommand(operationName) { config.generateDeclaration() }) } + open fun validate(descriptor: ExtractableCodeDescriptor): ExtractableCodeDescriptorWithConflicts = descriptor.validate() + abstract fun configureAndRun( project: Project, editor: Editor, @@ -61,7 +63,7 @@ class ExtractionEngine( } fun validateAndRefactor() { - val validationResult = analysisResult.descriptor!!.validate() + val validationResult = helper.validate(analysisResult.descriptor!!) project.checkConflictsInteractively(validationResult.conflicts) { helper.configureAndRun(project, editor, validationResult) { try { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt index 898ad634b9f..0bbd831f97f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractableAnalysisUtil.kt @@ -394,8 +394,12 @@ fun ExtractionData.createTemporaryDeclaration(pattern: String): KtNamedDeclarati } } -internal fun ExtractionData.createTemporaryCodeBlock(): KtBlockExpression = - (createTemporaryDeclaration("fun() {\n$0\n}\n") as KtNamedFunction).bodyExpression as KtBlockExpression +internal fun ExtractionData.createTemporaryCodeBlock(): KtBlockExpression { + if (options.extractAsProperty) { + return ((createTemporaryDeclaration("val = {\n$0\n}\n") as KtProperty).initializer as KtLambdaExpression).bodyExpression!! + } + return (createTemporaryDeclaration("fun() {\n$0\n}\n") as KtNamedFunction).bodyExpression as KtBlockExpression +} private fun KotlinType.collectReferencedTypes(processTypeArguments: Boolean): List { if (!processTypeArguments) return Collections.singletonList(this) @@ -739,7 +743,8 @@ internal fun KtNamedDeclaration.getGeneratedBody() = } } ?: throw AssertionError("Couldn't get block body for this declaration: ${getElementTextWithContext()}") -fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts { +@JvmOverloads +fun ExtractableCodeDescriptor.validate(target: ExtractionTarget = ExtractionTarget.FUNCTION): ExtractableCodeDescriptorWithConflicts { fun getDeclarationMessage(declaration: PsiNamedElement, messageKey: String, capitalize: Boolean = true): String { val message = KotlinRefactoringBundle.message(messageKey, RefactoringUIUtil.getDescription(declaration, true)) return if (capitalize) message.capitalize() else message @@ -749,7 +754,7 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts val result = ExtractionGeneratorConfiguration( this, - ExtractionGeneratorOptions(inTempFile = true, allowExpressionBody = false) + ExtractionGeneratorOptions(inTempFile = true, allowExpressionBody = false, target = target) ).generateDeclaration() val valueParameterList = (result.declaration as? KtNamedFunction)?.valueParameterList diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/KotlinIntroducePropertyHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/KotlinIntroducePropertyHandler.kt index d22f6d76688..921e26ab814 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/KotlinIntroducePropertyHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceProperty/KotlinIntroducePropertyHandler.kt @@ -16,25 +16,38 @@ package org.jetbrains.kotlin.idea.refactoring.introduce.introduceProperty -import com.intellij.openapi.project.* -import com.intellij.psi.* -import com.intellij.openapi.actionSystem.* -import com.intellij.openapi.editor.* -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.idea.refactoring.introduce.* -import org.jetbrains.kotlin.idea.refactoring.* -import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* -import org.jetbrains.kotlin.idea.util.psi.patternMatching.* -import com.intellij.openapi.application.* +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.intellij.refactoring.RefactoringActionHandler import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils +import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers +import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* +import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetSibling +import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint +import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHintByKey +import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange +import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtClassBody +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtProperty import java.util.* class KotlinIntroducePropertyHandler( val helper: ExtractionEngineHelper = KotlinIntroducePropertyHandler.InteractiveExtractionHelper ): RefactoringActionHandler { object InteractiveExtractionHelper : ExtractionEngineHelper(INTRODUCE_PROPERTY) { + private fun getExtractionTarget(descriptor: ExtractableCodeDescriptor) = + propertyTargets.filter { it.isAvailable(descriptor) }.firstOrNull() + + override fun validate(descriptor: ExtractableCodeDescriptor) = + descriptor.validate(getExtractionTarget(descriptor) ?: ExtractionTarget.FUNCTION) + override fun configureAndRun( project: Project, editor: Editor, @@ -42,7 +55,7 @@ class KotlinIntroducePropertyHandler( onFinish: (ExtractionResult) -> Unit ) { val descriptor = descriptorWithConflicts.descriptor - val target = propertyTargets.filter { it.isAvailable(descriptor) }.firstOrNull() + val target = getExtractionTarget(descriptor) if (target != null) { val options = ExtractionGeneratorOptions.DEFAULT.copy(target = target, delayInitialOccurrenceReplacement = true) doRefactor(ExtractionGeneratorConfiguration(descriptor, options), onFinish) diff --git a/idea/testData/refactoring/introduceProperty/primaryConstructorParameterReference.kt b/idea/testData/refactoring/introduceProperty/primaryConstructorParameterReference.kt new file mode 100644 index 00000000000..f8857b5f53d --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/primaryConstructorParameterReference.kt @@ -0,0 +1,4 @@ +// EXTRACTION_TARGET: property with initializer +class Foo(s: String) { + val l = (s + "1").length +} \ No newline at end of file diff --git a/idea/testData/refactoring/introduceProperty/primaryConstructorParameterReference.kt.after b/idea/testData/refactoring/introduceProperty/primaryConstructorParameterReference.kt.after new file mode 100644 index 00000000000..8af768e7bde --- /dev/null +++ b/idea/testData/refactoring/introduceProperty/primaryConstructorParameterReference.kt.after @@ -0,0 +1,6 @@ +// EXTRACTION_TARGET: property with initializer +class Foo(s: String) { + private val s = (s + "1") + + val l = s.length +} \ 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 fa3b90994a0..ea36e90aefc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/AbstractExtractionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/AbstractExtractionTest.kt @@ -216,6 +216,8 @@ abstract class AbstractExtractionTest() : KotlinLightCodeInsightFixtureTestCase( } val explicitPreviousSibling = file.findElementByCommentPrefix("// SIBLING:") val helper = object : ExtractionEngineHelper(INTRODUCE_PROPERTY) { + override fun validate(descriptor: ExtractableCodeDescriptor) = descriptor.validate(extractionTarget) + override fun configureAndRun( project: Project, editor: Editor, 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 b7f28c65b33..2edcf4eb99e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java @@ -3100,6 +3100,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest { doIntroducePropertyTest(fileName); } + @TestMetadata("primaryConstructorParameterReference.kt") + public void testPrimaryConstructorParameterReference() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/primaryConstructorParameterReference.kt"); + doIntroducePropertyTest(fileName); + } + @TestMetadata("replaceDuplicates.kt") public void testReplaceDuplicates() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceProperty/replaceDuplicates.kt");