Fix for 'this' expression call

Original commit: e31eac16adaf47ae5bf5af870e08f06abb29b333

GitOrigin-RevId: 12b8394048b87f6cf4f3898da2bf08c095fd47cf
This commit is contained in:
Toshiaki Kameyama
2021-04-13 21:29:13 +03:00
committed by intellij-monorepo-bot
parent 8e7c876180
commit dd8af0b030
7 changed files with 98 additions and 9 deletions
@@ -71,8 +71,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -403,6 +405,33 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
}
}
private fun processThisCall(
expression: KtSimpleNameExpression,
context: BindingContext,
extensionReceiver: ReceiverValue?,
dispatchReceiver: ReceiverValue?
) {
val thisExpression = expression.parent as? KtThisExpression ?: return
val thisCallExpression = thisExpression.parent as? KtCallExpression ?: return
val usageInfo = when (callableDescriptor) {
dispatchReceiver.getReceiverTargetDescriptor(context) -> {
val extensionReceiverTargetDescriptor = extensionReceiver.getReceiverTargetDescriptor(context)
if (extensionReceiverTargetDescriptor != null) {
KotlinNonQualifiedOuterThisCallUsage(
thisCallExpression, originalReceiverInfo!!, functionUsageInfo, extensionReceiverTargetDescriptor
)
} else {
KotlinParameterUsage(expression, originalReceiverInfo!!, functionUsageInfo)
}
}
extensionReceiver.getReceiverTargetDescriptor(context) -> {
KotlinParameterUsage(expression, originalReceiverInfo!!, functionUsageInfo)
}
else -> null
}
result.addIfNotNull(usageInfo)
}
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, context: BindingContext): Void? {
val resolvedCall = expression.getResolvedCall(context) ?: return null
@@ -412,11 +441,16 @@ class KotlinChangeSignatureUsageProcessor : ChangeSignatureUsageProcessor {
return null
}
val receiverValue = resolvedCall
val (extensionReceiver, dispatchReceiver) = resolvedCall
.let { (it as? VariableAsFunctionResolvedCall)?.variableCall ?: it }
.let { it.extensionReceiver ?: it.dispatchReceiver }
if (receiverValue is ImplicitReceiver) {
processImplicitThis(resolvedCall.call.callElement, receiverValue)
.let { (it.extensionReceiver to it.dispatchReceiver) }
if (extensionReceiver != null || dispatchReceiver != null) {
val receiverValue = extensionReceiver ?: dispatchReceiver
if (receiverValue is ImplicitReceiver) {
processImplicitThis(resolvedCall.call.callElement, receiverValue)
} else {
processThisCall(expression, context, extensionReceiver, dispatchReceiver)
}
}
return null
@@ -11,10 +11,8 @@ import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.core.ShortenReferences.Options
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeInfo
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinParameterInfo
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtQualifiedExpression
import org.jetbrains.kotlin.psi.KtThisExpression
import org.jetbrains.kotlin.idea.refactoring.explicateAsTextForReceiver
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
// Explicit reference to function parameter or outer this
@@ -63,4 +61,18 @@ class KotlinNonQualifiedOuterThisUsage(
}
override fun getReplacementText(changeInfo: KotlinChangeInfo): String = "this@${targetDescriptor.name.asString()}"
}
}
class KotlinNonQualifiedOuterThisCallUsage(
element: KtCallExpression,
val parameterInfo: KotlinParameterInfo,
val containingCallable: KotlinCallableDefinitionUsage<*>,
val targetDescriptor: DeclarationDescriptor
) : KotlinExplicitReferenceUsage<KtCallExpression>(element) {
override fun getReplacementText(changeInfo: KotlinChangeInfo): String {
val inheritedName = parameterInfo.getInheritedName(containingCallable)
val receiver = targetDescriptor.explicateAsTextForReceiver()
element?.calleeExpression?.replace(KtPsiFactory(changeInfo.context).createExpression(receiver))
return "with($inheritedName) $inheritedName@{ ${element?.text} }"
}
}
@@ -6454,6 +6454,11 @@ public abstract class IntentionTestGenerated extends AbstractIntentionTest {
runTest("testData/intentions/convertReceiverToParameter/replaceThis.kt");
}
@TestMetadata("thisCall.kt")
public void testThisCall() throws Exception {
runTest("testData/intentions/convertReceiverToParameter/thisCall.kt");
}
@TestMetadata("topLevelFun.kt")
public void testTopLevelFun() throws Exception {
runTest("testData/intentions/convertReceiverToParameter/topLevelFun.kt");
@@ -9,6 +9,8 @@ class User(
val callableLambda: () -> Unit = {}
fun checkName() = Unit
operator fun invoke() = Unit
}
fun <caret>User.extFun() {
@@ -16,4 +18,5 @@ fun <caret>User.extFun() {
checkName()
callableLambda()
callableObject()
this()
}
@@ -9,6 +9,8 @@ class User(
val callableLambda: () -> Unit = {}
fun checkName() = Unit
operator fun invoke() = Unit
}
fun extFun(user: User) {
@@ -16,4 +18,5 @@ fun extFun(user: User) {
user.checkName()
user.callableLambda()
user.callableObject()
user()
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
class CallableObject {
operator fun User.invoke() = println("User.invoke")
}
class User {
operator fun CallableObject.invoke() = println("CallableObject.invoke")
}
fun <caret>User.extFun() {
val callableObject = CallableObject()
with(callableObject) {
this()
this@extFun()
}
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
class CallableObject {
operator fun User.invoke() = println("User.invoke")
}
class User {
operator fun CallableObject.invoke() = println("CallableObject.invoke")
}
fun extFun(user: User) {
val callableObject = CallableObject()
with(callableObject) {
with(user) user@{ this@with() }
user()
}
}