diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt index 6588b82c219..ec3185845b5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt @@ -38,7 +38,10 @@ import org.jetbrains.kotlin.idea.util.isExpectDeclaration import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +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 java.util.* @@ -256,8 +259,14 @@ abstract class Slicer( val receiverPseudoValue = instruction.outputValue pseudocode.getUsages(receiverPseudoValue).forEach { receiverUseInstruction -> if (receiverUseInstruction is KtElementInstruction) { - // TODO: make sure it processes correct receiver!! - receiverPseudoValue.processIfReceiverValue(receiverUseInstruction, mode) + receiverPseudoValue.processIfReceiverValue( + receiverUseInstruction, + mode, + filter = { receiverValue, resolvedCall -> + receiverValue == resolvedCall.extensionReceiver && + (receiverValue as? ImplicitReceiver)?.declarationDescriptor == callableDescriptor + } + ) } } } @@ -265,9 +274,15 @@ abstract class Slicer( } } - protected fun PseudoValue.processIfReceiverValue(instruction: KtElementInstruction, mode: KotlinSliceAnalysisMode): Boolean { + protected fun PseudoValue.processIfReceiverValue( + instruction: KtElementInstruction, + mode: KotlinSliceAnalysisMode, + filter: (ReceiverValue, ResolvedCall) -> Boolean = { _, _ -> true } + ): Boolean { val receiverValue = (instruction as? InstructionWithReceivers)?.receiverValues?.get(this) ?: return false val resolvedCall = instruction.element.resolveToCall() ?: return true + if (!filter(receiverValue, resolvedCall)) return true + val descriptor = resolvedCall.resultingDescriptor if (descriptor.isImplicitInvokeFunction()) { diff --git a/idea/testData/slicer/outflow/implicitReceiver.kt b/idea/testData/slicer/outflow/implicitReceiver.kt index a47eaef831f..08f3c79f5c7 100644 --- a/idea/testData/slicer/outflow/implicitReceiver.kt +++ b/idea/testData/slicer/outflow/implicitReceiver.kt @@ -1,13 +1,19 @@ // FLOW: OUT -fun Any.extensionFun(): Any { - return this -} +class C { + fun Int.outer() { + fun String.stringExtensionFun() = this + fun Int.intExtensionFun() = this + fun C.cExtensionFun() = this -fun String.foo() { - val v = extensionFun() -} + fun String.foo() { + val string = stringExtensionFun() + val int = intExtensionFun() + val c = cExtensionFun() + } -fun main() { - "A".foo() + fun bar() { + "A".foo() + } + } } diff --git a/idea/testData/slicer/outflow/implicitReceiver.results.txt b/idea/testData/slicer/outflow/implicitReceiver.results.txt index f8b80bc6114..bdf746def21 100644 --- a/idea/testData/slicer/outflow/implicitReceiver.results.txt +++ b/idea/testData/slicer/outflow/implicitReceiver.results.txt @@ -1,7 +1,7 @@ -12 "A".foo() -7 fun String.foo() { -3 fun Any.extensionFun(): Any { -4 return this -3 fun Any.extensionFun(): Any { -8 val v = extensionFun() -8 val v = extensionFun() +16 "A".foo() +9 fun String.foo() { +5 fun String.stringExtensionFun() = this +5 fun String.stringExtensionFun() = this +5 fun String.stringExtensionFun() = this +10 val string = stringExtensionFun() +10 val string = stringExtensionFun()