Process only correct implicit receivers

This commit is contained in:
Valentin Kipyatkov
2020-04-12 21:03:14 +03:00
parent fdfae5260f
commit e4d9801388
3 changed files with 39 additions and 18 deletions
@@ -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<out CallableDescriptor>) -> 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()) {
+14 -8
View File
@@ -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() {
<caret>"A".foo()
fun bar() {
<caret>"A".foo()
}
}
}
+7 -7
View File
@@ -1,7 +1,7 @@
12 <bold>"A"</bold>.foo()
7 fun <bold>String</bold>.foo() {
3 fun <bold>Any</bold>.extensionFun(): Any {
4 return <bold>this</bold>
3 fun Any.<bold>extensionFun(): Any {</bold>
8 val v = <bold>extensionFun()</bold>
8 val <bold>v = extensionFun()</bold>
16 <bold>"A"</bold>.foo()
9 fun <bold>String</bold>.foo() {
5 fun <bold>String</bold>.stringExtensionFun() = this
5 fun String.stringExtensionFun() = <bold>this</bold>
5 fun String.<bold>stringExtensionFun() = this</bold>
10 val string = <bold>stringExtensionFun()</bold>
10 val <bold>string = stringExtensionFun()</bold>