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)
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)
if (thisExpression.labelQualifier == null && receiver != null) {
codeToInline.replaceExpression(thisExpression, receiver)
@@ -41,5 +41,6 @@ class CodeToInline(
companion object {
val PARAMETER_USAGE_KEY: Key<Name> = Key("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
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
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.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.sure
import java.util.*
@@ -153,7 +151,9 @@ class CodeToInlineBuilder(
}
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 ->
val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType
@@ -180,7 +180,7 @@ class CodeToInlineBuilder(
val resolutionScope = expression.getResolutionScope(bindingContext, resolutionFacade)
val receiverExpression = receiver.asExpression(resolutionScope, psiFactory)
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
for ((expr, receiverExpression) in receiversToAdd.asReversed()) {
for ((expr, receiverExpression, receiverType) in receiversToAdd.asReversed()) {
val expressionToReplace = expr.parent as? KtCallExpression ?: expr
codeToInline.replaceExpression(
val replaced = codeToInline.replaceExpression(
expressionToReplace,
psiFactory.createExpressionByPattern(
"$0.$1", receiverExpression, expressionToReplace,
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>) {
bar(object : Runnable {
override fun run() {
Foo.doRun()
doRun()
}
private fun doRun() {
@@ -86,6 +86,11 @@ public class InlineTestGenerated extends AbstractInlineTest {
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")
public void testUnitReturnType() throws Exception {
runTest("idea/testData/refactoring/inline/function/UnitReturnType.kt");