Introduce Property: Fix extraction of expressions referring to primary constructor parameters

#KT-12294 Fixed
(cherry picked from commit 78212a4)
This commit is contained in:
Alexey Sedunov
2016-06-23 17:20:06 +03:00
parent c075d27731
commit 00ad37b769
8 changed files with 55 additions and 16 deletions
+1
View File
@@ -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
@@ -37,6 +37,8 @@ abstract class ExtractionEngineHelper(val operationName: String) {
onFinish(project.executeWriteCommand<ExtractionResult>(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 {
@@ -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<KotlinType> {
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
@@ -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)
@@ -0,0 +1,4 @@
// EXTRACTION_TARGET: property with initializer
class Foo(s: String) {
val l = <selection>(s + "1")</selection>.length
}
@@ -0,0 +1,6 @@
// EXTRACTION_TARGET: property with initializer
class Foo(s: String) {
private val s = (s + "1")
val l = s.length
}
@@ -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,
@@ -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");