Special handling of inline function to track values from individual calls
This commit is contained in:
@@ -32,10 +32,10 @@ data class ArgumentSliceProducer private constructor(
|
|||||||
parameterDescriptor.containingDeclaration.isExtension
|
parameterDescriptor.containingDeclaration.isExtension
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection<SliceUsage>? {
|
override fun produce(usage: UsageInfo, mode: KotlinSliceAnalysisMode, parent: SliceUsage): Collection<SliceUsage>? {
|
||||||
val element = usage.element ?: return emptyList()
|
val element = usage.element ?: return emptyList()
|
||||||
val argumentExpression = extractArgumentExpression(element) ?: return emptyList()
|
val argumentExpression = extractArgumentExpression(element) ?: return emptyList()
|
||||||
return listOf(KotlinSliceUsage(argumentExpression, parent, behaviour, forcedExpressionMode = true))
|
return listOf(KotlinSliceUsage(argumentExpression, parent, mode, forcedExpressionMode = true))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractArgumentExpression(refElement: PsiElement): PsiElement? {
|
private fun extractArgumentExpression(refElement: PsiElement): PsiElement? {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
|
|
||||||
object CallSliceProducer : SliceProducer {
|
object CallSliceProducer : SliceProducer {
|
||||||
override fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection<SliceUsage>? {
|
override fun produce(usage: UsageInfo, mode: KotlinSliceAnalysisMode, parent: SliceUsage): Collection<SliceUsage>? {
|
||||||
if ((parent as? KotlinSliceUsage)?.behaviour is LambdaCallsBehaviour) {
|
if ((parent as? KotlinSliceUsage)?.mode?.currentBehaviour is LambdaCallsBehaviour) {
|
||||||
// UsageInfo produced by LambdaCallsBehaviour has full call-element and does not require any processing
|
// UsageInfo produced by LambdaCallsBehaviour has full call-element and does not require any processing
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -24,15 +24,22 @@ object CallSliceProducer : SliceProducer {
|
|||||||
when (val refElement = usage.element) {
|
when (val refElement = usage.element) {
|
||||||
null -> {
|
null -> {
|
||||||
val element = (usage.reference as? LightMemberReference)?.element ?: return emptyList()
|
val element = (usage.reference as? LightMemberReference)?.element ?: return emptyList()
|
||||||
return listOf(KotlinSliceUsage(element, parent, behaviour, false))
|
return listOf(KotlinSliceUsage(element, parent, mode, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
is KtExpression -> {
|
is KtExpression -> {
|
||||||
return mutableListOf<SliceUsage>().apply {
|
return mutableListOf<SliceUsage>().apply {
|
||||||
refElement.getCallElementForExactCallee()
|
refElement.getCallElementForExactCallee()
|
||||||
?.let { this += KotlinSliceUsage(it, parent, behaviour, false) }
|
?.let { this += KotlinSliceUsage(it, parent, mode, false) }
|
||||||
refElement.getCallableReferenceForExactCallee()
|
refElement.getCallableReferenceForExactCallee()
|
||||||
?.let { this += KotlinSliceUsage(it, parent, LambdaCallsBehaviour(SliceProducer.Trivial, behaviour), false) }
|
?.let {
|
||||||
|
this += KotlinSliceUsage(
|
||||||
|
it,
|
||||||
|
parent,
|
||||||
|
mode.withBehaviour(LambdaCallsBehaviour(SliceProducer.Trivial)),
|
||||||
|
forcedExpressionMode = true
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.idea.references.readWriteAccessWithFullExpression
|
|||||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
|
||||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
|
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders
|
||||||
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||||
|
import org.jetbrains.kotlin.idea.util.hasInlineModifier
|
||||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -141,8 +142,8 @@ class InflowSlicer(
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (lambda != null) {
|
if (lambda != null) {
|
||||||
if (behaviour is LambdaResultInflowBehaviour) {
|
if (mode.currentBehaviour is LambdaResultInflowBehaviour) {
|
||||||
lambda.passToProcessor(behaviour.originalBehaviour)
|
lambda.passToProcessor(mode.dropBehaviour())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -176,7 +177,7 @@ class InflowSlicer(
|
|||||||
val callable = accessedDescriptor.containingDeclaration as? CallableDescriptor ?: return
|
val callable = accessedDescriptor.containingDeclaration as? CallableDescriptor ?: return
|
||||||
when (val declaration = callable.originalSource.getPsi()) {
|
when (val declaration = callable.originalSource.getPsi()) {
|
||||||
is KtFunctionLiteral -> {
|
is KtFunctionLiteral -> {
|
||||||
declaration.passToProcessorAsValue(LambdaCallsBehaviour(ReceiverSliceProducer, behaviour))
|
declaration.passToProcessorAsValue(mode.withBehaviour(LambdaCallsBehaviour(ReceiverSliceProducer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
is KtCallableDeclaration -> {
|
is KtCallableDeclaration -> {
|
||||||
@@ -194,12 +195,12 @@ class InflowSlicer(
|
|||||||
processCalls(functionLiteral, false, ArgumentSliceProducer(parameterDescriptor))
|
processCalls(functionLiteral, false, ArgumentSliceProducer(parameterDescriptor))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
accessedDeclaration.passDeclarationToProcessorWithOverriders()
|
accessedDeclaration.passDeclarationToProcessorWithOverriders(createdAt.element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
accessedDeclaration?.passDeclarationToProcessorWithOverriders()
|
accessedDeclaration?.passDeclarationToProcessorWithOverriders(createdAt.element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,8 +216,8 @@ class InflowSlicer(
|
|||||||
val referencedDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, callableRefExpr.callableReference] ?: return
|
val referencedDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, callableRefExpr.callableReference] ?: return
|
||||||
val referencedDeclaration = (referencedDescriptor as? DeclarationDescriptorWithSource)?.originalSource?.getPsi()
|
val referencedDeclaration = (referencedDescriptor as? DeclarationDescriptorWithSource)?.originalSource?.getPsi()
|
||||||
?: return
|
?: return
|
||||||
if (behaviour is LambdaResultInflowBehaviour) {
|
if (mode.currentBehaviour is LambdaResultInflowBehaviour) {
|
||||||
referencedDeclaration.passToProcessor(behaviour.originalBehaviour)
|
referencedDeclaration.passToProcessor(mode.dropBehaviour())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,9 +229,9 @@ class InflowSlicer(
|
|||||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||||
if (resultingDescriptor is FunctionInvokeDescriptor) {
|
if (resultingDescriptor is FunctionInvokeDescriptor) {
|
||||||
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression
|
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression
|
||||||
?.passToProcessorAsValue(LambdaResultInflowBehaviour(behaviour))
|
?.passToProcessorAsValue(mode.withBehaviour(LambdaResultInflowBehaviour))
|
||||||
} else {
|
} else {
|
||||||
resultingDescriptor.originalSource.getPsi()?.passDeclarationToProcessorWithOverriders()
|
resultingDescriptor.originalSource.getPsi()?.passDeclarationToProcessorWithOverriders(createdAt.element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,19 +306,37 @@ class InflowSlicer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PsiElement.passDeclarationToProcessorWithOverriders() {
|
private fun PsiElement.passDeclarationToProcessorWithOverriders(callElement: KtElement) {
|
||||||
passToProcessor()
|
val newMode = if (this is KtNamedFunction && hasInlineModifier())
|
||||||
|
mode.withInlineFunctionCall(callElement, this)
|
||||||
|
else
|
||||||
|
mode
|
||||||
|
|
||||||
|
passToProcessor(newMode)
|
||||||
|
|
||||||
HierarchySearchRequest(this, analysisScope)
|
HierarchySearchRequest(this, analysisScope)
|
||||||
.searchOverriders()
|
.searchOverriders()
|
||||||
.forEach { it.namedUnwrappedElement?.passToProcessor() }
|
.forEach { it.namedUnwrappedElement?.passToProcessor(newMode) }
|
||||||
|
|
||||||
if (this is KtCallableDeclaration && isExpectDeclaration()) {
|
if (this is KtCallableDeclaration && isExpectDeclaration()) {
|
||||||
resolveToDescriptorIfAny(BodyResolveMode.FULL)
|
resolveToDescriptorIfAny(BodyResolveMode.FULL)
|
||||||
?.actualsForExpected()
|
?.actualsForExpected()
|
||||||
?.forEach {
|
?.forEach {
|
||||||
(it as? DeclarationDescriptorWithSource)?.originalSource?.getPsi()?.passToProcessor()
|
(it as? DeclarationDescriptorWithSource)?.originalSource?.getPsi()?.passToProcessor(newMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun processCalls(callable: KtCallableDeclaration, includeOverriders: Boolean, sliceProducer: SliceProducer) {
|
||||||
|
if (callable is KtNamedFunction) {
|
||||||
|
val (newMode, callElement) = mode.popInlineFunctionCall(callable)
|
||||||
|
if (newMode != null && callElement != null) {
|
||||||
|
val sliceUsage = KotlinSliceUsage(callElement, parentUsage, newMode, false)
|
||||||
|
sliceProducer.produceAndProcess(sliceUsage, newMode, parentUsage, processor)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.processCalls(callable, includeOverriders, sliceProducer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||||
|
|
||||||
|
data class KotlinSliceAnalysisMode(val behaviourStack: List<Behaviour>, val inlineCallStack: List<InlineFunctionCall>) {
|
||||||
|
fun withBehaviour(behaviour: Behaviour) = copy(behaviourStack = behaviourStack + behaviour)
|
||||||
|
|
||||||
|
fun withInlineFunctionCall(
|
||||||
|
callElement: KtElement,
|
||||||
|
function: KtNamedFunction
|
||||||
|
) = copy(inlineCallStack = inlineCallStack + InlineFunctionCall(callElement, function))
|
||||||
|
|
||||||
|
fun dropBehaviour(): KotlinSliceAnalysisMode {
|
||||||
|
check(behaviourStack.isNotEmpty())
|
||||||
|
return copy(behaviourStack = behaviourStack.dropLast(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popInlineFunctionCall(function: KtNamedFunction): Pair<KotlinSliceAnalysisMode?, KtElement?> {
|
||||||
|
val last = inlineCallStack.lastOrNull()
|
||||||
|
if (last?.function != function) return null to null
|
||||||
|
val newMode = copy(inlineCallStack = inlineCallStack.dropLast(1))
|
||||||
|
return newMode to last.callElement
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentBehaviour: Behaviour?
|
||||||
|
get() = behaviourStack.lastOrNull()
|
||||||
|
|
||||||
|
interface Behaviour {
|
||||||
|
fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor)
|
||||||
|
|
||||||
|
val slicePresentationPrefix: String
|
||||||
|
val testPresentationPrefix: String
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean
|
||||||
|
override fun hashCode(): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class InlineFunctionCall(callElement: KtElement, function: KtNamedFunction) {
|
||||||
|
private val callElementPointer = callElement.createSmartPointer()
|
||||||
|
private val functionPointer = function.createSmartPointer()
|
||||||
|
|
||||||
|
val callElement: KtElement?
|
||||||
|
get() = callElementPointer.element
|
||||||
|
|
||||||
|
val function: KtNamedFunction?
|
||||||
|
get() = functionPointer.element
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
return other is InlineFunctionCall && other.callElement == callElement && other.function == function
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode() = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val Default = KotlinSliceAnalysisMode(emptyList(), emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,8 +14,8 @@ import org.jetbrains.kotlin.idea.KotlinBundle
|
|||||||
class KotlinSliceDereferenceUsage(
|
class KotlinSliceDereferenceUsage(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
parent: KotlinSliceUsage,
|
parent: KotlinSliceUsage,
|
||||||
behaviour: SpecialBehaviour?
|
mode: KotlinSliceAnalysisMode
|
||||||
) : KotlinSliceUsage(element, parent, behaviour, false) {
|
) : KotlinSliceUsage(element, parent, mode, false) {
|
||||||
override fun processChildren(processor: Processor<in SliceUsage>) {
|
override fun processChildren(processor: Processor<in SliceUsage>) {
|
||||||
// no children
|
// no children
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import org.jetbrains.kotlin.idea.KotlinBundle
|
|||||||
class KotlinSliceDereferenceUsage(
|
class KotlinSliceDereferenceUsage(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
parent: KotlinSliceUsage,
|
parent: KotlinSliceUsage,
|
||||||
behaviour: SpecialBehaviour?
|
mode: KotlinSliceAnalysisMode
|
||||||
) : KotlinSliceUsage(element, parent, behaviour, false) {
|
) : KotlinSliceUsage(element, parent, mode, false) {
|
||||||
override fun processChildren(processor: Processor<SliceUsage>) {
|
override fun processChildren(processor: Processor<SliceUsage>) {
|
||||||
// no children
|
// no children
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class KotlinSliceProvider : SliceLanguageSupportProvider, SliceUsageTransformer
|
|||||||
}
|
}
|
||||||
|
|
||||||
val leafAnalyzer by lazy { SliceLeafAnalyzer(LEAF_ELEMENT_EQUALITY, this) }
|
val leafAnalyzer by lazy { SliceLeafAnalyzer(LEAF_ELEMENT_EQUALITY, this) }
|
||||||
|
|
||||||
val nullnessAnalyzer: SliceNullnessAnalyzerBase by lazy {
|
val nullnessAnalyzer: SliceNullnessAnalyzerBase by lazy {
|
||||||
object : SliceNullnessAnalyzerBase(LEAF_ELEMENT_EQUALITY, this) {
|
object : SliceNullnessAnalyzerBase(LEAF_ELEMENT_EQUALITY, this) {
|
||||||
override fun checkNullability(element: PsiElement?): Nullability {
|
override fun checkNullability(element: PsiElement?): Nullability {
|
||||||
@@ -72,7 +73,7 @@ class KotlinSliceProvider : SliceLanguageSupportProvider, SliceUsageTransformer
|
|||||||
|
|
||||||
override fun transform(usage: SliceUsage): Collection<SliceUsage>? {
|
override fun transform(usage: SliceUsage): Collection<SliceUsage>? {
|
||||||
if (usage is KotlinSliceUsage) return null
|
if (usage is KotlinSliceUsage) return null
|
||||||
return listOf(KotlinSliceUsage(usage.element, usage.parent, null, false))
|
return listOf(KotlinSliceUsage(usage.element, usage.parent, KotlinSliceAnalysisMode.Default, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExpressionAtCaret(atCaret: PsiElement, dataFlowToThis: Boolean): KtElement? {
|
override fun getExpressionAtCaret(atCaret: PsiElement, dataFlowToThis: Boolean): KtElement? {
|
||||||
|
|||||||
@@ -24,57 +24,61 @@ import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor
|
|||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
open class KotlinSliceUsage : SliceUsage {
|
open class KotlinSliceUsage : SliceUsage {
|
||||||
interface SpecialBehaviour {
|
|
||||||
val originalBehaviour: SpecialBehaviour?
|
|
||||||
fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor)
|
|
||||||
|
|
||||||
val slicePresentationPrefix: String
|
val mode: KotlinSliceAnalysisMode
|
||||||
val testPresentationPrefix: String
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean
|
|
||||||
override fun hashCode(): Int
|
|
||||||
}
|
|
||||||
|
|
||||||
val behaviour: SpecialBehaviour?
|
|
||||||
val forcedExpressionMode: Boolean
|
val forcedExpressionMode: Boolean
|
||||||
|
|
||||||
|
private var usageInfo: UsageInfo? = null
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
parent: SliceUsage,
|
parent: SliceUsage,
|
||||||
behaviour: SpecialBehaviour?,
|
mode: KotlinSliceAnalysisMode,
|
||||||
forcedExpressionMode: Boolean,
|
forcedExpressionMode: Boolean,
|
||||||
) : super(element, parent) {
|
) : super(element, parent) {
|
||||||
this.behaviour = behaviour
|
this.mode = mode
|
||||||
this.forcedExpressionMode = forcedExpressionMode
|
this.forcedExpressionMode = forcedExpressionMode
|
||||||
|
initializeUsageInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(element: PsiElement, params: SliceAnalysisParams) : super(element, params) {
|
constructor(element: PsiElement, params: SliceAnalysisParams) : super(element, params) {
|
||||||
this.behaviour = null
|
this.mode = KotlinSliceAnalysisMode.Default
|
||||||
this.forcedExpressionMode = false
|
this.forcedExpressionMode = false
|
||||||
|
initializeUsageInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeUsageInfo() {
|
||||||
|
val originalInfo = getUsageInfo()
|
||||||
|
if (mode != KotlinSliceAnalysisMode.Default) {
|
||||||
|
val element = originalInfo.element
|
||||||
|
if (element != null) {
|
||||||
|
usageInfo = UsageInfoWrapper(element, mode)
|
||||||
|
} else {
|
||||||
|
usageInfo = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
usageInfo = originalInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have to replace UsageInfo with another one whose equality takes into account mode
|
||||||
|
override fun getUsageInfo(): UsageInfo {
|
||||||
|
return usageInfo ?: super.getUsageInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun copy(): KotlinSliceUsage {
|
override fun copy(): KotlinSliceUsage {
|
||||||
val element = usageInfo.element!!
|
val element = getUsageInfo().element!!
|
||||||
return if (parent == null)
|
return if (parent == null)
|
||||||
KotlinSliceUsage(element, params)
|
KotlinSliceUsage(element, params)
|
||||||
else
|
else
|
||||||
KotlinSliceUsage(element, parent, behaviour, forcedExpressionMode)
|
KotlinSliceUsage(element, parent, mode, forcedExpressionMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getUsageInfo(): UsageInfo {
|
override fun canBeLeaf() = element != null && mode == KotlinSliceAnalysisMode.Default
|
||||||
val originalInfo = super.getUsageInfo()
|
|
||||||
if (behaviour != null) {
|
|
||||||
val element = originalInfo.element ?: return originalInfo
|
|
||||||
// Do not let IDEA consider usages of the same anonymous function as duplicates when their levels differ
|
|
||||||
return UsageInfoWrapper(element, behaviour)
|
|
||||||
}
|
|
||||||
return originalInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun canBeLeaf() = element != null && behaviour == null
|
|
||||||
|
|
||||||
public override fun processUsagesFlownDownTo(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
public override fun processUsagesFlownDownTo(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
||||||
val ktElement = element as? KtElement ?: return
|
val ktElement = element as? KtElement ?: return
|
||||||
|
val behaviour = mode.currentBehaviour
|
||||||
if (behaviour != null) {
|
if (behaviour != null) {
|
||||||
behaviour.processUsages(ktElement, this, uniqueProcessor)
|
behaviour.processUsages(ktElement, this, uniqueProcessor)
|
||||||
} else {
|
} else {
|
||||||
@@ -84,6 +88,7 @@ open class KotlinSliceUsage : SliceUsage {
|
|||||||
|
|
||||||
public override fun processUsagesFlownFromThe(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
public override fun processUsagesFlownFromThe(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
||||||
val ktElement = element as? KtElement ?: return
|
val ktElement = element as? KtElement ?: return
|
||||||
|
val behaviour = mode.currentBehaviour
|
||||||
if (behaviour != null) {
|
if (behaviour != null) {
|
||||||
behaviour.processUsages(ktElement, this, uniqueProcessor)
|
behaviour.processUsages(ktElement, this, uniqueProcessor)
|
||||||
} else {
|
} else {
|
||||||
@@ -92,9 +97,9 @@ open class KotlinSliceUsage : SliceUsage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("EqualsOrHashCode")
|
@Suppress("EqualsOrHashCode")
|
||||||
private class UsageInfoWrapper(element: PsiElement, private val behaviour: SpecialBehaviour) : UsageInfo(element) {
|
private class UsageInfoWrapper(element: PsiElement, private val mode: KotlinSliceAnalysisMode) : UsageInfo(element) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return other is UsageInfoWrapper && super.equals(other) && behaviour == other.behaviour
|
return other is UsageInfoWrapper && super.equals(other) && mode == other.mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,10 +43,8 @@ object KotlinSliceUsageCellRenderer : SliceUsageCellRendererBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var behaviour = sliceUsage.behaviour
|
for (behaviour in sliceUsage.mode.behaviourStack.reversed()) {
|
||||||
while (behaviour != null) {
|
|
||||||
append(behaviour.slicePresentationPrefix, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES)
|
append(behaviour.slicePresentationPrefix, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES)
|
||||||
behaviour = behaviour.originalBehaviour
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val declaration = sliceUsage.element?.parents?.firstOrNull {
|
val declaration = sliceUsage.element?.parents?.firstOrNull {
|
||||||
|
|||||||
@@ -12,20 +12,17 @@ import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor
|
|||||||
import org.jetbrains.kotlin.psi.Call
|
import org.jetbrains.kotlin.psi.Call
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
data class LambdaCallsBehaviour(
|
data class LambdaCallsBehaviour(private val sliceProducer: SliceProducer) : KotlinSliceAnalysisMode.Behaviour {
|
||||||
val sliceProducer: SliceProducer,
|
|
||||||
override val originalBehaviour: KotlinSliceUsage.SpecialBehaviour?
|
|
||||||
) : KotlinSliceUsage.SpecialBehaviour {
|
|
||||||
|
|
||||||
override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) {
|
override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) {
|
||||||
val processor = object : SliceUsageProcessor {
|
val processor = object : SliceUsageProcessor {
|
||||||
override fun process(sliceUsage: SliceUsage): Boolean {
|
override fun process(sliceUsage: SliceUsage): Boolean {
|
||||||
if (sliceUsage is KotlinSliceUsage && sliceUsage.behaviour === this@LambdaCallsBehaviour) {
|
if (sliceUsage is KotlinSliceUsage && sliceUsage.mode.currentBehaviour === this@LambdaCallsBehaviour) {
|
||||||
val sliceElement = sliceUsage.element ?: return true
|
val sliceElement = sliceUsage.element ?: return true
|
||||||
val resolvedCall = (sliceElement as? KtElement)?.resolveToCall()
|
val resolvedCall = (sliceElement as? KtElement)?.resolveToCall()
|
||||||
if (resolvedCall?.call?.callType == Call.CallType.INVOKE) {
|
if (resolvedCall?.call?.callType == Call.CallType.INVOKE) {
|
||||||
val newSliceUsage = KotlinSliceUsage(resolvedCall.call.callElement, parent, originalBehaviour, true)
|
val originalMode = sliceUsage.mode.dropBehaviour()
|
||||||
return sliceProducer.produceAndProcess(newSliceUsage, originalBehaviour, parent, uniqueProcessor)
|
val newSliceUsage = KotlinSliceUsage(resolvedCall.call.callElement, parent, originalMode, true)
|
||||||
|
return sliceProducer.produceAndProcess(newSliceUsage, originalMode, parent, uniqueProcessor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return uniqueProcessor.process(sliceUsage)
|
return uniqueProcessor.process(sliceUsage)
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.idea.KotlinBundle
|
|||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor
|
import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
data class LambdaResultInflowBehaviour(
|
object LambdaResultInflowBehaviour : KotlinSliceAnalysisMode.Behaviour {
|
||||||
override val originalBehaviour: KotlinSliceUsage.SpecialBehaviour?
|
|
||||||
) : KotlinSliceUsage.SpecialBehaviour {
|
|
||||||
|
|
||||||
override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) {
|
override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) {
|
||||||
InflowSlicer(element, uniqueProcessor, parent).processChildren(parent.forcedExpressionMode)
|
InflowSlicer(element, uniqueProcessor, parent).processChildren(parent.forcedExpressionMode)
|
||||||
}
|
}
|
||||||
@@ -22,4 +19,7 @@ data class LambdaResultInflowBehaviour(
|
|||||||
|
|
||||||
override val testPresentationPrefix: String
|
override val testPresentationPrefix: String
|
||||||
get() = "[LAMBDA IN] "
|
get() = "[LAMBDA IN] "
|
||||||
|
|
||||||
|
override fun equals(other: Any?) = other === this
|
||||||
|
override fun hashCode() = 0
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.idea.slicer
|
package org.jetbrains.kotlin.idea.slicer
|
||||||
|
|
||||||
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access
|
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
||||||
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor
|
|||||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingElement
|
import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingElement
|
||||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector
|
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector
|
||||||
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
import org.jetbrains.kotlin.idea.util.actualsForExpected
|
||||||
|
import org.jetbrains.kotlin.idea.util.hasInlineModifier
|
||||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
||||||
@@ -200,7 +202,7 @@ class OutflowSlicer(
|
|||||||
|
|
||||||
is CallInstruction -> {
|
is CallInstruction -> {
|
||||||
if (!processIfReceiverValue(instruction, pseudoValue)) {
|
if (!processIfReceiverValue(instruction, pseudoValue)) {
|
||||||
instruction.arguments[pseudoValue]?.originalSource?.getPsi()?.passToProcessor()
|
instruction.arguments[pseudoValue]?.originalSource?.getPsi()?.passCalledDeclarationToProcessor(instruction.element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,13 +228,13 @@ class OutflowSlicer(
|
|||||||
Call.CallType.DEFAULT -> {
|
Call.CallType.DEFAULT -> {
|
||||||
if (receiverValue == resolvedCall.extensionReceiver) {
|
if (receiverValue == resolvedCall.extensionReceiver) {
|
||||||
val targetDeclaration = resolvedCall.resultingDescriptor.originalSource.getPsi()
|
val targetDeclaration = resolvedCall.resultingDescriptor.originalSource.getPsi()
|
||||||
(targetDeclaration as? KtCallableDeclaration)?.receiverTypeReference?.passToProcessor()
|
(targetDeclaration as? KtCallableDeclaration)?.receiverTypeReference?.passCalledDeclarationToProcessor(instruction.element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Call.CallType.INVOKE -> {
|
Call.CallType.INVOKE -> {
|
||||||
if (receiverValue == resolvedCall.dispatchReceiver && behaviour is LambdaCallsBehaviour) {
|
if (receiverValue == resolvedCall.dispatchReceiver && mode.currentBehaviour is LambdaCallsBehaviour) {
|
||||||
instruction.element.passToProcessor(behaviour)
|
instruction.element.passCalledDeclarationToProcessor(instruction.element, mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +260,7 @@ class OutflowSlicer(
|
|||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
|
if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
|
||||||
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, behaviour))
|
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, mode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,4 +278,20 @@ class OutflowSlicer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.passCalledDeclarationToProcessor(
|
||||||
|
callElement: KtElement,
|
||||||
|
mode: KotlinSliceAnalysisMode = this@OutflowSlicer.mode
|
||||||
|
) {
|
||||||
|
var newMode = mode
|
||||||
|
when (this) {
|
||||||
|
is KtParameter -> {
|
||||||
|
val ownerFunction = ownerFunction as? KtNamedFunction
|
||||||
|
if (ownerFunction != null && ownerFunction.hasInlineModifier()) {
|
||||||
|
newMode = mode.withInlineFunctionCall(callElement, ownerFunction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
passToProcessor(newMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
|||||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
|
||||||
object ReceiverSliceProducer : SliceProducer {
|
object ReceiverSliceProducer : SliceProducer {
|
||||||
override fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection<SliceUsage>? {
|
override fun produce(usage: UsageInfo, mode: KotlinSliceAnalysisMode, parent: SliceUsage): Collection<SliceUsage>? {
|
||||||
val refElement = usage.element ?: return emptyList()
|
val refElement = usage.element ?: return emptyList()
|
||||||
when (refElement) {
|
when (refElement) {
|
||||||
is KtExpression -> {
|
is KtExpression -> {
|
||||||
val resolvedCall = refElement.resolveToCall() ?: return emptyList()
|
val resolvedCall = refElement.resolveToCall() ?: return emptyList()
|
||||||
when (val receiver = resolvedCall.extensionReceiver) {
|
when (val receiver = resolvedCall.extensionReceiver) {
|
||||||
is ExpressionReceiver -> {
|
is ExpressionReceiver -> {
|
||||||
return listOf(KotlinSliceUsage(receiver.expression, parent, behaviour, forcedExpressionMode = true))
|
return listOf(KotlinSliceUsage(receiver.expression, parent, mode, forcedExpressionMode = true))
|
||||||
}
|
}
|
||||||
|
|
||||||
is ImplicitReceiver -> {
|
is ImplicitReceiver -> {
|
||||||
@@ -33,13 +33,13 @@ object ReceiverSliceProducer : SliceProducer {
|
|||||||
?: return emptyList()
|
?: return emptyList()
|
||||||
when (val callableDeclaration = callableDescriptor.originalSource.getPsi()) {
|
when (val callableDeclaration = callableDescriptor.originalSource.getPsi()) {
|
||||||
is KtFunctionLiteral -> {
|
is KtFunctionLiteral -> {
|
||||||
val newBehaviour = LambdaCallsBehaviour(ReceiverSliceProducer, behaviour)
|
val newMode = mode.withBehaviour(LambdaCallsBehaviour(ReceiverSliceProducer))
|
||||||
return listOf(KotlinSliceUsage(callableDeclaration, parent, newBehaviour, forcedExpressionMode = true))
|
return listOf(KotlinSliceUsage(callableDeclaration, parent, newMode, forcedExpressionMode = true))
|
||||||
}
|
}
|
||||||
|
|
||||||
is KtCallableDeclaration -> {
|
is KtCallableDeclaration -> {
|
||||||
val receiverTypeReference = callableDeclaration.receiverTypeReference ?: return emptyList()
|
val receiverTypeReference = callableDeclaration.receiverTypeReference ?: return emptyList()
|
||||||
return listOf(KotlinSliceUsage(receiverTypeReference, parent, behaviour, false))
|
return listOf(KotlinSliceUsage(receiverTypeReference, parent, mode, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return emptyList()
|
else -> return emptyList()
|
||||||
@@ -52,7 +52,7 @@ object ReceiverSliceProducer : SliceProducer {
|
|||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val argument = (refElement.parent as? PsiCall)?.argumentList?.expressions?.getOrNull(0) ?: return emptyList()
|
val argument = (refElement.parent as? PsiCall)?.argumentList?.expressions?.getOrNull(0) ?: return emptyList()
|
||||||
return listOf(KotlinSliceUsage(argument, parent, behaviour, true))
|
return listOf(KotlinSliceUsage(argument, parent, mode, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ import com.intellij.usageView.UsageInfo
|
|||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor
|
import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor
|
||||||
|
|
||||||
interface SliceProducer {
|
interface SliceProducer {
|
||||||
fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection<SliceUsage>?
|
fun produce(usage: UsageInfo, mode: KotlinSliceAnalysisMode, parent: SliceUsage): Collection<SliceUsage>?
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean
|
override fun equals(other: Any?): Boolean
|
||||||
override fun hashCode(): Int
|
override fun hashCode(): Int
|
||||||
|
|
||||||
object Trivial : SliceProducer {
|
object Trivial : SliceProducer {
|
||||||
override fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection<SliceUsage>? {
|
override fun produce(usage: UsageInfo, mode: KotlinSliceAnalysisMode, parent: SliceUsage): Collection<SliceUsage>? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,11 +27,11 @@ interface SliceProducer {
|
|||||||
|
|
||||||
fun SliceProducer.produceAndProcess(
|
fun SliceProducer.produceAndProcess(
|
||||||
sliceUsage: SliceUsage,
|
sliceUsage: SliceUsage,
|
||||||
behaviour: KotlinSliceUsage.SpecialBehaviour?,
|
mode: KotlinSliceAnalysisMode,
|
||||||
parentUsage: SliceUsage,
|
parentUsage: SliceUsage,
|
||||||
processor: SliceUsageProcessor
|
processor: SliceUsageProcessor
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val result = produce(sliceUsage.usageInfo, behaviour, parentUsage) ?: listOf(sliceUsage)
|
val result = produce(sliceUsage.usageInfo, mode, parentUsage) ?: listOf(sliceUsage)
|
||||||
for (usage in result) {
|
for (usage in result) {
|
||||||
if (!processor.process(usage)) return false
|
if (!processor.process(usage)) return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ abstract class Slicer(
|
|||||||
abstract fun processChildren(forcedExpressionMode: Boolean)
|
abstract fun processChildren(forcedExpressionMode: Boolean)
|
||||||
|
|
||||||
protected val analysisScope: SearchScope = parentUsage.scope.toSearchScope()
|
protected val analysisScope: SearchScope = parentUsage.scope.toSearchScope()
|
||||||
protected val behaviour: KotlinSliceUsage.SpecialBehaviour? = parentUsage.behaviour
|
protected val mode: KotlinSliceAnalysisMode = parentUsage.mode
|
||||||
protected val project = element.project
|
protected val project = element.project
|
||||||
|
|
||||||
protected class PseudocodeCache {
|
protected class PseudocodeCache {
|
||||||
@@ -57,24 +57,21 @@ abstract class Slicer(
|
|||||||
|
|
||||||
protected val pseudocodeCache = PseudocodeCache()
|
protected val pseudocodeCache = PseudocodeCache()
|
||||||
|
|
||||||
protected fun PsiElement.passToProcessor(
|
protected fun PsiElement.passToProcessor(mode: KotlinSliceAnalysisMode = this@Slicer.mode) {
|
||||||
behaviour: KotlinSliceUsage.SpecialBehaviour? = this@Slicer.behaviour,
|
processor.process(KotlinSliceUsage(this, parentUsage, mode, false))
|
||||||
forcedExpressionMode: Boolean = false,
|
|
||||||
) {
|
|
||||||
processor.process(KotlinSliceUsage(this, parentUsage, behaviour, forcedExpressionMode))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun PsiElement.passToProcessorAsValue(behaviour: KotlinSliceUsage.SpecialBehaviour? = this@Slicer.behaviour) {
|
protected fun PsiElement.passToProcessorAsValue(mode: KotlinSliceAnalysisMode = this@Slicer.mode) {
|
||||||
passToProcessor(behaviour, forcedExpressionMode = true)
|
processor.process(KotlinSliceUsage(this, parentUsage, mode, forcedExpressionMode = true))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun processCalls(
|
protected open fun processCalls(
|
||||||
callable: KtCallableDeclaration,
|
callable: KtCallableDeclaration,
|
||||||
includeOverriders: Boolean,
|
includeOverriders: Boolean,
|
||||||
sliceProducer: SliceProducer
|
sliceProducer: SliceProducer,
|
||||||
) {
|
) {
|
||||||
if (callable is KtFunctionLiteral || callable is KtFunction && callable.name == null) {
|
if (callable is KtFunctionLiteral || callable is KtFunction && callable.name == null) {
|
||||||
callable.passToProcessorAsValue(LambdaCallsBehaviour(sliceProducer, behaviour))
|
callable.passToProcessorAsValue(mode.withBehaviour(LambdaCallsBehaviour(sliceProducer)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,8 +114,8 @@ abstract class Slicer(
|
|||||||
is KtDeclaration -> {
|
is KtDeclaration -> {
|
||||||
val usageProcessor: (UsageInfo) -> Unit = processor@ { usageInfo ->
|
val usageProcessor: (UsageInfo) -> Unit = processor@ { usageInfo ->
|
||||||
val element = usageInfo.element ?: return@processor
|
val element = usageInfo.element ?: return@processor
|
||||||
val sliceUsage = KotlinSliceUsage(element, parentUsage, behaviour, false)
|
val sliceUsage = KotlinSliceUsage(element, parentUsage, mode, false)
|
||||||
sliceProducer.produceAndProcess(sliceUsage, behaviour, parentUsage, processor)
|
sliceProducer.produceAndProcess(sliceUsage, mode, parentUsage, processor)
|
||||||
}
|
}
|
||||||
if (includeOverriders) {
|
if (includeOverriders) {
|
||||||
declaration.processAllUsages(options, usageProcessor)
|
declaration.processAllUsages(options, usageProcessor)
|
||||||
@@ -129,12 +126,12 @@ abstract class Slicer(
|
|||||||
|
|
||||||
is PsiMethod -> {
|
is PsiMethod -> {
|
||||||
val sliceUsage = JavaSliceUsage.createRootUsage(declaration, parentUsage.params)
|
val sliceUsage = JavaSliceUsage.createRootUsage(declaration, parentUsage.params)
|
||||||
sliceProducer.produceAndProcess(sliceUsage, behaviour, parentUsage, processor)
|
sliceProducer.produceAndProcess(sliceUsage, mode, parentUsage, processor)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val sliceUsage = KotlinSliceUsage(declaration, parentUsage, behaviour, false)
|
val sliceUsage = KotlinSliceUsage(declaration, parentUsage, mode, false)
|
||||||
sliceProducer.produceAndProcess(sliceUsage, behaviour, parentUsage, processor)
|
sliceProducer.produceAndProcess(sliceUsage, mode, parentUsage, processor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
5 val <bold>v = this</bold>
|
5 val <bold>v = this</bold>
|
||||||
5 val v = <bold>this</bold>
|
5 val v = <bold>this</bold>
|
||||||
4 [LAMBDA CALLS] with("A") <bold>{</bold>
|
4 [LAMBDA CALLS] with("A") <bold>{</bold>
|
||||||
9 [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
9 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
10 return <bold>receiver</bold>.block()
|
10 (INLINE CALL with) return <bold>receiver</bold>.block()
|
||||||
9 inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
9 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
4 with(<bold>"A"</bold>) {
|
4 with(<bold>"A"</bold>) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
5 val <bold>v = this</bold>
|
5 val <bold>v = this</bold>
|
||||||
5 val v = <bold>this</bold>
|
5 val v = <bold>this</bold>
|
||||||
4 [LAMBDA CALLS] with("A") <bold>{</bold>
|
4 [LAMBDA CALLS] with("A") <bold>{</bold>
|
||||||
9 [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
9 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
10 return <bold>receiver</bold>.block()
|
10 (INLINE CALL with) return <bold>receiver</bold>.block()
|
||||||
9 inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
9 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
4 with(<bold>"A"</bold>) {
|
4 with(<bold>"A"</bold>) {
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// FLOW: IN
|
||||||
|
|
||||||
|
fun <caret>Any.extensionFun() {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.foo() {
|
||||||
|
with(123) {
|
||||||
|
extensionFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
with(456) {
|
||||||
|
this.extensionFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
with(789) {
|
||||||
|
// no calls here
|
||||||
|
}
|
||||||
|
|
||||||
|
withNoInline(1) {
|
||||||
|
extensionFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
withNoInline(2) {
|
||||||
|
// no calls here
|
||||||
|
}
|
||||||
|
|
||||||
|
"A".let {
|
||||||
|
it.extensionFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
"B".let {
|
||||||
|
// no calls here
|
||||||
|
}
|
||||||
|
|
||||||
|
"D".letNoInline {
|
||||||
|
it.extensionFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
"C".letNoInline {
|
||||||
|
// no calls here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
|
||||||
|
val result = receiver.block()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T, R> T.let(block: (T) -> R): R {
|
||||||
|
return block(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, R> withNoInline(receiver: T, block: T.() -> R): R {
|
||||||
|
val result = receiver.block()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, R> T.letNoInline(block: (T) -> R): R {
|
||||||
|
return block(this)
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
35 <bold>"D"</bold>.letNoInline {
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
36 <bold>it</bold>.extensionFun()
|
||||||
|
35 [LAMBDA CALLS] "D".letNoInline <bold>{</bold>
|
||||||
|
58 [LAMBDA CALLS] fun <T, R> T.letNoInline(<bold>block: (T) -> R</bold>): R {
|
||||||
|
59 return block(<bold>this</bold>)
|
||||||
|
58 fun <T, R> <bold>T</bold>.letNoInline(block: (T) -> R): R {
|
||||||
|
35 <bold>"D"</bold>.letNoInline {
|
||||||
|
|
||||||
|
39 <bold>"C"</bold>.letNoInline {
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
36 <bold>it</bold>.extensionFun()
|
||||||
|
35 [LAMBDA CALLS] "D".letNoInline <bold>{</bold>
|
||||||
|
58 [LAMBDA CALLS] fun <T, R> T.letNoInline(<bold>block: (T) -> R</bold>): R {
|
||||||
|
59 return block(<bold>this</bold>)
|
||||||
|
58 fun <T, R> <bold>T</bold>.letNoInline(block: (T) -> R): R {
|
||||||
|
39 <bold>"C"</bold>.letNoInline {
|
||||||
|
|
||||||
|
27 <bold>"A"</bold>.let {
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
28 <bold>it</bold>.extensionFun()
|
||||||
|
27 [LAMBDA CALLS] "A".let <bold>{</bold>
|
||||||
|
49 (INLINE CALL let) [LAMBDA CALLS] inline fun <T, R> T.let(<bold>block: (T) -> R</bold>): R {
|
||||||
|
50 (INLINE CALL let) return block(<bold>this</bold>)
|
||||||
|
49 (INLINE CALL let) inline fun <T, R> <bold>T</bold>.let(block: (T) -> R): R {
|
||||||
|
27 <bold>"A"</bold>.let {
|
||||||
|
|
||||||
|
19 withNoInline(<bold>1</bold>) {
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
19 [LAMBDA CALLS] withNoInline(1) <bold>{</bold>
|
||||||
|
53 [LAMBDA CALLS] fun <T, R> withNoInline(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
|
54 val result = <bold>receiver</bold>.block()
|
||||||
|
53 fun <T, R> withNoInline(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
|
19 withNoInline(<bold>1</bold>) {
|
||||||
|
|
||||||
|
7 with(<bold>123</bold>) {
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
7 [LAMBDA CALLS] with(123) <bold>{</bold>
|
||||||
|
44 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
|
45 (INLINE CALL with) val result = <bold>receiver</bold>.block()
|
||||||
|
44 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
|
7 with(<bold>123</bold>) {
|
||||||
|
|
||||||
|
23 withNoInline(<bold>2</bold>) {
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
19 [LAMBDA CALLS] withNoInline(1) <bold>{</bold>
|
||||||
|
53 [LAMBDA CALLS] fun <T, R> withNoInline(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
|
54 val result = <bold>receiver</bold>.block()
|
||||||
|
53 fun <T, R> withNoInline(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
|
23 withNoInline(<bold>2</bold>) {
|
||||||
|
|
||||||
|
11 with(<bold>456</bold>) {
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
12 <bold>this</bold>.extensionFun()
|
||||||
|
11 [LAMBDA CALLS] with(456) <bold>{</bold>
|
||||||
|
44 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
|
45 (INLINE CALL with) val result = <bold>receiver</bold>.block()
|
||||||
|
44 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
|
11 with(<bold>456</bold>) {
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
[NotNull Values]
|
||||||
|
7 with(123) <bold>{</bold>
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
7 [LAMBDA CALLS] with(123) <bold>{</bold>
|
||||||
|
19 [LAMBDA CALLS] withNoInline(1) <bold>{</bold>
|
||||||
|
12 <bold>this</bold>.extensionFun()
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
12 <bold>this</bold>.extensionFun()
|
||||||
|
36 <bold>it</bold>.extensionFun()
|
||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
28 <bold>it</bold>.extensionFun()
|
||||||
|
36 <bold>it</bold>.extensionFun()
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
3 fun <bold>Any</bold>.extensionFun() {
|
||||||
|
7 [LAMBDA CALLS] with(123) <bold>{</bold>
|
||||||
|
44 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
|
45 (INLINE CALL with) val result = <bold>receiver</bold>.block()
|
||||||
|
44 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
|
7 with(<bold>123</bold>) {
|
||||||
|
12 <bold>this</bold>.extensionFun()
|
||||||
|
11 [LAMBDA CALLS] with(456) <bold>{</bold>
|
||||||
|
44 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
|
45 (INLINE CALL with) val result = <bold>receiver</bold>.block()
|
||||||
|
44 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
|
11 with(<bold>456</bold>) {
|
||||||
|
19 [LAMBDA CALLS] withNoInline(1) <bold>{</bold>
|
||||||
|
53 [LAMBDA CALLS] fun <T, R> withNoInline(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
|
54 val result = <bold>receiver</bold>.block()
|
||||||
|
53 fun <T, R> withNoInline(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
|
19 withNoInline(<bold>1</bold>) {
|
||||||
|
23 withNoInline(<bold>2</bold>) {
|
||||||
|
28 <bold>it</bold>.extensionFun()
|
||||||
|
27 [LAMBDA CALLS] "A".let <bold>{</bold>
|
||||||
|
49 (INLINE CALL let) [LAMBDA CALLS] inline fun <T, R> T.let(<bold>block: (T) -> R</bold>): R {
|
||||||
|
50 (INLINE CALL let) return block(<bold>this</bold>)
|
||||||
|
49 (INLINE CALL let) inline fun <T, R> <bold>T</bold>.let(block: (T) -> R): R {
|
||||||
|
27 <bold>"A"</bold>.let {
|
||||||
|
36 <bold>it</bold>.extensionFun()
|
||||||
|
35 [LAMBDA CALLS] "D".letNoInline <bold>{</bold>
|
||||||
|
58 [LAMBDA CALLS] fun <T, R> T.letNoInline(<bold>block: (T) -> R</bold>): R {
|
||||||
|
59 return block(<bold>this</bold>)
|
||||||
|
58 fun <T, R> <bold>T</bold>.letNoInline(block: (T) -> R): R {
|
||||||
|
35 <bold>"D"</bold>.letNoInline {
|
||||||
|
39 <bold>"C"</bold>.letNoInline {
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
5 fun bar(<bold>a: Int</bold>): Int = foo(a) { 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 <bold>bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 }</bold>
|
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>
|
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>
|
3 (INLINE CALL foo) inline fun <bold>foo(a: Int, f: (Int) -> Int) = f(a)</bold>
|
||||||
3 inline fun foo(a: Int, f: (Int) -> Int) = <bold>f(a)</bold>
|
3 (INLINE CALL foo) inline fun foo(a: Int, f: (Int) -> Int) = <bold>f(a)</bold>
|
||||||
3 [LAMBDA IN] inline fun foo(a: Int, f: (Int) -> Int) = <bold>f</bold>(a)
|
3 (INLINE CALL foo) [LAMBDA IN] inline fun foo(a: Int, f: (Int) -> Int) = <bold>f</bold>(a)
|
||||||
3 [LAMBDA IN] inline fun foo(a: Int, <bold>f: (Int) -> Int</bold>) = f(a)
|
3 (INLINE CALL foo) [LAMBDA IN] inline fun foo(a: Int, <bold>f: (Int) -> Int</bold>) = f(a)
|
||||||
5 [LAMBDA IN] fun bar(a: Int): Int = foo(a) <bold>{ if (it > 0) it else return 0 }</bold>
|
5 [LAMBDA IN] 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) <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) { <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 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>
|
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 CALL foo) [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 CALL foo) 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)
|
3 (INLINE CALL foo) 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(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(<bold>a: Int</bold>): Int = foo(a) { if (it > 0) it else return 0 }
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -1,17 +1,17 @@
|
|||||||
5 fun <bold>bar(a: Int): Int = foo(a) { if (it > 0) it else return 0 }</bold>
|
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>
|
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>
|
3 (INLINE CALL foo) inline fun <bold>foo(a: Int, f: (Int) -> Int) = f(a)</bold>
|
||||||
3 inline fun foo(a: Int, f: (Int) -> Int) = <bold>f(a)</bold>
|
3 (INLINE CALL foo) inline fun foo(a: Int, f: (Int) -> Int) = <bold>f(a)</bold>
|
||||||
3 [LAMBDA IN] inline fun foo(a: Int, f: (Int) -> Int) = <bold>f</bold>(a)
|
3 (INLINE CALL foo) [LAMBDA IN] inline fun foo(a: Int, f: (Int) -> Int) = <bold>f</bold>(a)
|
||||||
3 [LAMBDA IN] inline fun foo(a: Int, <bold>f: (Int) -> Int</bold>) = f(a)
|
3 (INLINE CALL foo) [LAMBDA IN] inline fun foo(a: Int, <bold>f: (Int) -> Int</bold>) = f(a)
|
||||||
5 [LAMBDA IN] fun bar(a: Int): Int = foo(a) <bold>{ if (it > 0) it else return 0 }</bold>
|
5 [LAMBDA IN] 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) <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) { <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 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>
|
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 CALL foo) [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 CALL foo) 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)
|
3 (INLINE CALL foo) 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(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(<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 bar(a: Int): Int = foo(a) { if (it > 0) it else return <bold>0</bold> }
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
18 with(<bold>123</bold>) {
|
18 with(<bold>123</bold>) {
|
||||||
8 fun <bold>Any</bold>.extensionFun() {
|
8 fun <bold>Any</bold>.extensionFun() {
|
||||||
18 [LAMBDA CALLS] with(123) <bold>{</bold>
|
18 [LAMBDA CALLS] with(123) <bold>{</bold>
|
||||||
27 [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
27 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
28 return <bold>receiver</bold>.block()
|
28 (INLINE CALL with) return <bold>receiver</bold>.block()
|
||||||
27 inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
27 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
18 with(<bold>123</bold>) {
|
18 with(<bold>123</bold>) {
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
12 <bold>""</bold>.extensionFun()
|
12 <bold>""</bold>.extensionFun()
|
||||||
14 <bold>1</bold>.extensionFun()
|
14 <bold>1</bold>.extensionFun()
|
||||||
18 [LAMBDA CALLS] with(123) <bold>{</bold>
|
18 [LAMBDA CALLS] with(123) <bold>{</bold>
|
||||||
27 [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
27 (INLINE CALL with) [LAMBDA CALLS] inline fun <T, R> with(receiver: T, <bold>block: T.() -> R</bold>): R {
|
||||||
28 return <bold>receiver</bold>.block()
|
28 (INLINE CALL with) return <bold>receiver</bold>.block()
|
||||||
27 inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
27 (INLINE CALL with) inline fun <T, R> with(<bold>receiver: T</bold>, block: T.() -> R): R {
|
||||||
18 with(<bold>123</bold>) {
|
18 with(<bold>123</bold>) {
|
||||||
|
|||||||
+5
@@ -178,6 +178,11 @@ public class SlicerLeafGroupingTestGenerated extends AbstractSlicerLeafGroupingT
|
|||||||
runTest("idea/testData/slicer/inflow/ifExpression.kt");
|
runTest("idea/testData/slicer/inflow/ifExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineFunctionManyCalls.kt")
|
||||||
|
public void testInlineFunctionManyCalls() throws Exception {
|
||||||
|
runTest("idea/testData/slicer/inflow/inlineFunctionManyCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaImplicitParameter.kt")
|
@TestMetadata("lambdaImplicitParameter.kt")
|
||||||
public void testLambdaImplicitParameter() throws Exception {
|
public void testLambdaImplicitParameter() throws Exception {
|
||||||
runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt");
|
runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt");
|
||||||
|
|||||||
+5
@@ -178,6 +178,11 @@ public class SlicerNullnessGroupingTestGenerated extends AbstractSlicerNullnessG
|
|||||||
runTest("idea/testData/slicer/inflow/ifExpression.kt");
|
runTest("idea/testData/slicer/inflow/ifExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineFunctionManyCalls.kt")
|
||||||
|
public void testInlineFunctionManyCalls() throws Exception {
|
||||||
|
runTest("idea/testData/slicer/inflow/inlineFunctionManyCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaImplicitParameter.kt")
|
@TestMetadata("lambdaImplicitParameter.kt")
|
||||||
public void testLambdaImplicitParameter() throws Exception {
|
public void testLambdaImplicitParameter() throws Exception {
|
||||||
runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt");
|
runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt");
|
||||||
|
|||||||
@@ -52,8 +52,10 @@ internal fun buildTreeRepresentation(rootNode: SliceNode): String {
|
|||||||
node.sortedChildren.forEach { append(process(it, indent)) }
|
node.sortedChildren.forEach { append(process(it, indent)) }
|
||||||
return@buildString
|
return@buildString
|
||||||
}
|
}
|
||||||
|
|
||||||
// SliceLeafValueClassNode is package-private
|
// SliceLeafValueClassNode is package-private
|
||||||
node.isSliceLeafValueClassNode() -> append("[${node.nodeText}]\n")
|
node.isSliceLeafValueClassNode() -> append("[${node.nodeText}]\n")
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val chunks = usage.text
|
val chunks = usage.text
|
||||||
append(chunks.first().render() + " ")
|
append(chunks.first().render() + " ")
|
||||||
@@ -62,11 +64,10 @@ internal fun buildTreeRepresentation(rootNode: SliceNode): String {
|
|||||||
append("DEREFERENCE: ")
|
append("DEREFERENCE: ")
|
||||||
}
|
}
|
||||||
if (usage is KotlinSliceUsage) {
|
if (usage is KotlinSliceUsage) {
|
||||||
var behaviour = usage.behaviour
|
usage.mode.inlineCallStack.forEach {
|
||||||
while (behaviour != null) {
|
append("(INLINE CALL ${it.function?.name}) ")
|
||||||
append(behaviour.testPresentationPrefix)
|
|
||||||
behaviour = behaviour.originalBehaviour
|
|
||||||
}
|
}
|
||||||
|
usage.mode.behaviourStack.reversed().joinTo(this, separator = "") { it.testPresentationPrefix }
|
||||||
}
|
}
|
||||||
chunks.slice(1 until chunks.size).joinTo(
|
chunks.slice(1 until chunks.size).joinTo(
|
||||||
this,
|
this,
|
||||||
|
|||||||
@@ -190,6 +190,11 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest {
|
|||||||
runTest("idea/testData/slicer/inflow/ifExpression.kt");
|
runTest("idea/testData/slicer/inflow/ifExpression.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineFunctionManyCalls.kt")
|
||||||
|
public void testInlineFunctionManyCalls() throws Exception {
|
||||||
|
runTest("idea/testData/slicer/inflow/inlineFunctionManyCalls.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaImplicitParameter.kt")
|
@TestMetadata("lambdaImplicitParameter.kt")
|
||||||
public void testLambdaImplicitParameter() throws Exception {
|
public void testLambdaImplicitParameter() throws Exception {
|
||||||
runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt");
|
runTest("idea/testData/slicer/inflow/lambdaImplicitParameter.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user