Track lambda parameters in inbound data flow analysis
This commit is contained in:
@@ -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>)
|
||||
|
||||
+4
@@ -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>)
|
||||
@@ -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>)
|
||||
@@ -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
@@ -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
@@ -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>)
|
||||
|
||||
|
||||
@@ -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>)
|
||||
|
||||
@@ -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> }
|
||||
|
||||
+20
@@ -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");
|
||||
|
||||
+20
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user