diff --git a/idea/resources/messages/KotlinBundle.properties b/idea/resources/messages/KotlinBundle.properties index c24cf6954ae..607286252b7 100644 --- a/idea/resources/messages/KotlinBundle.properties +++ b/idea/resources/messages/KotlinBundle.properties @@ -667,6 +667,7 @@ test.integration.title.no.test.roots.found=No Test Roots Found slicer.text.in=\ in {0} slicer.text.tracking.enclosing.lambda=\ (Tracking enclosing lambda) +slicer.text.tracking.lambda.calls=\ (Tracking lambda calls) slicer.title.dataflow.from.here=Dataflow from Here slicer.title.dataflow.to.here=Dataflow to Here slicer.tool.tip.text.variable.dereferenced=Variable dereferenced diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt index f3ed64e2965..25076b957fb 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt @@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.SearchScope import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.slicer.SliceUsage import com.intellij.usageView.UsageInfo import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor @@ -18,10 +19,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor -import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.idea.caches.resolve.* import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor @@ -34,15 +33,16 @@ import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchReques import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders import org.jetbrains.kotlin.idea.util.actualsForExpected import org.jetbrains.kotlin.idea.util.isExpectDeclaration +import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType -import org.jetbrains.kotlin.psi.psiUtil.parameterIndex import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument +import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver @@ -129,30 +129,15 @@ class InflowSlicer( val parameterDescriptor = parameter.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return if (function is KtFunction) { - fun extractArgumentExpression(refElement: PsiElement): PsiElement? { - val refParent = refElement.parent - return when { - refElement is KtExpression -> { - val callElement = refElement.getParentOfTypeAndBranch { calleeExpression } ?: return null - val resolvedCall = callElement.resolveToCall() ?: return null - val callParameterDescriptor = resolvedCall.resultingDescriptor.valueParameters[parameterDescriptor.index] - val resolvedArgument = resolvedCall.valueArguments[callParameterDescriptor] ?: return null - when (resolvedArgument) { - is DefaultValueArgument -> parameter.defaultValue - is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression() - else -> null - } + val sliceTransformer = ArgumentExpressionTransformer(parameterDescriptor) + + if (function is KtFunctionLiteral) { + processFunctionLiteralCalls(function, sliceTransformer) + } else { + processCalls(function, analysisScope, includeOverriders) { usageInfo -> + usageInfo.element?.let { + sliceTransformer.extractArgumentExpression(it)?.passToProcessorAsValue() } - - refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(parameter.parameterIndex()) - - else -> null - } - } - - processCalls(function, analysisScope, includeOverriders) { usageInfo -> - usageInfo.element?.let { - extractArgumentExpression(it)?.passToProcessorAsValue() } } } @@ -178,7 +163,7 @@ class InflowSlicer( } } } - + else -> { (refElement.parent as? PsiCall)?.argumentList?.expressions?.getOrNull(0)?.passToProcessorAsValue() } @@ -236,6 +221,19 @@ class InflowSlicer( callableDeclaration.receiverTypeReference?.passToProcessor() } + is ValueParameterDescriptor -> { + if (accessedDeclaration == null) { + val anonymousFunction = accessedDescriptor.containingDeclaration as? AnonymousFunctionDescriptor + if (anonymousFunction != null && accessedDescriptor.name.asString() == "it") { + val functionLiteral = anonymousFunction.source.getPsi() as KtFunctionLiteral + val sliceTransformer = ArgumentExpressionTransformer(anonymousFunction.valueParameters.first()) + processFunctionLiteralCalls(functionLiteral, sliceTransformer) + } + } else { + accessedDeclaration.passDeclarationToProcessorWithOverriders() + } + } + else -> { accessedDeclaration?.passDeclarationToProcessorWithOverriders() } @@ -358,4 +356,48 @@ class InflowSlicer( } } } + + @Suppress("DataClassPrivateConstructor") // we have modifier data to get equals&hashCode only + private data class ArgumentExpressionTransformer private constructor( + private val parameterIndex: Int, + private val isExtension: Boolean + ) : KotlinSliceUsageTransformer + { + constructor(parameterDescriptor: ValueParameterDescriptor) : this( + parameterDescriptor.index, + parameterDescriptor.containingDeclaration.isExtension + ) + + override fun transform(usage: KotlinSliceUsage): SliceUsage? { + val element = usage.element ?: return null + val argumentExpression = extractArgumentExpression(element) ?: return null + return KotlinSliceUsage(argumentExpression, usage.parent, usage.behaviour?.originalBehaviour, forcedExpressionMode = true) + } + + fun extractArgumentExpression(refElement: PsiElement): PsiElement? { + val refParent = refElement.parent + return when { + refElement is KtExpression -> { + val callElement = refElement as? KtCallElement + ?: refElement.getParentOfTypeAndBranch { calleeExpression } + ?: return null + val resolvedCall = callElement.resolveToCall() ?: return null + val resultingDescriptor = resolvedCall.resultingDescriptor + val parameterIndexToUse = parameterIndex + + (if (isExtension && resultingDescriptor.extensionReceiverParameter == null) 1 else 0) + val parameterDescriptor = resultingDescriptor.valueParameters[parameterIndexToUse] + val resolvedArgument = resolvedCall.valueArguments[parameterDescriptor] ?: return null + when (resolvedArgument) { + is DefaultValueArgument -> (parameterDescriptor.source.getPsi() as? KtParameter)?.defaultValue + is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression() + else -> null + } + } + + refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(parameterIndex + (if (isExtension) 1 else 0)) + + else -> null + } + } + } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceUsage.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceUsage.kt index 90760a8d592..8d467992a88 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceUsage.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinSliceUsage.kt @@ -129,3 +129,4 @@ data class LambdaResultInflowBehaviour( override val testPresentationPrefix: String get() = "[LAMBDA] " } + diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaCallsBehaviour.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaCallsBehaviour.kt new file mode 100644 index 00000000000..26e09caa1d8 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/LambdaCallsBehaviour.kt @@ -0,0 +1,49 @@ +/* + * 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 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 +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver + +interface KotlinSliceUsageTransformer { + fun transform(usage: KotlinSliceUsage): SliceUsage? + + override fun equals(other: Any?): Boolean + override fun hashCode(): Int +} + +data class LambdaCallsBehaviour( + val usageTransformer: KotlinSliceUsageTransformer, + override val originalBehaviour: KotlinSliceUsage.SpecialBehaviour? +) : KotlinSliceUsage.SpecialBehaviour { + + override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) { + val processor = object : SliceUsageProcessor { + override fun process(sliceUsage: SliceUsage): Boolean { + if (sliceUsage is KotlinSliceUsage && sliceUsage.behaviour === this@LambdaCallsBehaviour) { + val sliceElement = sliceUsage.element ?: return true + val resolvedCall = (sliceElement as? KtElement)?.resolveToCall() + if (resolvedCall?.call?.callType == Call.CallType.INVOKE) { + return usageTransformer.transform(sliceUsage)?.let { uniqueProcessor.process(it) } ?: true + } + } + return uniqueProcessor.process(sliceUsage) + } + } + OutflowSlicer(element, processor, parent).processChildren(parent.forcedExpressionMode) + } + + override val slicePresentationPrefix: String + get() = KotlinBundle.message("slicer.text.tracking.lambda.calls") + + override val testPresentationPrefix: String + get() = "[LAMBDA CALLS] " +} \ 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 ddc9ca17e18..df5369addd0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt @@ -232,8 +232,13 @@ class OutflowSlicer( } Call.CallType.INVOKE -> { - if (receiverValue == resolvedCall.dispatchReceiver && behaviour is LambdaResultOutflowBehaviour) { - instruction.element.passToProcessor(behaviour.originalBehaviour) + if (receiverValue == resolvedCall.dispatchReceiver) { + if (behaviour is LambdaResultOutflowBehaviour) { + instruction.element.passToProcessor(behaviour.originalBehaviour) + } + else if (behaviour is LambdaCallsBehaviour) { + instruction.element.passToProcessor(behaviour) + } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt index 0e91d185e8f..5d262b0265e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.search.SearchScope import com.intellij.slicer.JavaSliceUsage +import com.intellij.slicer.SliceUsage import com.intellij.usageView.UsageInfo import com.intellij.util.containers.addIfNotNull import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode @@ -68,12 +69,24 @@ abstract class Slicer( passToProcessor(behaviour, forcedExpressionMode = true) } + protected fun processFunctionLiteralCalls( + callable: KtFunctionLiteral, + sliceTransformer: KotlinSliceUsageTransformer, + ) { + (callable.parent as KtLambdaExpression).passToProcessorAsValue(LambdaCallsBehaviour(sliceTransformer, behaviour)) + } + protected fun processCalls( callable: KtCallableDeclaration, scope: SearchScope, includeOverriders: Boolean, usageProcessor: (UsageInfo) -> Unit ) { + if (callable is KtFunctionLiteral) { + //TODO + return + } + val options = when (callable) { is KtFunction -> { KotlinFunctionFindUsagesOptions(project).apply { diff --git a/idea/testData/slicer/inflow/doubleLambdaResult.leafGroups.txt b/idea/testData/slicer/inflow/doubleLambdaResult.leafGroups.txt index 62e8a17c198..d92bcf7034f 100644 --- a/idea/testData/slicer/inflow/doubleLambdaResult.leafGroups.txt +++ b/idea/testData/slicer/inflow/doubleLambdaResult.leafGroups.txt @@ -1,4 +1,4 @@ -8 val x = foo(1, 2) { { it } } +8 val x = foo(1, 2) { { it } } 8 val x = foo(1, 2) { { it } } 8 val x = foo(1, 2) { { it } } 3 fun foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int { @@ -11,4 +11,13 @@ 8 [LAMBDA] val x = foo(1, 2) { { it } } 8 val x = foo(1, 2) { { it } } 8 val x = foo(1, 2) { { it } } +8 [LAMBDA CALLS] val x = foo(1, 2) { { it } } +8 [LAMBDA CALLS] val x = foo(1, 2) { { it } } +8 [LAMBDA] [LAMBDA CALLS] val x = foo(1, 2) { { it } } +3 [LAMBDA] [LAMBDA CALLS] fun foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int { +4 [LAMBDA] [LAMBDA CALLS] return f(a)(b) +4 [LAMBDA CALLS] return f(a)(b) +4 return f(a)(b) +3 fun foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int { +8 val x = foo(1, 2) { { it } } diff --git a/idea/testData/slicer/inflow/doubleLambdaResult.results.txt b/idea/testData/slicer/inflow/doubleLambdaResult.results.txt index fe9b9ba6d71..1ac7196ff12 100644 --- a/idea/testData/slicer/inflow/doubleLambdaResult.results.txt +++ b/idea/testData/slicer/inflow/doubleLambdaResult.results.txt @@ -10,3 +10,12 @@ 8 [LAMBDA] val x = foo(1, 2) { { it } } 8 val x = foo(1, 2) { { it } } 8 val x = foo(1, 2) { { it } } +8 [LAMBDA CALLS] val x = foo(1, 2) { { it } } +8 [LAMBDA CALLS] val x = foo(1, 2) { { it } } +8 [LAMBDA] [LAMBDA CALLS] val x = foo(1, 2) { { it } } +3 [LAMBDA] [LAMBDA CALLS] fun foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int { +4 [LAMBDA] [LAMBDA CALLS] return f(a)(b) +4 [LAMBDA CALLS] return f(a)(b) +4 return f(a)(b) +3 fun foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int { +8 val x = foo(1, 2) { { it } } diff --git a/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.kt b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.kt new file mode 100644 index 00000000000..5d8184f6814 --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.kt @@ -0,0 +1,21 @@ +// FLOW: IN + +fun foo(f: String.(Int) -> Unit) { + f("", 1) + + "".f(2) + + with("") { + f(3) + } +} + +fun test() { + foo { + println(it) + } +} + +inline fun with(receiver: T, block: T.() -> R): R { + return receiver.block() +} diff --git a/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.leafGroups.txt b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.leafGroups.txt new file mode 100644 index 00000000000..0ba21e435ed --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.leafGroups.txt @@ -0,0 +1,18 @@ +4 f("", 1) +15 println(it) +14 [LAMBDA CALLS] foo { +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +4 f("", 1) + +6 "".f(2) +15 println(it) +14 [LAMBDA CALLS] foo { +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +6 "".f(2) + +9 f(3) +15 println(it) +14 [LAMBDA CALLS] foo { +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +9 f(3) + diff --git a/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.nullnessGroups.txt b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.nullnessGroups.txt new file mode 100644 index 00000000000..7b0be39b1c7 --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.nullnessGroups.txt @@ -0,0 +1,4 @@ +[NotNull Values] +15 println(it) +15 println(it) + diff --git a/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.results.txt b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.results.txt new file mode 100644 index 00000000000..eb578f6015a --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaImplicitParameter.results.txt @@ -0,0 +1,6 @@ +15 println(it) +14 [LAMBDA CALLS] foo { +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +4 f("", 1) +6 "".f(2) +9 f(3) diff --git a/idea/testData/slicer/inflow/extensionLambdaParameter.kt b/idea/testData/slicer/inflow/extensionLambdaParameter.kt new file mode 100644 index 00000000000..9da17a22158 --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaParameter.kt @@ -0,0 +1,21 @@ +// FLOW: IN + +fun foo(f: String.(Int) -> Unit) { + f("", 1) + + "".f(2) + + with("") { + f(3) + } +} + +fun test() { + foo { i -> + println(i) + } +} + +inline fun with(receiver: T, block: T.() -> R): R { + return receiver.block() +} diff --git a/idea/testData/slicer/inflow/extensionLambdaParameter.leafGroups.txt b/idea/testData/slicer/inflow/extensionLambdaParameter.leafGroups.txt new file mode 100644 index 00000000000..b41a25af01e --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaParameter.leafGroups.txt @@ -0,0 +1,21 @@ +4 f("", 1) +15 println(i) +14 foo { i -> +14 [LAMBDA CALLS] foo { i -> +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +4 f("", 1) + +6 "".f(2) +15 println(i) +14 foo { i -> +14 [LAMBDA CALLS] foo { i -> +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +6 "".f(2) + +9 f(3) +15 println(i) +14 foo { i -> +14 [LAMBDA CALLS] foo { i -> +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +9 f(3) + diff --git a/idea/testData/slicer/inflow/extensionLambdaParameter.nullnessGroups.txt b/idea/testData/slicer/inflow/extensionLambdaParameter.nullnessGroups.txt new file mode 100644 index 00000000000..d6ff54bc478 --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaParameter.nullnessGroups.txt @@ -0,0 +1,4 @@ +[NotNull Values] +15 println(i) +15 println(i) + diff --git a/idea/testData/slicer/inflow/extensionLambdaParameter.results.txt b/idea/testData/slicer/inflow/extensionLambdaParameter.results.txt new file mode 100644 index 00000000000..2b282650a36 --- /dev/null +++ b/idea/testData/slicer/inflow/extensionLambdaParameter.results.txt @@ -0,0 +1,7 @@ +15 println(i) +14 foo { i -> +14 [LAMBDA CALLS] foo { i -> +3 [LAMBDA CALLS] fun foo(f: String.(Int) -> Unit) { +4 f("", 1) +6 "".f(2) +9 f(3) diff --git a/idea/testData/slicer/inflow/lambdaImplicitParameter.kt b/idea/testData/slicer/inflow/lambdaImplicitParameter.kt new file mode 100644 index 00000000000..130c0cfb954 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaImplicitParameter.kt @@ -0,0 +1,11 @@ +// FLOW: IN + +fun foo(f: (Int) -> Unit): Int { + return f(1) +} + +fun test() { + foo { + println(it) + } +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/lambdaImplicitParameter.leafGroups.txt b/idea/testData/slicer/inflow/lambdaImplicitParameter.leafGroups.txt new file mode 100644 index 00000000000..27b609d4b08 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaImplicitParameter.leafGroups.txt @@ -0,0 +1,6 @@ +4 return f(1) +9 println(it) +8 [LAMBDA CALLS] foo { +3 [LAMBDA CALLS] fun foo(f: (Int) -> Unit): Int { +4 return f(1) + diff --git a/idea/testData/slicer/inflow/lambdaImplicitParameter.nullnessGroups.txt b/idea/testData/slicer/inflow/lambdaImplicitParameter.nullnessGroups.txt new file mode 100644 index 00000000000..19c9185d0f6 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaImplicitParameter.nullnessGroups.txt @@ -0,0 +1,3 @@ +[NotNull Values] +9 println(it) +9 println(it) diff --git a/idea/testData/slicer/inflow/lambdaImplicitParameter.results.txt b/idea/testData/slicer/inflow/lambdaImplicitParameter.results.txt new file mode 100644 index 00000000000..f90150738d7 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaImplicitParameter.results.txt @@ -0,0 +1,4 @@ +9 println(it) +8 [LAMBDA CALLS] foo { +3 [LAMBDA CALLS] fun foo(f: (Int) -> Unit): Int { +4 return f(1) diff --git a/idea/testData/slicer/inflow/lambdaParameter.kt b/idea/testData/slicer/inflow/lambdaParameter.kt new file mode 100644 index 00000000000..a5d4b750176 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaParameter.kt @@ -0,0 +1,11 @@ +// FLOW: IN + +fun foo(f: (Int) -> Unit): Int { + return f(1) +} + +fun test() { + foo { value -> + println(value) + } +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/lambdaParameter.leafGroups.txt b/idea/testData/slicer/inflow/lambdaParameter.leafGroups.txt new file mode 100644 index 00000000000..591d6bdc490 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaParameter.leafGroups.txt @@ -0,0 +1,7 @@ +4 return f(1) +9 println(value) +8 foo { value -> +8 [LAMBDA CALLS] foo { value -> +3 [LAMBDA CALLS] fun foo(f: (Int) -> Unit): Int { +4 return f(1) + diff --git a/idea/testData/slicer/inflow/lambdaParameter.nullnessGroups.txt b/idea/testData/slicer/inflow/lambdaParameter.nullnessGroups.txt new file mode 100644 index 00000000000..c458ceed792 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaParameter.nullnessGroups.txt @@ -0,0 +1,3 @@ +[NotNull Values] +9 println(value) +9 println(value) diff --git a/idea/testData/slicer/inflow/lambdaParameter.results.txt b/idea/testData/slicer/inflow/lambdaParameter.results.txt new file mode 100644 index 00000000000..c5d7ae68aa9 --- /dev/null +++ b/idea/testData/slicer/inflow/lambdaParameter.results.txt @@ -0,0 +1,5 @@ +9 println(value) +8 foo { value -> +8 [LAMBDA CALLS] foo { value -> +3 [LAMBDA CALLS] fun foo(f: (Int) -> Unit): Int { +4 return f(1) diff --git a/idea/testData/slicer/inflow/lambdaResult.leafGroups.txt b/idea/testData/slicer/inflow/lambdaResult.leafGroups.txt index b087d61984a..5e71f82c65a 100644 --- a/idea/testData/slicer/inflow/lambdaResult.leafGroups.txt +++ b/idea/testData/slicer/inflow/lambdaResult.leafGroups.txt @@ -1,4 +1,4 @@ -8 val x = foo { it } +4 return f(1) 8 val x = foo { it } 8 val x = foo { it } 3 fun foo(f: (Int) -> Int): Int { @@ -8,4 +8,7 @@ 8 [LAMBDA] val x = foo { it } 8 val x = foo { it } 8 val x = foo { it } +8 [LAMBDA CALLS] val x = foo { it } +3 [LAMBDA CALLS] fun foo(f: (Int) -> Int): Int { +4 return f(1) diff --git a/idea/testData/slicer/inflow/lambdaResult.results.txt b/idea/testData/slicer/inflow/lambdaResult.results.txt index 9799ce293d7..d6fe53789dc 100644 --- a/idea/testData/slicer/inflow/lambdaResult.results.txt +++ b/idea/testData/slicer/inflow/lambdaResult.results.txt @@ -7,3 +7,6 @@ 8 [LAMBDA] val x = foo { it } 8 val x = foo { it } 8 val x = foo { it } +8 [LAMBDA CALLS] val x = foo { it } +3 [LAMBDA CALLS] fun foo(f: (Int) -> Int): Int { +4 return f(1) diff --git a/idea/testData/slicer/inflow/lambdaResultWithAssignments.leafGroups.txt b/idea/testData/slicer/inflow/lambdaResultWithAssignments.leafGroups.txt index 2d31c99ed33..93238c3f0d7 100644 --- a/idea/testData/slicer/inflow/lambdaResultWithAssignments.leafGroups.txt +++ b/idea/testData/slicer/inflow/lambdaResultWithAssignments.leafGroups.txt @@ -1,4 +1,4 @@ -9 val y = foo { it } +5 return x(1) 9 val y = foo { it } 9 val y = foo { it } 3 fun foo(f: (Int) -> Int): Int { @@ -10,4 +10,9 @@ 9 [LAMBDA] val y = foo { it } 9 val y = foo { it } 9 val y = foo { it } +9 [LAMBDA CALLS] val y = foo { it } +3 [LAMBDA CALLS] fun foo(f: (Int) -> Int): Int { +4 [LAMBDA CALLS] val x = f +4 [LAMBDA CALLS] val x = f +5 return x(1) diff --git a/idea/testData/slicer/inflow/lambdaResultWithAssignments.results.txt b/idea/testData/slicer/inflow/lambdaResultWithAssignments.results.txt index 8b7bc172dae..18c9144f7bc 100644 --- a/idea/testData/slicer/inflow/lambdaResultWithAssignments.results.txt +++ b/idea/testData/slicer/inflow/lambdaResultWithAssignments.results.txt @@ -9,3 +9,8 @@ 9 [LAMBDA] val y = foo { it } 9 val y = foo { it } 9 val y = foo { it } +9 [LAMBDA CALLS] val y = foo { it } +3 [LAMBDA CALLS] fun foo(f: (Int) -> Int): Int { +4 [LAMBDA CALLS] val x = f +4 [LAMBDA CALLS] val x = f +5 return x(1) diff --git a/idea/testData/slicer/inflow/nonLocalReturn.leafGroups.txt b/idea/testData/slicer/inflow/nonLocalReturn.leafGroups.txt index a9af915157d..43a3afd0b8f 100644 --- a/idea/testData/slicer/inflow/nonLocalReturn.leafGroups.txt +++ b/idea/testData/slicer/inflow/nonLocalReturn.leafGroups.txt @@ -1,4 +1,4 @@ -5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } +5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 3 inline fun foo(a: Int, f: (Int) -> Int) = f(a) @@ -9,6 +9,12 @@ 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } +5 [LAMBDA CALLS] fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } +3 [LAMBDA CALLS] inline fun foo(a: Int, f: (Int) -> Int) = f(a) +3 inline fun foo(a: Int, f: (Int) -> Int) = f(a) +3 inline fun foo(a: Int, f: (Int) -> Int) = f(a) +5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } +5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } diff --git a/idea/testData/slicer/inflow/nonLocalReturn.results.txt b/idea/testData/slicer/inflow/nonLocalReturn.results.txt index 18a78688da2..d0705bd85d3 100644 --- a/idea/testData/slicer/inflow/nonLocalReturn.results.txt +++ b/idea/testData/slicer/inflow/nonLocalReturn.results.txt @@ -8,4 +8,10 @@ 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } +5 [LAMBDA CALLS] fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } +3 [LAMBDA CALLS] inline fun foo(a: Int, f: (Int) -> Int) = f(a) +3 inline fun foo(a: Int, f: (Int) -> Int) = f(a) +3 inline fun foo(a: Int, f: (Int) -> Int) = f(a) +5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } +5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } 5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 } diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerLeafGroupingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerLeafGroupingTestGenerated.java index 637f33d9d3a..9938bcfa440 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerLeafGroupingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerLeafGroupingTestGenerated.java @@ -103,6 +103,16 @@ public class SlicerLeafGroupingTestGenerated extends AbstractSlicerLeafGroupingT runTest("idea/testData/slicer/inflow/doubleLambdaResult.kt"); } + @TestMetadata("extensionLambdaImplicitParameter.kt") + public void testExtensionLambdaImplicitParameter() throws Exception { + runTest("idea/testData/slicer/inflow/extensionLambdaImplicitParameter.kt"); + } + + @TestMetadata("extensionLambdaParameter.kt") + public void testExtensionLambdaParameter() throws Exception { + runTest("idea/testData/slicer/inflow/extensionLambdaParameter.kt"); + } + @TestMetadata("funParamerer.kt") public void testFunParamerer() throws Exception { runTest("idea/testData/slicer/inflow/funParamerer.kt"); @@ -158,6 +168,16 @@ public class SlicerLeafGroupingTestGenerated extends AbstractSlicerLeafGroupingT runTest("idea/testData/slicer/inflow/ifExpression.kt"); } + @TestMetadata("lambdaImplicitParameter.kt") + public void testLambdaImplicitParameter() throws Exception { + runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt"); + } + + @TestMetadata("lambdaParameter.kt") + public void testLambdaParameter() throws Exception { + runTest("idea/testData/slicer/inflow/lambdaParameter.kt"); + } + @TestMetadata("lambdaResult.kt") public void testLambdaResult() throws Exception { runTest("idea/testData/slicer/inflow/lambdaResult.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerNullnessGroupingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerNullnessGroupingTestGenerated.java index a717e5ecfdb..f00f44ae364 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerNullnessGroupingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerNullnessGroupingTestGenerated.java @@ -103,6 +103,16 @@ public class SlicerNullnessGroupingTestGenerated extends AbstractSlicerNullnessG runTest("idea/testData/slicer/inflow/doubleLambdaResult.kt"); } + @TestMetadata("extensionLambdaImplicitParameter.kt") + public void testExtensionLambdaImplicitParameter() throws Exception { + runTest("idea/testData/slicer/inflow/extensionLambdaImplicitParameter.kt"); + } + + @TestMetadata("extensionLambdaParameter.kt") + public void testExtensionLambdaParameter() throws Exception { + runTest("idea/testData/slicer/inflow/extensionLambdaParameter.kt"); + } + @TestMetadata("funParamerer.kt") public void testFunParamerer() throws Exception { runTest("idea/testData/slicer/inflow/funParamerer.kt"); @@ -158,6 +168,16 @@ public class SlicerNullnessGroupingTestGenerated extends AbstractSlicerNullnessG runTest("idea/testData/slicer/inflow/ifExpression.kt"); } + @TestMetadata("lambdaImplicitParameter.kt") + public void testLambdaImplicitParameter() throws Exception { + runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt"); + } + + @TestMetadata("lambdaParameter.kt") + public void testLambdaParameter() throws Exception { + runTest("idea/testData/slicer/inflow/lambdaParameter.kt"); + } + @TestMetadata("lambdaResult.kt") public void testLambdaResult() throws Exception { runTest("idea/testData/slicer/inflow/lambdaResult.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java index 36ae6e7295b..44afd45066a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java @@ -115,6 +115,16 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest { runTest("idea/testData/slicer/inflow/doubleLambdaResult.kt"); } + @TestMetadata("extensionLambdaImplicitParameter.kt") + public void testExtensionLambdaImplicitParameter() throws Exception { + runTest("idea/testData/slicer/inflow/extensionLambdaImplicitParameter.kt"); + } + + @TestMetadata("extensionLambdaParameter.kt") + public void testExtensionLambdaParameter() throws Exception { + runTest("idea/testData/slicer/inflow/extensionLambdaParameter.kt"); + } + @TestMetadata("funParamerer.kt") public void testFunParamerer() throws Exception { runTest("idea/testData/slicer/inflow/funParamerer.kt"); @@ -170,6 +180,16 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest { runTest("idea/testData/slicer/inflow/ifExpression.kt"); } + @TestMetadata("lambdaImplicitParameter.kt") + public void testLambdaImplicitParameter() throws Exception { + runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt"); + } + + @TestMetadata("lambdaParameter.kt") + public void testLambdaParameter() throws Exception { + runTest("idea/testData/slicer/inflow/lambdaParameter.kt"); + } + @TestMetadata("lambdaResult.kt") public void testLambdaResult() throws Exception { runTest("idea/testData/slicer/inflow/lambdaResult.kt");