Tracking inflow of lambda receiver
This commit is contained in:
@@ -179,10 +179,17 @@ class InflowSlicer(
|
||||
}
|
||||
|
||||
is ReceiverParameterDescriptor -> {
|
||||
//TODO: handle non-extension receivers?
|
||||
val callable = accessedDescriptor.containingDeclaration as? CallableDescriptor ?: return
|
||||
val callableDeclaration = callable.originalSource.getPsi() as? KtCallableDeclaration ?: return
|
||||
//TODO: what about non-extensions?
|
||||
callableDeclaration.receiverTypeReference?.passToProcessor()
|
||||
when (val declaration = callable.originalSource.getPsi()) {
|
||||
is KtFunctionLiteral -> {
|
||||
declaration.passToProcessorAsValue(LambdaCallsBehaviour(ReceiverSliceProducer, behaviour))
|
||||
}
|
||||
|
||||
is KtCallableDeclaration -> {
|
||||
declaration.receiverTypeReference?.passToProcessor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is ValueParameterDescriptor -> {
|
||||
|
||||
@@ -150,17 +150,12 @@ class OutflowSlicer(
|
||||
}
|
||||
|
||||
private fun processFunction(function: KtFunction) {
|
||||
//TODO: CallSliceProducer in all cases
|
||||
if (function is KtConstructor<*> || function is KtNamedFunction && function.name != null) {
|
||||
processCalls(function, includeOverriders = false, sliceProducer = CallSliceProducer)
|
||||
return
|
||||
} else {
|
||||
processCalls(function, false, SliceProducer.Trivial)
|
||||
}
|
||||
|
||||
val funExpression = when (function) {
|
||||
is KtFunctionLiteral -> function.parent as? KtLambdaExpression
|
||||
is KtNamedFunction -> function
|
||||
else -> null
|
||||
} ?: return
|
||||
funExpression.passToProcessor(LambdaCallsBehaviour(SliceProducer.Trivial, behaviour), forcedExpressionMode = true)
|
||||
}
|
||||
|
||||
private fun processExtensionReceiver(declaration: KtCallableDeclaration, declarationWithBody: KtDeclarationWithBody) {
|
||||
@@ -178,7 +173,11 @@ class OutflowSlicer(
|
||||
}
|
||||
|
||||
private fun processExpression(expression: KtExpression) {
|
||||
expression.processPseudocodeUsages { pseudoValue, instruction ->
|
||||
val expressionWithValue = when (expression) {
|
||||
is KtFunctionLiteral -> expression.parent as KtLambdaExpression
|
||||
else -> expression
|
||||
}
|
||||
expressionWithValue.processPseudocodeUsages { pseudoValue, instruction ->
|
||||
when (instruction) {
|
||||
is WriteValueInstruction -> {
|
||||
if (!processIfReceiverValue(instruction, pseudoValue)) {
|
||||
|
||||
@@ -73,12 +73,7 @@ abstract class Slicer(
|
||||
includeOverriders: Boolean,
|
||||
sliceProducer: SliceProducer
|
||||
) {
|
||||
if (callable is KtFunctionLiteral) {
|
||||
(callable.parent as KtLambdaExpression).passToProcessorAsValue(LambdaCallsBehaviour(sliceProducer, behaviour))
|
||||
return
|
||||
}
|
||||
|
||||
if (callable is KtFunction && callable.name == null) {
|
||||
if (callable is KtFunctionLiteral || callable is KtFunction && callable.name == null) {
|
||||
callable.passToProcessorAsValue(LambdaCallsBehaviour(sliceProducer, behaviour))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// FLOW: IN
|
||||
|
||||
fun foo() {
|
||||
with("A") {
|
||||
val <caret>v = this
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
|
||||
return receiver.block()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
4 with(<bold>"A"</bold>) {
|
||||
5 val <bold>v = this</bold>
|
||||
5 val v = <bold>this</bold>
|
||||
4 [LAMBDA OUT] with("A") <bold>{</bold>
|
||||
9 [LAMBDA OUT] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||
10 return <bold>receiver</bold>.block()
|
||||
9 inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||
4 with(<bold>"A"</bold>) {
|
||||
@@ -0,0 +1,3 @@
|
||||
[NotNull Values]
|
||||
5 val <bold>v = this</bold>
|
||||
5 val <bold>v = this</bold>
|
||||
@@ -0,0 +1,7 @@
|
||||
5 val <bold>v = this</bold>
|
||||
5 val v = <bold>this</bold>
|
||||
4 [LAMBDA OUT] with("A") <bold>{</bold>
|
||||
9 [LAMBDA OUT] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||
10 return <bold>receiver</bold>.block()
|
||||
9 inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||
4 with(<bold>"A"</bold>) {
|
||||
+5
@@ -118,6 +118,11 @@ public class SlicerLeafGroupingTestGenerated extends AbstractSlicerLeafGroupingT
|
||||
runTest("idea/testData/slicer/inflow/extensionLambdaParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionLambdaReceiver.kt")
|
||||
public void testExtensionLambdaReceiver() throws Exception {
|
||||
runTest("idea/testData/slicer/inflow/extensionLambdaReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funParamerer.kt")
|
||||
public void testFunParamerer() throws Exception {
|
||||
runTest("idea/testData/slicer/inflow/funParamerer.kt");
|
||||
|
||||
+5
@@ -118,6 +118,11 @@ public class SlicerNullnessGroupingTestGenerated extends AbstractSlicerNullnessG
|
||||
runTest("idea/testData/slicer/inflow/extensionLambdaParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionLambdaReceiver.kt")
|
||||
public void testExtensionLambdaReceiver() throws Exception {
|
||||
runTest("idea/testData/slicer/inflow/extensionLambdaReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funParamerer.kt")
|
||||
public void testFunParamerer() throws Exception {
|
||||
runTest("idea/testData/slicer/inflow/funParamerer.kt");
|
||||
|
||||
@@ -130,6 +130,11 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest {
|
||||
runTest("idea/testData/slicer/inflow/extensionLambdaParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionLambdaReceiver.kt")
|
||||
public void testExtensionLambdaReceiver() throws Exception {
|
||||
runTest("idea/testData/slicer/inflow/extensionLambdaReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("funParamerer.kt")
|
||||
public void testFunParamerer() throws Exception {
|
||||
runTest("idea/testData/slicer/inflow/funParamerer.kt");
|
||||
|
||||
Reference in New Issue
Block a user