Processing implicit extension receiver usages in outflow processing
This commit is contained in:
@@ -153,16 +153,32 @@ class OutflowSlicer(
|
|||||||
|
|
||||||
private fun processExtensionReceiver(declaration: KtCallableDeclaration, declarationWithBody: KtDeclarationWithBody) {
|
private fun processExtensionReceiver(declaration: KtCallableDeclaration, declarationWithBody: KtDeclarationWithBody) {
|
||||||
//TODO: overriders
|
//TODO: overriders
|
||||||
//TODO: implicit receivers
|
|
||||||
val resolutionFacade = declaration.getResolutionFacade()
|
val resolutionFacade = declaration.getResolutionFacade()
|
||||||
val callableDescriptor = declaration.resolveToDescriptorIfAny(resolutionFacade) as? CallableDescriptor ?: return
|
val callableDescriptor = declaration.resolveToDescriptorIfAny(resolutionFacade) as? CallableDescriptor ?: return
|
||||||
val extensionReceiver = callableDescriptor.extensionReceiverParameter ?: return
|
val extensionReceiver = callableDescriptor.extensionReceiverParameter ?: return
|
||||||
declarationWithBody.bodyExpression?.forEachDescendantOfType<KtThisExpression> { thisExpression ->
|
val body = declarationWithBody.bodyExpression ?: return
|
||||||
|
|
||||||
|
body.forEachDescendantOfType<KtThisExpression> { thisExpression ->
|
||||||
val receiverDescriptor = thisExpression.resolveToCall(resolutionFacade)?.resultingDescriptor
|
val receiverDescriptor = thisExpression.resolveToCall(resolutionFacade)?.resultingDescriptor
|
||||||
if (receiverDescriptor == extensionReceiver) {
|
if (receiverDescriptor == extensionReceiver) {
|
||||||
thisExpression.passToProcessor()
|
thisExpression.passToProcessor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process implicit receiver usages
|
||||||
|
val pseudocode = pseudocodeCache[body]
|
||||||
|
if (pseudocode != null) {
|
||||||
|
for (instruction in pseudocode.instructions) {
|
||||||
|
if (instruction is MagicInstruction && instruction.kind == MagicKind.IMPLICIT_RECEIVER) {
|
||||||
|
val receiverPseudoValue = instruction.outputValue
|
||||||
|
pseudocode.getUsages(receiverPseudoValue).forEach { receiverUseInstruction ->
|
||||||
|
if (receiverUseInstruction is KtElementInstruction) {
|
||||||
|
processIfReceiverValue(receiverUseInstruction, receiverPseudoValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processExpression(expression: KtExpression) {
|
private fun processExpression(expression: KtExpression) {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// FLOW: OUT
|
||||||
|
|
||||||
|
fun Any.extensionFun(): Any {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.foo() {
|
||||||
|
val v = extensionFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
<caret>"A".foo()
|
||||||
|
}
|
||||||
@@ -0,0 +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>
|
||||||
@@ -583,6 +583,11 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest {
|
|||||||
runTest("idea/testData/slicer/outflow/ifExpression.kt");
|
runTest("idea/testData/slicer/outflow/ifExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("implicitReceiver.kt")
|
||||||
|
public void testImplicitReceiver() throws Exception {
|
||||||
|
runTest("idea/testData/slicer/outflow/implicitReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("indexingDereferences.kt")
|
@TestMetadata("indexingDereferences.kt")
|
||||||
public void testIndexingDereferences() throws Exception {
|
public void testIndexingDereferences() throws Exception {
|
||||||
runTest("idea/testData/slicer/outflow/indexingDereferences.kt");
|
runTest("idea/testData/slicer/outflow/indexingDereferences.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user