diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt index d48b869c400..e53d4144857 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt @@ -140,19 +140,26 @@ class InflowSlicer( } val currentBehaviour = mode.currentBehaviour if (lambda != null) { - if (currentBehaviour is LambdaResultInflowBehaviour) { - lambda.passToProcessor(mode.dropBehaviour()) - } - else if (currentBehaviour is LambdaArgumentInflowBehaviour) { - val valueParameters = lambda.valueParameters - if (valueParameters.isEmpty() && lambda is KtFunctionLiteral) { - if (currentBehaviour.argumentIndex == 0) { - lambda.implicitItUsages().forEach { - it.passToProcessor(mode.dropBehaviour()) + when (currentBehaviour) { + is LambdaResultInflowBehaviour -> { + lambda.passToProcessor(mode.dropBehaviour()) + } + + is LambdaArgumentInflowBehaviour -> { + val valueParameters = lambda.valueParameters + if (valueParameters.isEmpty() && lambda is KtFunctionLiteral) { + if (currentBehaviour.argumentIndex == 0) { + lambda.implicitItUsages().forEach { + it.passToProcessor(mode.dropBehaviour()) + } } + } else { + valueParameters.getOrNull(currentBehaviour.argumentIndex)?.passToProcessor(mode.dropBehaviour()) } - } else { - valueParameters.getOrNull(currentBehaviour.argumentIndex)?.passToProcessor(mode.dropBehaviour()) + } + + is LambdaReceiverInflowBehaviour -> { + processExtensionReceiverUsages(lambda, lambda, mode.dropBehaviour()) } } return diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaCallsBehaviour.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaCallsBehaviour.kt index 1b93e1d1514..d9e0d26a894 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaCallsBehaviour.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaCallsBehaviour.kt @@ -9,7 +9,6 @@ import com.intellij.slicer.SliceUsage import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor -import org.jetbrains.kotlin.psi.Call import org.jetbrains.kotlin.psi.KtElement data class LambdaCallsBehaviour(private val sliceProducer: SliceProducer) : KotlinSliceAnalysisMode.Behaviour { @@ -19,7 +18,7 @@ data class LambdaCallsBehaviour(private val sliceProducer: SliceProducer) : Kotl if (sliceUsage is KotlinSliceUsage && sliceUsage.mode.currentBehaviour === this@LambdaCallsBehaviour) { val sliceElement = sliceUsage.element ?: return true val resolvedCall = (sliceElement as? KtElement)?.resolveToCall() - if (resolvedCall?.call?.callType == Call.CallType.INVOKE) { + if (resolvedCall != null && resolvedCall.resultingDescriptor.isImplicitInvokeFunction()) { val originalMode = sliceUsage.mode.dropBehaviour() val newSliceUsage = KotlinSliceUsage(resolvedCall.call.callElement, parent, originalMode, true) return sliceProducer.produceAndProcess(newSliceUsage, originalMode, parent, uniqueProcessor) diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaReceiverInflowBehaviour.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaReceiverInflowBehaviour.kt new file mode 100644 index 00000000000..5bfc5907de6 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaReceiverInflowBehaviour.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.slicer + +import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor +import org.jetbrains.kotlin.psi.KtElement + +object LambdaReceiverInflowBehaviour : KotlinSliceAnalysisMode.Behaviour { + override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) { + InflowSlicer(element, uniqueProcessor, parent).processChildren(parent.forcedExpressionMode) + } + + override val slicePresentationPrefix: String + get() = TODO() + + override val testPresentationPrefix: String + get() = "[LAMBDA RECEIVER IN] " + + override fun equals(other: Any?) = other === this + override fun hashCode() = 0 +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt index 889fb75eec0..e6318968da4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt @@ -10,15 +10,11 @@ import com.intellij.psi.PsiMethod import com.intellij.usageView.UsageInfo import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction -import org.jetbrains.kotlin.cfg.pseudocode.instructions.KtElementInstruction import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction -import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingElement @@ -26,11 +22,9 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDete import org.jetbrains.kotlin.idea.util.actualsForExpected import org.jetbrains.kotlin.idea.util.isExpectDeclaration import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.parameterIndex import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.source.getPsi -import org.jetbrains.kotlin.util.OperatorNameConventions class OutflowSlicer( element: KtElement, @@ -73,13 +67,13 @@ class OutflowSlicer( when (declaration) { is KtFunction -> { - processExtensionReceiver(declaration, declaration) + processExtensionReceiverUsages(declaration, declaration.bodyExpression, mode) } is KtProperty -> { //TODO: process only one of them or both depending on the usage type - declaration.getter?.let { processExtensionReceiver(declaration, it) } - declaration.setter?.let { processExtensionReceiver(declaration, it) } + processExtensionReceiverUsages(declaration, declaration.getter?.bodyExpression, mode) + processExtensionReceiverUsages(declaration, declaration.setter?.bodyExpression, mode) } } } @@ -154,36 +148,6 @@ class OutflowSlicer( processCalls(function, includeOverriders = false, CallSliceProducer) } - private fun processExtensionReceiver(declaration: KtCallableDeclaration, declarationWithBody: KtDeclarationWithBody) { - //TODO: overriders - val resolutionFacade = declaration.getResolutionFacade() - val callableDescriptor = declaration.resolveToDescriptorIfAny(resolutionFacade) as? CallableDescriptor ?: return - val extensionReceiver = callableDescriptor.extensionReceiverParameter ?: return - val body = declarationWithBody.bodyExpression ?: return - - body.forEachDescendantOfType { thisExpression -> - val receiverDescriptor = thisExpression.resolveToCall(resolutionFacade)?.resultingDescriptor - if (receiverDescriptor == extensionReceiver) { - 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) { val expressionWithValue = when (expression) { is KtFunctionLiteral -> expression.parent as KtLambdaExpression @@ -192,24 +156,24 @@ class OutflowSlicer( expressionWithValue.processPseudocodeUsages { pseudoValue, instruction -> when (instruction) { is WriteValueInstruction -> { - if (!processIfReceiverValue(instruction, pseudoValue)) { + if (!processIfReceiverValue(instruction, pseudoValue, mode)) { instruction.target.accessedDescriptor?.originalSource?.getPsi()?.passToProcessor() } } is ReadValueInstruction -> { - processIfReceiverValue(instruction, pseudoValue) + processIfReceiverValue(instruction, pseudoValue, mode) } is CallInstruction -> { - if (!processIfReceiverValue(instruction, pseudoValue)) { + if (!processIfReceiverValue(instruction, pseudoValue, mode)) { val parameterDescriptor = instruction.arguments[pseudoValue] ?: return@processPseudocodeUsages val parameter = parameterDescriptor.originalSource.getPsi() if (parameter != null) { parameter.passToProcessorInCallMode(instruction.element) } else { - val function = parameterDescriptor.containingDeclaration as? FunctionDescriptor - if (function != null && function.isOperator && function.name == OperatorNameConventions.INVOKE) { + val function = parameterDescriptor.containingDeclaration as? FunctionDescriptor ?: return@processPseudocodeUsages + if (function.isImplicitInvokeFunction()) { val receiverPseudoValue = instruction.receiverValues.entries.singleOrNull()?.key ?: return@processPseudocodeUsages if (receiverPseudoValue.createdAt != null) { @@ -256,30 +220,6 @@ class OutflowSlicer( } } - private fun processIfReceiverValue(instruction: KtElementInstruction, pseudoValue: PseudoValue): Boolean { - val receiverValue = (instruction as? InstructionWithReceivers)?.receiverValues?.get(pseudoValue) ?: return false - val resolvedCall = instruction.element.resolveToCall() ?: return true - when (resolvedCall.call.callType) { - Call.CallType.DEFAULT -> { - if (receiverValue == resolvedCall.extensionReceiver) { - val targetDeclaration = resolvedCall.resultingDescriptor.originalSource.getPsi() - (targetDeclaration as? KtCallableDeclaration)?.receiverTypeReference?.passToProcessorInCallMode(instruction.element) - } - } - - Call.CallType.INVOKE -> { - if (receiverValue == resolvedCall.dispatchReceiver && mode.currentBehaviour is LambdaCallsBehaviour) { - instruction.element.passToProcessor() - } - } - - else -> { - //TODO - } - } - return true - } - private fun processDereferenceIfNeeded( expression: KtExpression, pseudoValue: PseudoValue, diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt index 127ef32786e..ed223501bb6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt @@ -12,13 +12,16 @@ import com.intellij.slicer.JavaSliceUsage import com.intellij.usageView.UsageInfo import com.intellij.util.containers.addIfNotNull import org.jetbrains.kotlin.asJava.namedUnwrappedElement +import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode import org.jetbrains.kotlin.cfg.pseudocode.getContainingPseudocode -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource -import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.cfg.pseudocode.instructions.KtElementInstruction +import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions @@ -33,9 +36,11 @@ import org.jetbrains.kotlin.idea.util.expectedDescriptor import org.jetbrains.kotlin.idea.util.hasInlineModifier 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.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.source.getPsi +import org.jetbrains.kotlin.util.OperatorNameConventions import java.util.* abstract class Slicer( @@ -71,17 +76,21 @@ abstract class Slicer( processor.process(KotlinSliceUsage(this, parentUsage, mode, forcedExpressionMode = true)) } - protected fun PsiElement.passToProcessorInCallMode(callElement: KtElement, withOverriders: Boolean = false) { + protected fun PsiElement.passToProcessorInCallMode( + callElement: KtElement, + mode: KotlinSliceAnalysisMode = this@Slicer.mode, + withOverriders: Boolean = false + ) { val newMode = when (this) { - is KtNamedFunction -> this.callMode(callElement) + is KtNamedFunction -> this.callMode(callElement, mode) - is KtParameter -> ownerFunction.callMode(callElement) + is KtParameter -> ownerFunction.callMode(callElement, mode) is KtTypeReference -> { val declaration = parent require(declaration is KtCallableDeclaration) require(this == declaration.receiverTypeReference) - declaration.callMode(callElement) + declaration.callMode(callElement, mode) } else -> mode @@ -110,13 +119,6 @@ abstract class Slicer( } } - protected fun KtDeclaration?.callMode(callElement: KtElement): KotlinSliceAnalysisMode { - return if (this is KtNamedFunction && hasInlineModifier()) - mode.withInlineFunctionCall(callElement, this) - else - mode - } - protected open fun processCalls( callable: KtCallableDeclaration, includeOverriders: Boolean, @@ -227,6 +229,98 @@ abstract class Slicer( } protected fun canProcessParameter(parameter: KtParameter) = !parameter.isVarArg + + protected fun processExtensionReceiverUsages( + declaration: KtCallableDeclaration, + body: KtExpression?, + mode: KotlinSliceAnalysisMode, + ) { + if (body == null) return + //TODO: overriders + val resolutionFacade = declaration.getResolutionFacade() + val callableDescriptor = declaration.resolveToDescriptorIfAny(resolutionFacade) as? CallableDescriptor ?: return + val extensionReceiver = callableDescriptor.extensionReceiverParameter ?: return + + body.forEachDescendantOfType { thisExpression -> + val receiverDescriptor = thisExpression.resolveToCall(resolutionFacade)?.resultingDescriptor + if (receiverDescriptor == extensionReceiver) { + thisExpression.passToProcessor(mode) + } + } + + // 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) { + // TODO: make sure it processes correct receiver!! + processIfReceiverValue(receiverUseInstruction, receiverPseudoValue, mode) + } + } + } + } + } + } + + protected fun processIfReceiverValue( + instruction: KtElementInstruction, + receiverPseudoValue: PseudoValue, + mode: KotlinSliceAnalysisMode, + ): Boolean { + val receiverValue = (instruction as? InstructionWithReceivers)?.receiverValues?.get(receiverPseudoValue) ?: return false + val resolvedCall = instruction.element.resolveToCall() ?: return true + val descriptor = resolvedCall.resultingDescriptor + + if (descriptor.isImplicitInvokeFunction()) { + when (receiverValue) { + resolvedCall.dispatchReceiver -> { + if (mode.currentBehaviour is LambdaCallsBehaviour) { + instruction.element.passToProcessor(mode) + } + } + + resolvedCall.extensionReceiver -> { + val dispatchReceiver = resolvedCall.dispatchReceiver ?: return true + val dispatchReceiverPseudoValue = instruction.receiverValues.entries + .singleOrNull { it.value == dispatchReceiver }?.key + ?: return true + if (dispatchReceiverPseudoValue.createdAt != null) { + when (val createdAt = dispatchReceiverPseudoValue.createdAt) { + is ReadValueInstruction -> { + val accessedDescriptor = createdAt.target.accessedDescriptor ?: return true + val accessedDeclaration = accessedDescriptor.originalSource.getPsi() ?: return true + when (accessedDescriptor) { + is ValueParameterDescriptor -> { + accessedDeclaration.passToProcessor(mode.withBehaviour(LambdaReceiverInflowBehaviour)) + } + } + } + } + } + } + } + } else { + if (receiverValue == resolvedCall.extensionReceiver) { + val declaration = descriptor.originalSource.getPsi() + (declaration as? KtCallableDeclaration)?.receiverTypeReference?.passToProcessorInCallMode(instruction.element, mode) + } + } + + + return true + } + + companion object { + protected fun KtDeclaration?.callMode(callElement: KtElement, defaultMode: KotlinSliceAnalysisMode): KotlinSliceAnalysisMode { + return if (this is KtNamedFunction && hasInlineModifier()) + defaultMode.withInlineFunctionCall(callElement, this) + else + defaultMode + } + } } val DeclarationDescriptorWithSource.originalSource: SourceElement @@ -238,3 +332,9 @@ val DeclarationDescriptorWithSource.originalSource: SourceElement return descriptor.source } +fun CallableDescriptor.isImplicitInvokeFunction(): Boolean { + if (this !is FunctionDescriptor) return false + if (!isOperator) return false + if (name != OperatorNameConventions.INVOKE) return false + return originalSource.getPsi() == null +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/extensionIndexingDereferences.results.txt b/idea/testData/slicer/outflow/extensionIndexingDereferences.results.txt index 6497719d948..8fc37514958 100644 --- a/idea/testData/slicer/outflow/extensionIndexingDereferences.results.txt +++ b/idea/testData/slicer/outflow/extensionIndexingDereferences.results.txt @@ -1,6 +1,26 @@ 15 val x = A() 18 x[1] +6 operator fun A.get(i: Int) = this +6 operator fun A.get(i: Int) = this +6 operator fun A.get(i: Int) = this +18 x[1] +20 x[1] += y +8 operator fun A.plusAssign(a: A) { +9 val v = this +9 val v = this +21 x[1] *= y +11 operator fun A.times(a: A) = this +11 operator fun A.times(a: A) = this +11 operator fun A.times(a: A) = this +21 x[1] *= y +22 x[1]++ +12 operator fun A.inc() = this +12 operator fun A.inc() = this +12 operator fun A.inc() = this +22 x[1]++ +12 DUPLICATE: operator fun A.inc() = this 19 x[1] = y 20 x[1] += y +6 DUPLICATE: operator fun A.get(i: Int) = this 21 x[1] *= y 22 x[1]++ diff --git a/idea/testData/slicer/outflow/lambdaResultWithInvokeCall.kt b/idea/testData/slicer/outflow/lambdaResultWithInvokeCall.kt new file mode 100644 index 00000000000..fa77838ccde --- /dev/null +++ b/idea/testData/slicer/outflow/lambdaResultWithInvokeCall.kt @@ -0,0 +1,9 @@ +// FLOW: OUT + +fun test() { + val x = foo { 1 } +} + +fun foo(callback: () -> Int): Int { + return callback.invoke() +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/lambdaResultWithInvokeCall.results.txt b/idea/testData/slicer/outflow/lambdaResultWithInvokeCall.results.txt new file mode 100644 index 00000000000..7c633e70c0d --- /dev/null +++ b/idea/testData/slicer/outflow/lambdaResultWithInvokeCall.results.txt @@ -0,0 +1,9 @@ +4 val x = foo { 1 } +4 val x = foo { 1 } +4 [LAMBDA CALLS] val x = foo { 1 } +7 [LAMBDA CALLS] fun foo(callback: () -> Int): Int { +8 [LAMBDA CALLS] return callback.invoke() +8 return callback.invoke() +7 fun foo(callback: () -> Int): Int { +4 val x = foo { 1 } +4 val x = foo { 1 } diff --git a/idea/testData/slicer/outflow/withResult.kt b/idea/testData/slicer/outflow/withResult.kt new file mode 100644 index 00000000000..573cdf4dd0d --- /dev/null +++ b/idea/testData/slicer/outflow/withResult.kt @@ -0,0 +1,15 @@ +// FLOW: OUT + +fun String.foo(p: String) { + val v1 = with(p) { this } + + val v2 = with(p) { bar(this) } + + val v3 = with(p) { this@foo } +} + +fun bar(s: String) = s + +inline fun with(receiver: T, block: T.() -> R): R { + return receiver.block() +} diff --git a/idea/testData/slicer/outflow/withResult.results.txt b/idea/testData/slicer/outflow/withResult.results.txt new file mode 100644 index 00000000000..76b1c366dc1 --- /dev/null +++ b/idea/testData/slicer/outflow/withResult.results.txt @@ -0,0 +1,34 @@ +3 fun String.foo(p: String) { +4 val v1 = with(p) { this } +13 (INLINE CALL with) inline fun with(receiver: T, block: T.() -> R): R { +14 (INLINE CALL with) return receiver.block() +13 (INLINE CALL with) [LAMBDA RECEIVER IN] inline fun with(receiver: T, block: T.() -> R): R { +4 [LAMBDA RECEIVER IN] val v1 = with(p) { this } +4 val v1 = with(p) { this } +4 val v1 = with(p) { this } +4 [LAMBDA CALLS] val v1 = with(p) { this } +13 (INLINE CALL with) [LAMBDA CALLS] inline fun with(receiver: T, block: T.() -> R): R { +14 (INLINE CALL with) return receiver.block() +4 val v1 = with(p) { this } +4 val v1 = with(p) { this } +6 val v2 = with(p) { bar(this) } +13 (INLINE CALL with) inline fun with(receiver: T, block: T.() -> R): R { +14 (INLINE CALL with) return receiver.block() +13 (INLINE CALL with) [LAMBDA RECEIVER IN] inline fun with(receiver: T, block: T.() -> R): R { +6 [LAMBDA RECEIVER IN] val v2 = with(p) { bar(this) } +6 val v2 = with(p) { bar(this) } +11 fun bar(s: String) = s +11 fun bar(s: String) = s +11 fun bar(s: String) = s +6 val v2 = with(p) { bar(this) } +6 val v2 = with(p) { bar(this) } +6 [LAMBDA CALLS] val v2 = with(p) { bar(this) } +13 (INLINE CALL with) [LAMBDA CALLS] inline fun with(receiver: T, block: T.() -> R): R { +14 (INLINE CALL with) return receiver.block() +6 val v2 = with(p) { bar(this) } +6 val v2 = with(p) { bar(this) } +8 val v3 = with(p) { this@foo } +13 (INLINE CALL with) inline fun with(receiver: T, block: T.() -> R): R { +14 (INLINE CALL with) return receiver.block() +13 (INLINE CALL with) [LAMBDA RECEIVER IN] inline fun with(receiver: T, block: T.() -> R): R { +8 [LAMBDA RECEIVER IN] val v3 = with(p) { this@foo } diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java index 7571a9d8394..8b4acc82fc4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java @@ -623,6 +623,11 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest { runTest("idea/testData/slicer/outflow/lambdaResultWithDirectCallViaAssignment.kt"); } + @TestMetadata("lambdaResultWithInvokeCall.kt") + public void testLambdaResultWithInvokeCall() throws Exception { + runTest("idea/testData/slicer/outflow/lambdaResultWithInvokeCall.kt"); + } + @TestMetadata("letResult.kt") public void testLetResult() throws Exception { runTest("idea/testData/slicer/outflow/letResult.kt"); @@ -753,6 +758,11 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest { runTest("idea/testData/slicer/outflow/whenExpression.kt"); } + @TestMetadata("withResult.kt") + public void testWithResult() throws Exception { + runTest("idea/testData/slicer/outflow/withResult.kt"); + } + @TestMetadata("wrongThis.kt") public void testWrongThis() throws Exception { runTest("idea/testData/slicer/outflow/wrongThis.kt");