Track lambda parameters in inbound data flow analysis

This commit is contained in:
Valentin Kipyatkov
2020-04-10 16:18:07 +03:00
parent 799b2d7291
commit c19a16f1e0
33 changed files with 404 additions and 35 deletions
@@ -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
@@ -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<KtCallElement> { 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
}
}
}
}
@@ -129,3 +129,4 @@ data class LambdaResultInflowBehaviour(
override val testPresentationPrefix: String
get() = "[LAMBDA] "
}
@@ -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] "
}
@@ -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)
}
}
}
@@ -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 {
@@ -1,4 +1,4 @@
8 val x = foo(1, 2) { { <bold>it</bold> } }
8 val x = foo(1, <bold>2</bold>) { { it } }
8 val <bold>x = foo(1, 2) { { it } }</bold>
8 val x = <bold>foo(1, 2) { { it } }</bold>
3 fun <bold>foo(a: Int, b: Int, f: (Int) -> (Int) -> Int): Int {</bold>
@@ -11,4 +11,13 @@
8 [LAMBDA] val x = foo(1, 2) { <bold>{ it }</bold> }
8 val x = foo(1, 2) { <bold>{ it }</bold> }
8 val x = foo(1, 2) { { <bold>it</bold> } }
8 [LAMBDA CALLS] val x = foo(1, 2) { <bold>{ it }</bold> }
8 [LAMBDA CALLS] val x = foo(1, 2) <bold>{ { it } }</bold>
8 [LAMBDA] [LAMBDA CALLS] val x = foo(1, 2) <bold>{ { it } }</bold>
3 [LAMBDA] [LAMBDA CALLS] fun foo(a: Int, b: Int, <bold>f: (Int) -> (Int) -> Int</bold>): Int {
4 [LAMBDA] [LAMBDA CALLS] return <bold>f</bold>(a)(b)
4 [LAMBDA CALLS] return <bold>f(a)</bold>(b)
4 return f(a)(<bold>b</bold>)
3 fun foo(a: Int, <bold>b: Int</bold>, f: (Int) -> (Int) -> Int): Int {
8 val x = foo(1, <bold>2</bold>) { { it } }
@@ -10,3 +10,12 @@
8 [LAMBDA] val x = foo(1, 2) { <bold>{ it }</bold> }
8 val x = foo(1, 2) { <bold>{ it }</bold> }
8 val x = foo(1, 2) { { <bold>it</bold> } }
8 [LAMBDA CALLS] val x = foo(1, 2) { <bold>{ it }</bold> }
8 [LAMBDA CALLS] val x = foo(1, 2) <bold>{ { it } }</bold>
8 [LAMBDA] [LAMBDA CALLS] val x = foo(1, 2) <bold>{ { it } }</bold>
3 [LAMBDA] [LAMBDA CALLS] fun foo(a: Int, b: Int, <bold>f: (Int) -> (Int) -> Int</bold>): Int {
4 [LAMBDA] [LAMBDA CALLS] return <bold>f</bold>(a)(b)
4 [LAMBDA CALLS] return <bold>f(a)</bold>(b)
4 return f(a)(<bold>b</bold>)
3 fun foo(a: Int, <bold>b: Int</bold>, f: (Int) -> (Int) -> Int): Int {
8 val x = foo(1, <bold>2</bold>) { { it } }
@@ -0,0 +1,21 @@
// FLOW: IN
fun foo(f: String.(Int) -> Unit) {
f("", 1)
"".f(2)
with("") {
f(3)
}
}
fun test() {
foo {
println(<caret>it)
}
}
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}
@@ -0,0 +1,18 @@
4 f("", <bold>1</bold>)
15 println(<bold>it</bold>)
14 [LAMBDA CALLS] foo <bold>{</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
4 f("", <bold>1</bold>)
6 "".f(<bold>2</bold>)
15 println(<bold>it</bold>)
14 [LAMBDA CALLS] foo <bold>{</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
6 "".f(<bold>2</bold>)
9 f(<bold>3</bold>)
15 println(<bold>it</bold>)
14 [LAMBDA CALLS] foo <bold>{</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
9 f(<bold>3</bold>)
@@ -0,0 +1,4 @@
[NotNull Values]
15 println(<bold>it</bold>)
15 println(<bold>it</bold>)
@@ -0,0 +1,6 @@
15 println(<bold>it</bold>)
14 [LAMBDA CALLS] foo <bold>{</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
4 f("", <bold>1</bold>)
6 "".f(<bold>2</bold>)
9 f(<bold>3</bold>)
+21
View File
@@ -0,0 +1,21 @@
// FLOW: IN
fun foo(f: String.(Int) -> Unit) {
f("", 1)
"".f(2)
with("") {
f(3)
}
}
fun test() {
foo { i ->
println(<caret>i)
}
}
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}
@@ -0,0 +1,21 @@
4 f("", <bold>1</bold>)
15 println(<bold>i</bold>)
14 foo { <bold>i</bold> ->
14 [LAMBDA CALLS] foo <bold>{ i -></bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
4 f("", <bold>1</bold>)
6 "".f(<bold>2</bold>)
15 println(<bold>i</bold>)
14 foo { <bold>i</bold> ->
14 [LAMBDA CALLS] foo <bold>{ i -></bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
6 "".f(<bold>2</bold>)
9 f(<bold>3</bold>)
15 println(<bold>i</bold>)
14 foo { <bold>i</bold> ->
14 [LAMBDA CALLS] foo <bold>{ i -></bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
9 f(<bold>3</bold>)
@@ -0,0 +1,4 @@
[NotNull Values]
15 println(<bold>i</bold>)
15 println(<bold>i</bold>)
@@ -0,0 +1,7 @@
15 println(<bold>i</bold>)
14 foo { <bold>i</bold> ->
14 [LAMBDA CALLS] foo <bold>{ i -></bold>
3 [LAMBDA CALLS] fun foo(<bold>f: String.(Int) -> Unit</bold>) {
4 f("", <bold>1</bold>)
6 "".f(<bold>2</bold>)
9 f(<bold>3</bold>)
+11
View File
@@ -0,0 +1,11 @@
// FLOW: IN
fun foo(f: (Int) -> Unit): Int {
return f(1)
}
fun test() {
foo {
println(<caret>it)
}
}
@@ -0,0 +1,6 @@
4 return f(<bold>1</bold>)
9 println(<bold>it</bold>)
8 [LAMBDA CALLS] foo <bold>{</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Unit</bold>): Int {
4 return f(<bold>1</bold>)
@@ -0,0 +1,3 @@
[NotNull Values]
9 println(<bold>it</bold>)
9 println(<bold>it</bold>)
@@ -0,0 +1,4 @@
9 println(<bold>it</bold>)
8 [LAMBDA CALLS] foo <bold>{</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Unit</bold>): Int {
4 return f(<bold>1</bold>)
+11
View File
@@ -0,0 +1,11 @@
// FLOW: IN
fun foo(f: (Int) -> Unit): Int {
return f(1)
}
fun test() {
foo { value ->
println(<caret>value)
}
}
@@ -0,0 +1,7 @@
4 return f(<bold>1</bold>)
9 println(<bold>value</bold>)
8 foo { <bold>value</bold> ->
8 [LAMBDA CALLS] foo <bold>{ value -></bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Unit</bold>): Int {
4 return f(<bold>1</bold>)
@@ -0,0 +1,3 @@
[NotNull Values]
9 println(<bold>value</bold>)
9 println(<bold>value</bold>)
@@ -0,0 +1,5 @@
9 println(<bold>value</bold>)
8 foo { <bold>value</bold> ->
8 [LAMBDA CALLS] foo <bold>{ value -></bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Unit</bold>): Int {
4 return f(<bold>1</bold>)
+4 -1
View File
@@ -1,4 +1,4 @@
8 val x = foo { <bold>it</bold> }
4 return f(<bold>1</bold>)
8 val <bold>x = foo { it }</bold>
8 val x = <bold>foo { it }</bold>
3 fun <bold>foo(f: (Int) -> Int): Int {</bold>
@@ -8,4 +8,7 @@
8 [LAMBDA] val x = foo <bold>{ it }</bold>
8 val x = foo <bold>{ it }</bold>
8 val x = foo { <bold>it</bold> }
8 [LAMBDA CALLS] val x = foo <bold>{ it }</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Int</bold>): Int {
4 return f(<bold>1</bold>)
+3
View File
@@ -7,3 +7,6 @@
8 [LAMBDA] val x = foo <bold>{ it }</bold>
8 val x = foo <bold>{ it }</bold>
8 val x = foo { <bold>it</bold> }
8 [LAMBDA CALLS] val x = foo <bold>{ it }</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Int</bold>): Int {
4 return f(<bold>1</bold>)
@@ -1,4 +1,4 @@
9 val y = foo { <bold>it</bold> }
5 return x(<bold>1</bold>)
9 val <bold>y = foo { it }</bold>
9 val y = <bold>foo { it }</bold>
3 fun <bold>foo(f: (Int) -> Int): Int {</bold>
@@ -10,4 +10,9 @@
9 [LAMBDA] val y = foo <bold>{ it }</bold>
9 val y = foo <bold>{ it }</bold>
9 val y = foo { <bold>it</bold> }
9 [LAMBDA CALLS] val y = foo <bold>{ it }</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Int</bold>): Int {
4 [LAMBDA CALLS] val x = <bold>f</bold>
4 [LAMBDA CALLS] val <bold>x = f</bold>
5 return x(<bold>1</bold>)
@@ -9,3 +9,8 @@
9 [LAMBDA] val y = foo <bold>{ it }</bold>
9 val y = foo <bold>{ it }</bold>
9 val y = foo { <bold>it</bold> }
9 [LAMBDA CALLS] val y = foo <bold>{ it }</bold>
3 [LAMBDA CALLS] fun foo(<bold>f: (Int) -> Int</bold>): Int {
4 [LAMBDA CALLS] val x = <bold>f</bold>
4 [LAMBDA CALLS] val <bold>x = f</bold>
5 return x(<bold>1</bold>)
+7 -1
View File
@@ -1,4 +1,4 @@
5 fun bar(a: Int): Int = foo(a) { if (it > 0) <bold>it</bold> else return 0 }
5 fun bar(<bold>a: Int</bold>): Int = foo(a) { if (it > 0) it else return 0 }
5 fun <bold>bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 }</bold>
5 fun bar(a: Int): Int = <bold>foo(a) { if (it > 0) it else return 0 }</bold>
3 inline fun <bold>foo(a: Int, f: (Int) -> Int) = f(a)</bold>
@@ -9,6 +9,12 @@
5 fun bar(a: Int): Int = foo(a) <bold>{ if (it > 0) it else return 0 }</bold>
5 fun bar(a: Int): Int = foo(a) { <bold>if (it > 0) it else return 0</bold> }
5 fun bar(a: Int): Int = foo(a) { if (it > 0) <bold>it</bold> else return 0 }
5 [LAMBDA CALLS] fun bar(a: Int): Int = foo(a) <bold>{ if (it > 0) it else return 0 }</bold>
3 [LAMBDA CALLS] inline fun foo(a: Int, <bold>f: (Int) -> Int</bold>) = f(a)
3 inline fun foo(a: Int, f: (Int) -> Int) = f(<bold>a</bold>)
3 inline fun foo(<bold>a: Int</bold>, f: (Int) -> Int) = f(a)
5 fun bar(a: Int): Int = foo(<bold>a</bold>) { if (it > 0) it else return 0 }
5 fun bar(<bold>a: Int</bold>): Int = foo(a) { if (it > 0) it else return 0 }
5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return <bold>0</bold> }
5 fun <bold>bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 }</bold>
@@ -8,4 +8,10 @@
5 fun bar(a: Int): Int = foo(a) <bold>{ if (it > 0) it else return 0 }</bold>
5 fun bar(a: Int): Int = foo(a) { <bold>if (it > 0) it else return 0</bold> }
5 fun bar(a: Int): Int = foo(a) { if (it > 0) <bold>it</bold> else return 0 }
5 [LAMBDA CALLS] fun bar(a: Int): Int = foo(a) <bold>{ if (it > 0) it else return 0 }</bold>
3 [LAMBDA CALLS] inline fun foo(a: Int, <bold>f: (Int) -> Int</bold>) = f(a)
3 inline fun foo(a: Int, f: (Int) -> Int) = f(<bold>a</bold>)
3 inline fun foo(<bold>a: Int</bold>, f: (Int) -> Int) = f(a)
5 fun bar(a: Int): Int = foo(<bold>a</bold>) { if (it > 0) it else return 0 }
5 fun bar(<bold>a: Int</bold>): Int = foo(a) { if (it > 0) it else return 0 }
5 fun bar(a: Int): Int = foo(a) { if (it > 0) it else return <bold>0</bold> }
@@ -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");
@@ -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");
@@ -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");