From 767897dccf84b7bb03a705cb08a163be944a25e4 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Mon, 14 Sep 2015 13:16:20 +0300 Subject: [PATCH] Extraction Engine: Replace receiver occurrences with 'this' when necessary --- .../ExtractableCodeDescriptor.kt | 29 +++++++++---------- .../extractableAnalysisUtil.kt | 5 ++-- .../extractionEngine/extractorUtil.kt | 8 ++--- .../parameters/extractThis/qualifiedThis.kt | 11 +++++++ .../extractThis/qualifiedThis.kt.after | 13 +++++++++ .../introduce/JetExtractionTestGenerated.java | 6 ++++ 6 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt create mode 100644 idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt index a5af7ca591e..84ba61afc4e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractableCodeDescriptor.kt @@ -71,7 +71,7 @@ data class TypeParameter( val originalConstraints: List ) -interface Replacement: Function1 +interface Replacement: Function2 interface ParameterReplacement : Replacement { val parameter: Parameter @@ -81,19 +81,17 @@ interface ParameterReplacement : Replacement { class RenameReplacement(override val parameter: Parameter): ParameterReplacement { override fun copy(parameter: Parameter) = RenameReplacement(parameter) - override fun invoke(e: JetElement): JetElement { + override fun invoke(descriptor: ExtractableCodeDescriptor, e: JetElement): JetElement { var expressionToReplace = (e.getParent() as? JetThisExpression ?: e).let { it.getQualifiedExpressionForSelector() ?: it } val parameterName = JetPsiUtil.unquoteIdentifier(parameter.nameForRef) val replacingName = if (e.getText().startsWith('`') || !KotlinNameSuggester.isIdentifier(parameterName)) "`$parameterName`" else parameterName val psiFactory = JetPsiFactory(e) - val replacement = - if (expressionToReplace is JetOperationReferenceExpression) { - psiFactory.createOperationName(replacingName) - } - else { - psiFactory.createSimpleName(replacingName) - } + val replacement = when { + parameter == descriptor.receiverParameter -> psiFactory.createExpression("this") + expressionToReplace is JetOperationReferenceExpression -> psiFactory.createOperationName(replacingName) + else -> psiFactory.createSimpleName(replacingName) + } return expressionToReplace.replaced(replacement) } } @@ -101,17 +99,18 @@ class RenameReplacement(override val parameter: Parameter): ParameterReplacement class AddPrefixReplacement(override val parameter: Parameter): ParameterReplacement { override fun copy(parameter: Parameter) = AddPrefixReplacement(parameter) - override fun invoke(e: JetElement): JetElement { - val selector = (e.getParent() as? JetCallExpression) ?: e - val newExpr = selector.replace(JetPsiFactory(e).createExpression("${parameter.nameForRef}.${selector.getText()}") - ) as JetQualifiedExpression + override fun invoke(descriptor: ExtractableCodeDescriptor, e: JetElement): JetElement { + if (descriptor.receiverParameter == parameter) return e - return with(newExpr.getSelectorExpression()!!) { if (this is JetCallExpression) getCalleeExpression()!! else this } + val selector = (e.parent as? JetCallExpression) ?: e + val replacingExpression = JetPsiFactory(e).createExpression("${parameter.nameForRef}.${selector.text}") + val newExpr = (selector.replace(replacingExpression) as JetQualifiedExpression).selectorExpression!! + return (newExpr as? JetCallExpression)?.calleeExpression ?: newExpr } } class FqNameReplacement(val fqName: FqName): Replacement { - override fun invoke(e: JetElement): JetElement { + override fun invoke(descriptor: ExtractableCodeDescriptor, e: JetElement): JetElement { val thisExpr = e.getParent() as? JetThisExpression if (thisExpr != null) { return thisExpr.replaced(JetPsiFactory(e).createExpression(fqName.asString())).getQualifiedElementSelector()!! 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 dce71379e7e..be4d3872d9a 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 @@ -1005,8 +1005,9 @@ fun ExtractableCodeDescriptor.validate(): ExtractableCodeDescriptorWithConflicts for ((originalOffset, resolveResult) in extractionData.refOffsetToDeclaration) { if (resolveResult.declaration.isInsideOf(extractionData.originalElements)) continue - val currentRefExpr = result.nameByOffset[originalOffset] as JetSimpleNameExpression? - if (currentRefExpr == null) continue + val currentRefExpr = result.nameByOffset[originalOffset]?.let { + (it as? JetThisExpression)?.instanceReference ?: it as? JetSimpleNameExpression + } ?: continue if (currentRefExpr.getParent() is JetThisExpression) continue diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt index 0b6433513f5..17ac0c836d5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt @@ -455,7 +455,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration( fun adjustDeclarationBody(declaration: JetNamedDeclaration) { val body = declaration.getGeneratedBody() - val exprReplacementMap = HashMap JetElement>() + val exprReplacementMap = HashMap JetElement>() val originalOffsetByExpr = LinkedHashMap() val bodyOffset = body.getBlockContentOffset() @@ -472,9 +472,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration( originalOffsetByExpr[expr!!] = offsetInBody descriptor.replacementMap[offsetInBody]?.let { replacement -> - if (replacement !is ParameterReplacement || replacement.parameter != descriptor.receiverParameter) { - exprReplacementMap[expr] = replacement - } + exprReplacementMap[expr] = replacement } } @@ -505,7 +503,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration( for ((expr, originalOffset) in originalOffsetByExpr) { if (expr.isValid()) { - nameByOffset.put(originalOffset, exprReplacementMap[expr]?.invoke(expr) ?: expr) + nameByOffset.put(originalOffset, exprReplacementMap[expr]?.invoke(descriptor, expr) ?: expr) } } diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt new file mode 100644 index 00000000000..48caccbaf03 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt @@ -0,0 +1,11 @@ +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, kotlin.Any +// PARAM_DESCRIPTOR: public fun kotlin.String.test(): kotlin.Unit defined in root package +fun String.foo(f: () -> Unit) { + f() +} + +fun String.test() { + "sss".foo { + println(this@test) + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after new file mode 100644 index 00000000000..f1b1c5dc5f7 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt.after @@ -0,0 +1,13 @@ +// PARAM_TYPES: kotlin.String, Comparable, CharSequence, kotlin.Any +// PARAM_DESCRIPTOR: public fun kotlin.String.test(): kotlin.Unit defined in root package +fun String.foo(f: () -> Unit) { + f() +} + +fun String.test() { + "sss".foo { + println(s()) + } +} + +private fun String.s() = this \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java index 9525d80fa4f..b2da6fe61a4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java @@ -2003,6 +2003,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doExtractFunctionTest(fileName); } + @TestMetadata("qualifiedThis.kt") + public void testQualifiedThis() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThis.kt"); + doExtractFunctionTest(fileName); + } + @TestMetadata("qualifiedThisAsArgument.kt") public void testQualifiedThisAsArgument() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThisAsArgument.kt");