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.*
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import org.jetbrains.kotlin.resolve.DescriptorUtils 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.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.resolve.source.getPsi
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.* import java.util.*
@@ -256,8 +259,14 @@ abstract class Slicer(
val receiverPseudoValue = instruction.outputValue val receiverPseudoValue = instruction.outputValue
pseudocode.getUsages(receiverPseudoValue).forEach { receiverUseInstruction -> pseudocode.getUsages(receiverPseudoValue).forEach { receiverUseInstruction ->
if (receiverUseInstruction is KtElementInstruction) { if (receiverUseInstruction is KtElementInstruction) {
// TODO: make sure it processes correct receiver!! receiverPseudoValue.processIfReceiverValue(
receiverPseudoValue.processIfReceiverValue(receiverUseInstruction, mode) 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 receiverValue = (instruction as? InstructionWithReceivers)?.receiverValues?.get(this) ?: return false
val resolvedCall = instruction.element.resolveToCall() ?: return true val resolvedCall = instruction.element.resolveToCall() ?: return true
if (!filter(receiverValue, resolvedCall)) return true
val descriptor = resolvedCall.resultingDescriptor val descriptor = resolvedCall.resultingDescriptor
if (descriptor.isImplicitInvokeFunction()) { if (descriptor.isImplicitInvokeFunction()) {
+14 -8
View File
@@ -1,13 +1,19 @@
// FLOW: OUT // FLOW: OUT
fun Any.extensionFun(): Any { class C {
return this fun Int.outer() {
} fun String.stringExtensionFun() = this
fun Int.intExtensionFun() = this
fun C.cExtensionFun() = this
fun String.foo() { fun String.foo() {
val v = extensionFun() val string = stringExtensionFun()
} val int = intExtensionFun()
val c = cExtensionFun()
}
fun main() { fun bar() {
<caret>"A".foo() <caret>"A".foo()
}
}
} }
+7 -7
View File
@@ -1,7 +1,7 @@
12 <bold>"A"</bold>.foo() 16 <bold>"A"</bold>.foo()
7 fun <bold>String</bold>.foo() { 9 fun <bold>String</bold>.foo() {
3 fun <bold>Any</bold>.extensionFun(): Any { 5 fun <bold>String</bold>.stringExtensionFun() = this
4 return <bold>this</bold> 5 fun String.stringExtensionFun() = <bold>this</bold>
3 fun Any.<bold>extensionFun(): Any {</bold> 5 fun String.<bold>stringExtensionFun() = this</bold>
8 val v = <bold>extensionFun()</bold> 10 val string = <bold>stringExtensionFun()</bold>
8 val <bold>v = extensionFun()</bold> 10 val <bold>string = stringExtensionFun()</bold>