Move: Convert implicit receiver to this when moving class member to companion object

#KT-11483 Fixed
This commit is contained in:
Alexey Sedunov
2016-04-25 12:30:35 +03:00
parent 6faedc1adc
commit aaa873f227
6 changed files with 54 additions and 14 deletions
+1
View File
@@ -38,6 +38,7 @@ Issues fixed:
- [KT-11282](https://youtrack.jetbrains.com/issue/KT-11282) Delete interface reference from super-type list when applying Safe Delete to Java interface - [KT-11282](https://youtrack.jetbrains.com/issue/KT-11282) Delete interface reference from super-type list when applying Safe Delete to Java interface
- [KT-11967](https://youtrack.jetbrains.com/issue/KT-11967) Fix Find Usages/Rename for parameter references in XML files - [KT-11967](https://youtrack.jetbrains.com/issue/KT-11967) Fix Find Usages/Rename for parameter references in XML files
- [KT-11482](https://youtrack.jetbrains.com/issue/KT-11482) Fixed exception in "Move to companion object" intention - [KT-11482](https://youtrack.jetbrains.com/issue/KT-11482) Fixed exception in "Move to companion object" intention
- [KT-11483](https://youtrack.jetbrains.com/issue/KT-11483) Pass implicit receiver as argument when moving member function to companion object
#### Debugger #### Debugger
@@ -57,6 +57,7 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
) { ) {
companion object { companion object {
val DEFAULT = Options() val DEFAULT = Options()
val ALL_ENABLED = Options(true, true)
} }
} }
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.*
@@ -115,7 +116,7 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
} }
} }
private fun moveReceiverToArgumentList(refElement: PsiElement) { private fun moveReceiverToArgumentList(refElement: PsiElement, classFqName: FqName) {
when (refElement) { when (refElement) {
is PsiReferenceExpression -> { is PsiReferenceExpression -> {
val qualifier = refElement.qualifier val qualifier = refElement.qualifier
@@ -127,15 +128,15 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
} }
is KtSimpleNameExpression -> { is KtSimpleNameExpression -> {
val call = refElement.parent as? KtCallExpression val call = refElement.parent as? KtCallExpression ?: return
val receiver = call?.getQualifiedExpressionForSelector()?.receiverExpression val psiFactory = KtPsiFactory(refElement)
if (call != null && receiver != null) { val argumentList = call.valueArgumentList
val psiFactory = KtPsiFactory(refElement) ?: call.addAfter(psiFactory.createCallArguments("()"), call.typeArgumentList ?: refElement) as KtValueArgumentList
val argumentList = call.valueArgumentList
?: call.addAfter(psiFactory.createCallArguments("()"), call.typeArgumentList ?: refElement) as KtValueArgumentList val receiver = call.getQualifiedExpressionForSelector()?.receiverExpression
argumentList.addArgumentBefore(psiFactory.createArgument(receiver), val receiverArg = receiver?.let { psiFactory.createArgument(it) }
argumentList.arguments.firstOrNull()) ?: psiFactory.createArgument(psiFactory.createExpression("this@${classFqName.asString()}"))
} argumentList.addArgumentBefore(receiverArg, argumentList.arguments.firstOrNull())
} }
} }
} }
@@ -190,6 +191,8 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
nameSuggestions = emptyList() nameSuggestions = emptyList()
} }
val hasInstanceArg = nameSuggestions.isNotEmpty()
element.removeModifier(KtTokens.OPEN_KEYWORD) element.removeModifier(KtTokens.OPEN_KEYWORD)
element.removeModifier(KtTokens.FINAL_KEYWORD) element.removeModifier(KtTokens.FINAL_KEYWORD)
@@ -198,8 +201,8 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
for (usage in externalUsages) { for (usage in externalUsages) {
val usageElement = usage.element ?: continue val usageElement = usage.element ?: continue
if (nameSuggestions.isNotEmpty()) { if (hasInstanceArg) {
moveReceiverToArgumentList(usageElement) moveReceiverToArgumentList(usageElement, containingClass.fqName!!)
} }
when (usage) { when (usage) {
@@ -217,12 +220,18 @@ class MoveMemberToCompanionObjectIntention : SelfTargetingRangeIntention<KtNamed
is ImplicitReceiverUsageInfo -> { is ImplicitReceiverUsageInfo -> {
usage.callExpression usage.callExpression
.let { it.replaced(ktPsiFactory.createExpressionByPattern("$0.$1", ktCompanionRef, it)) } .let { it.replaced(ktPsiFactory.createExpressionByPattern("$0.$1", ktCompanionRef, it)) }
.let { elementsToShorten += (it as KtQualifiedExpression).receiverExpression } .let {
val qualifiedCall = it as KtQualifiedExpression
elementsToShorten += qualifiedCall.receiverExpression
if (hasInstanceArg) {
elementsToShorten += (qualifiedCall.selectorExpression as KtCallExpression).valueArguments.first()
}
}
} }
} }
} }
ShortenReferences.DEFAULT.process(elementsToShorten) ShortenReferences { ShortenReferences.Options.ALL_ENABLED }.process(elementsToShorten)
runTemplateForInstanceParam(newDeclaration, nameSuggestions, editor) runTemplateForInstanceParam(newDeclaration, nameSuggestions, editor)
} }
@@ -0,0 +1,9 @@
fun println(a: Any) {}
class InsertThis {
val v1 = 1
fun <caret>f() {
println(v1)
}
fun use() { f() }
}
@@ -0,0 +1,14 @@
fun println(a: Any) {}
class InsertThis {
val v1 = 1
fun use() {
Companion.f(this)
}
companion object {
fun f(insertThis: InsertThis) {
println(insertThis.v1)
}
}
}
@@ -6886,6 +6886,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("implicitDispatchReceiver.kt")
public void testImplicitDispatchReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/implicitDispatchReceiver.kt");
doTest(fileName);
}
@TestMetadata("inInnerClass.kt") @TestMetadata("inInnerClass.kt")
public void testInInnerClass() throws Exception { public void testInInnerClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/inInnerClass.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveToCompanion/inInnerClass.kt");