Inline: do more precise check before adding this@Labeled #KT-30762 Fixed

This commit is contained in:
Mikhail Glukhikh
2019-07-09 16:58:35 +03:00
parent 6605e0dfc0
commit 615aa265f5
7 changed files with 49 additions and 11 deletions
@@ -99,7 +99,7 @@ class CodeInliner<TCallElement : KtElement>(
receiver?.mark(RECEIVER_VALUE_KEY) receiver?.mark(RECEIVER_VALUE_KEY)
for (thisExpression in codeToInline.collectDescendantsOfType<KtThisExpression>()) { codeToInline.collectDescendantsOfType<KtThisExpression> { !it[CodeToInline.SIDE_RECEIVER_USAGE_KEY] }.forEach { thisExpression ->
// for this@ClassName we have only option to keep it as is (although it's sometimes incorrect but we have no other options) // for this@ClassName we have only option to keep it as is (although it's sometimes incorrect but we have no other options)
if (thisExpression.labelQualifier == null && receiver != null) { if (thisExpression.labelQualifier == null && receiver != null) {
codeToInline.replaceExpression(thisExpression, receiver) codeToInline.replaceExpression(thisExpression, receiver)
@@ -41,5 +41,6 @@ class CodeToInline(
companion object { companion object {
val PARAMETER_USAGE_KEY: Key<Name> = Key("PARAMETER_USAGE") val PARAMETER_USAGE_KEY: Key<Name> = Key("PARAMETER_USAGE")
val TYPE_PARAMETER_USAGE_KEY: Key<Name> = Key("TYPE_PARAMETER_USAGE") val TYPE_PARAMETER_USAGE_KEY: Key<Name> = Key("TYPE_PARAMETER_USAGE")
val SIDE_RECEIVER_USAGE_KEY: Key<Unit> = Key("SIDE_RECEIVER_USAGE")
} }
} }
@@ -16,10 +16,7 @@
package org.jetbrains.kotlin.idea.codeInliner package org.jetbrains.kotlin.idea.codeInliner
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.asExpression import org.jetbrains.kotlin.idea.core.asExpression
@@ -41,6 +38,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.sure
import java.util.* import java.util.*
@@ -153,7 +151,9 @@ class CodeToInlineBuilder(
} }
private fun processReferences(codeToInline: MutableCodeToInline, bindingContext: BindingContext, reformat: Boolean) { private fun processReferences(codeToInline: MutableCodeToInline, bindingContext: BindingContext, reformat: Boolean) {
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>() val receiversToAdd = ArrayList<Triple<KtExpression, KtExpression, KotlinType>>()
val targetDispatchReceiverType = targetCallable.dispatchReceiverParameter?.value?.type
val targetExtensionReceiverType = targetCallable.extensionReceiverParameter?.value?.type
codeToInline.forEachDescendantOfType<KtSimpleNameExpression> { expression -> codeToInline.forEachDescendantOfType<KtSimpleNameExpression> { expression ->
val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType
@@ -180,7 +180,7 @@ class CodeToInlineBuilder(
val resolutionScope = expression.getResolutionScope(bindingContext, resolutionFacade) val resolutionScope = expression.getResolutionScope(bindingContext, resolutionFacade)
val receiverExpression = receiver.asExpression(resolutionScope, psiFactory) val receiverExpression = receiver.asExpression(resolutionScope, psiFactory)
if (receiverExpression != null) { if (receiverExpression != null) {
receiversToAdd.add(expression to receiverExpression) receiversToAdd.add(Triple(expression, receiverExpression, receiver.type))
} }
} }
} }
@@ -188,15 +188,18 @@ class CodeToInlineBuilder(
} }
// add receivers in reverse order because arguments of a call were processed after the callee's name // add receivers in reverse order because arguments of a call were processed after the callee's name
for ((expr, receiverExpression) in receiversToAdd.asReversed()) { for ((expr, receiverExpression, receiverType) in receiversToAdd.asReversed()) {
val expressionToReplace = expr.parent as? KtCallExpression ?: expr val expressionToReplace = expr.parent as? KtCallExpression ?: expr
codeToInline.replaceExpression( val replaced = codeToInline.replaceExpression(
expressionToReplace, expressionToReplace,
psiFactory.createExpressionByPattern( psiFactory.createExpressionByPattern(
"$0.$1", receiverExpression, expressionToReplace, "$0.$1", receiverExpression, expressionToReplace,
reformat = reformat reformat = reformat
) )
) ) as? KtQualifiedExpression
if (receiverType != targetDispatchReceiverType && receiverType != targetExtensionReceiverType) {
replaced?.receiverExpression?.putCopyableUserData(CodeToInline.SIDE_RECEIVER_USAGE_KEY, Unit)
}
} }
} }
} }
+15
View File
@@ -0,0 +1,15 @@
interface MySeq<T> {
fun yield(arg: T)
}
fun <T> mySeq(f: MySeq<T>.() -> Unit): MySeq<T> = null!!
class Test {
fun repro() = mySeq<Int> {
inner()
}
private fun <caret>inner() = mySeq<Double> {
yield(1.0)
}
}
@@ -0,0 +1,14 @@
interface MySeq<T> {
fun yield(arg: T)
}
fun <T> mySeq(f: MySeq<T>.() -> Unit): MySeq<T> = null!!
class Test {
fun repro() = mySeq<Int> {
mySeq<Double> {
yield(1.0)
}
}
}
@@ -11,7 +11,7 @@ internal object Bar {
@JvmStatic fun main(args: Array<String>) { @JvmStatic fun main(args: Array<String>) {
bar(object : Runnable { bar(object : Runnable {
override fun run() { override fun run() {
Foo.doRun() doRun()
} }
private fun doRun() { private fun doRun() {
@@ -86,6 +86,11 @@ public class InlineTestGenerated extends AbstractInlineTest {
runTest("idea/testData/refactoring/inline/function/ReturnNotInTheEnd.kt"); runTest("idea/testData/refactoring/inline/function/ReturnNotInTheEnd.kt");
} }
@TestMetadata("Sequence.kt")
public void testSequence() throws Exception {
runTest("idea/testData/refactoring/inline/function/Sequence.kt");
}
@TestMetadata("UnitReturnType.kt") @TestMetadata("UnitReturnType.kt")
public void testUnitReturnType() throws Exception { public void testUnitReturnType() throws Exception {
runTest("idea/testData/refactoring/inline/function/UnitReturnType.kt"); runTest("idea/testData/refactoring/inline/function/UnitReturnType.kt");