Rename: Fix qualified expression replacement for the case 'invoke' <-> 'get'

#KT-22705 Fixed
This commit is contained in:
Alexey Sedunov
2018-02-06 17:42:07 +03:00
parent fffd74f002
commit 5c6bba9f14
12 changed files with 184 additions and 7 deletions
@@ -156,6 +156,9 @@ fun KtExpression.getQualifiedExpressionForReceiverOrThis(): KtExpression {
fun KtExpression.isDotReceiver(): Boolean =
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
fun KtExpression.getPossiblyQualifiedCallExpression(): KtCallExpression? =
((this as? KtQualifiedExpression)?.selectorExpression ?: this) as? KtCallExpression
// ---------- Block expression -------------------------------------------------------------------------------------------------------------
fun KtElement.blockExpressionsOrSingle(): Sequence<KtElement> =
@@ -20,12 +20,14 @@ import com.google.common.collect.Lists
import com.intellij.psi.MultiRangeReference
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.buildExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getPossiblyQualifiedCallExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_GET
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_SET
@@ -55,13 +57,27 @@ class KtArrayAccessReference(
override fun handleElementRename(newElementName: String?): PsiElement? {
val arrayAccessExpression = expression
if (OperatorNameConventions.INVOKE.asString() == newElementName) {
val callExpression = KtPsiFactory(arrayAccessExpression.project).buildExpression {
appendExpression(arrayAccessExpression.arrayExpression)
val replacement = KtPsiFactory(arrayAccessExpression.project).buildExpression {
val arrayExpression = arrayAccessExpression.arrayExpression
if (arrayExpression is KtQualifiedExpression) {
appendExpression(arrayExpression.receiverExpression)
appendFixedText(arrayExpression.operationSign.value)
appendExpression(arrayExpression.selectorExpression)
}
else {
appendExpression(arrayExpression)
}
appendFixedText("(")
appendExpressions(arrayAccessExpression.indexExpressions, ",")
appendFixedText(")")
}
return arrayAccessExpression.replace(callExpression)
val fullCallExpression = arrayAccessExpression.replaced(replacement)
val callExpression = fullCallExpression.getPossiblyQualifiedCallExpression()
if (callExpression != null && callExpression.canMoveLambdaOutsideParentheses()) {
callExpression.moveFunctionLiteralOutsideParentheses()
}
return fullCallExpression
}
return this.renameImplicitConventionalCall(newElementName)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -95,14 +96,19 @@ class KtInvokeFunctionReference(expression: KtCallExpression) : KtSimpleReferenc
override fun handleElementRename(newElementName: String?): PsiElement? {
val callExpression = expression
val fullCallExpression = callExpression.getQualifiedExpressionForSelectorOrThis()
if (newElementName == OperatorNameConventions.GET.asString() && callExpression.typeArguments.isEmpty()) {
val arrayAccessExpression = KtPsiFactory(callExpression).buildExpression {
if (fullCallExpression is KtQualifiedExpression) {
appendExpression(fullCallExpression.receiverExpression)
appendFixedText(fullCallExpression.operationSign.value)
}
appendExpression(callExpression.calleeExpression)
appendFixedText("[")
appendExpressions(callExpression.valueArguments.map { it.getArgumentExpression() })
appendFixedText("]")
}
return callExpression.replace(arrayAccessExpression)
return fullCallExpression.replace(arrayAccessExpression)
}
return renameImplicitConventionalCall(newElementName)
@@ -0,0 +1,17 @@
class WInvoke {
operator fun <caret>get(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second, body: () -> Unit) { }
fun foo(s: Second) {
boo(s) {
s.testInvoke[{
"Hello"
}]
}
}
@@ -0,0 +1,17 @@
class WInvoke {
operator fun invoke(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second, body: () -> Unit) { }
fun foo(s: Second) {
boo(s) {
s.testInvoke {
"Hello"
}
}
}
@@ -0,0 +1,17 @@
class WInvoke {
operator fun <caret>get(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second?, body: () -> Unit) { }
fun foo(s: Second?) {
boo(s) {
s?.testInvoke[{
"Hello"
}]
}
}
@@ -0,0 +1,17 @@
class WInvoke {
operator fun invoke(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second?, body: () -> Unit) { }
fun foo(s: Second?) {
boo(s) {
s?.testInvoke {
"Hello"
}
}
}
@@ -0,0 +1,17 @@
class WInvoke {
operator fun <caret>invoke(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second, body: () -> Unit) { }
fun foo(s: Second) {
boo(s) {
s.testInvoke {
"Hello"
}
}
}
@@ -0,0 +1,17 @@
class WInvoke {
operator fun get(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second, body: () -> Unit) { }
fun foo(s: Second) {
boo(s) {
s.testInvoke[{
"Hello"
}]
}
}
@@ -0,0 +1,17 @@
class WInvoke {
operator fun <caret>invoke(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second?, body: () -> Unit) { }
fun foo(s: Second?) {
boo(s) {
s?.testInvoke {
"Hello"
}
}
}
@@ -0,0 +1,17 @@
class WInvoke {
operator fun get(body: () -> Unit) { }
}
class Second {
val testInvoke = WInvoke()
}
fun boo(s: Second?, body: () -> Unit) { }
fun foo(s: Second?) {
boo(s) {
s?.testInvoke[{
"Hello"
}]
}
}
@@ -94,6 +94,14 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
doTestMemberInplaceRename("get")
}
fun testInvokeToGetWithQualifiedExpr() {
doTestMemberInplaceRename("get")
}
fun testInvokeToGetWithSafeQualifiedExpr() {
doTestMemberInplaceRename("get")
}
fun testInvokeToPlus() {
doTestMemberInplaceRename("plus")
}
@@ -106,6 +114,14 @@ class InplaceRenameTest : LightPlatformCodeInsightTestCase() {
doTestMemberInplaceRename("invoke")
}
fun testGetToInvokeWithQualifiedExpr() {
doTestMemberInplaceRename("invoke")
}
fun testGetToInvokeWithSafeQualifiedExpr() {
doTestMemberInplaceRename("invoke")
}
fun testGetToPlus() {
doTestMemberInplaceRename("plus")
}