Refactoring: abstraction of idea with "lambdaLevel" in slices
This commit is contained in:
@@ -55,8 +55,8 @@ class InflowSlicer(
|
|||||||
parentUsage: KotlinSliceUsage
|
parentUsage: KotlinSliceUsage
|
||||||
) : Slicer(element, processor, parentUsage) {
|
) : Slicer(element, processor, parentUsage) {
|
||||||
|
|
||||||
override fun processChildren() {
|
override fun processChildren(forcedExpressionMode: Boolean) {
|
||||||
if (parentUsage.forcedExpressionMode) {
|
if (forcedExpressionMode) {
|
||||||
(element as? KtExpression)?.let { processExpression(it) }
|
(element as? KtExpression)?.let { processExpression(it) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -199,8 +199,8 @@ class InflowSlicer(
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (lambda != null) {
|
if (lambda != null) {
|
||||||
if (parentUsage.lambdaLevel > 0) {
|
if (behaviour is LambdaResultInflowBehaviour) {
|
||||||
lambda.passToProcessor(parentUsage.lambdaLevel - 1)
|
lambda.passToProcessor(behaviour.originalBehaviour)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,9 @@ 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
|
||||||
referencedDeclaration.passToProcessor(parentUsage.lambdaLevel - 1)
|
if (behaviour is LambdaResultInflowBehaviour) {
|
||||||
|
referencedDeclaration.passToProcessor(behaviour.originalBehaviour)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return
|
else -> return
|
||||||
@@ -263,7 +265,8 @@ class InflowSlicer(
|
|||||||
val resolvedCall = createdAt.resolvedCall
|
val resolvedCall = createdAt.resolvedCall
|
||||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||||
if (resultingDescriptor is FunctionInvokeDescriptor) {
|
if (resultingDescriptor is FunctionInvokeDescriptor) {
|
||||||
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression?.passToProcessorAsValue(parentUsage.lambdaLevel + 1)
|
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression
|
||||||
|
?.passToProcessorAsValue(LambdaResultInflowBehaviour(behaviour))
|
||||||
} else {
|
} else {
|
||||||
resultingDescriptor.originalSource.getPsi()?.passDeclarationToProcessorWithOverriders()
|
resultingDescriptor.originalSource.getPsi()?.passDeclarationToProcessorWithOverriders()
|
||||||
}
|
}
|
||||||
@@ -340,8 +343,6 @@ class InflowSlicer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true)
|
|
||||||
|
|
||||||
private fun PsiElement.passDeclarationToProcessorWithOverriders() {
|
private fun PsiElement.passDeclarationToProcessorWithOverriders() {
|
||||||
passToProcessor()
|
passToProcessor()
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import org.jetbrains.kotlin.idea.KotlinBundle
|
|||||||
class KotlinSliceDereferenceUsage(
|
class KotlinSliceDereferenceUsage(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
parent: KotlinSliceUsage,
|
parent: KotlinSliceUsage,
|
||||||
lambdaLevel: Int
|
behaviour: SpecialBehaviour?
|
||||||
) : KotlinSliceUsage(element, parent, lambdaLevel, false) {
|
) : KotlinSliceUsage(element, parent, behaviour, false) {
|
||||||
override fun processChildren(processor: Processor<in SliceUsage>) {
|
override fun processChildren(processor: Processor<in SliceUsage>) {
|
||||||
// no children
|
// no children
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ import com.intellij.util.Processor
|
|||||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
|
|
||||||
class KotlinSliceDereferenceUsage(
|
class KotlinSliceDereferenceUsage(
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
parent: KotlinSliceUsage,
|
parent: KotlinSliceUsage,
|
||||||
lambdaLevel: Int
|
behaviour: SpecialBehaviour?
|
||||||
) : KotlinSliceUsage(element, parent, lambdaLevel, false) {
|
) : KotlinSliceUsage(element, parent, behaviour, false) {
|
||||||
override fun processChildren(processor: Processor<SliceUsage>) {
|
override fun processChildren(processor: Processor<SliceUsage>) {
|
||||||
// no children
|
// no children
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,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, 0, false))
|
return listOf(KotlinSliceUsage(usage.element, usage.parent, null, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getExpressionAtCaret(atCaret: PsiElement, dataFlowToThis: Boolean): KtElement? {
|
override fun getExpressionAtCaret(atCaret: PsiElement, dataFlowToThis: Boolean): KtElement? {
|
||||||
|
|||||||
@@ -20,49 +20,112 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.slicer.SliceAnalysisParams
|
import com.intellij.slicer.SliceAnalysisParams
|
||||||
import com.intellij.slicer.SliceUsage
|
import com.intellij.slicer.SliceUsage
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
|
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
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
|
||||||
|
|
||||||
open class KotlinSliceUsage : SliceUsage {
|
open class KotlinSliceUsage : SliceUsage {
|
||||||
class UsageInfoLambdaWrapper(element: PsiElement) : UsageInfo(element)
|
interface SpecialBehaviour {
|
||||||
|
val originalBehaviour: SpecialBehaviour?
|
||||||
|
fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor)
|
||||||
|
|
||||||
val lambdaLevel: Int
|
val slicePresentationPrefix: String
|
||||||
|
val testPresentationPrefix: String
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean
|
||||||
|
override fun hashCode(): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
val behaviour: SpecialBehaviour?
|
||||||
val forcedExpressionMode: Boolean
|
val forcedExpressionMode: Boolean
|
||||||
|
|
||||||
constructor(element: PsiElement, parent: SliceUsage, lambdaLevel: Int, forcedExpressionMode: Boolean) : super(element, parent) {
|
constructor(
|
||||||
this.lambdaLevel = lambdaLevel
|
element: PsiElement,
|
||||||
|
parent: SliceUsage,
|
||||||
|
behaviour: SpecialBehaviour?,
|
||||||
|
forcedExpressionMode: Boolean,
|
||||||
|
) : super(element, parent) {
|
||||||
|
this.behaviour = behaviour
|
||||||
this.forcedExpressionMode = forcedExpressionMode
|
this.forcedExpressionMode = forcedExpressionMode
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(element: PsiElement, params: SliceAnalysisParams) : super(element, params) {
|
constructor(element: PsiElement, params: SliceAnalysisParams) : super(element, params) {
|
||||||
this.lambdaLevel = 0
|
this.behaviour = null
|
||||||
this.forcedExpressionMode = false
|
this.forcedExpressionMode = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun copy(): KotlinSliceUsage {
|
override fun copy(): KotlinSliceUsage {
|
||||||
val element = usageInfo.element!!
|
val element = usageInfo.element!!
|
||||||
if (parent == null) return KotlinSliceUsage(element, params)
|
return if (parent == null)
|
||||||
return KotlinSliceUsage(element, parent, lambdaLevel, forcedExpressionMode)
|
KotlinSliceUsage(element, params)
|
||||||
|
else
|
||||||
|
KotlinSliceUsage(element, parent, behaviour, forcedExpressionMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getUsageInfo(): UsageInfo {
|
override fun getUsageInfo(): UsageInfo {
|
||||||
val originalInfo = super.getUsageInfo()
|
val originalInfo = super.getUsageInfo()
|
||||||
if (lambdaLevel > 0 && forcedExpressionMode) {
|
if (behaviour != null) {
|
||||||
val element = originalInfo.element ?: return originalInfo
|
val element = originalInfo.element ?: return originalInfo
|
||||||
// Do not let IDEA consider usages of the same anonymous function as duplicates when their levels differ
|
// Do not let IDEA consider usages of the same anonymous function as duplicates when their levels differ
|
||||||
return UsageInfoLambdaWrapper(element)
|
return UsageInfoWrapper(element, behaviour)
|
||||||
}
|
}
|
||||||
return originalInfo
|
return originalInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun canBeLeaf() = element != null && lambdaLevel == 0
|
override fun canBeLeaf() = element != null && behaviour == null
|
||||||
|
|
||||||
public override fun processUsagesFlownDownTo(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
public override fun processUsagesFlownDownTo(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
||||||
InflowSlicer(element as? KtElement ?: return, uniqueProcessor, this).processChildren()
|
val ktElement = element as? KtElement ?: return
|
||||||
|
if (behaviour != null) {
|
||||||
|
behaviour.processUsages(ktElement, this, uniqueProcessor)
|
||||||
|
} else {
|
||||||
|
InflowSlicer(ktElement, uniqueProcessor, this).processChildren(forcedExpressionMode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun processUsagesFlownFromThe(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
public override fun processUsagesFlownFromThe(element: PsiElement, uniqueProcessor: SliceUsageProcessor) {
|
||||||
OutflowSlicer(element as? KtElement ?: return, uniqueProcessor, this).processChildren()
|
val ktElement = element as? KtElement ?: return
|
||||||
|
if (behaviour != null) {
|
||||||
|
behaviour.processUsages(ktElement, this, uniqueProcessor)
|
||||||
|
} else {
|
||||||
|
OutflowSlicer(ktElement, uniqueProcessor, this).processChildren(forcedExpressionMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("EqualsOrHashCode")
|
||||||
|
private class UsageInfoWrapper(element: PsiElement, private val behaviour: SpecialBehaviour) : UsageInfo(element) {
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return other is UsageInfoWrapper && super.equals(other) && behaviour == other.behaviour
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class LambdaResultOutflowBehaviour(
|
||||||
|
override val originalBehaviour: KotlinSliceUsage.SpecialBehaviour?
|
||||||
|
) : KotlinSliceUsage.SpecialBehaviour {
|
||||||
|
|
||||||
|
override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) {
|
||||||
|
OutflowSlicer(element, uniqueProcessor, parent).processChildren(parent.forcedExpressionMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val slicePresentationPrefix: String
|
||||||
|
get() = KotlinBundle.message("slicer.text.tracking.enclosing.lambda")
|
||||||
|
|
||||||
|
override val testPresentationPrefix: String
|
||||||
|
get() = "[LAMBDA] "
|
||||||
|
}
|
||||||
|
|
||||||
|
data class LambdaResultInflowBehaviour(
|
||||||
|
override val originalBehaviour: KotlinSliceUsage.SpecialBehaviour?
|
||||||
|
) : KotlinSliceUsage.SpecialBehaviour {
|
||||||
|
|
||||||
|
override fun processUsages(element: KtElement, parent: KotlinSliceUsage, uniqueProcessor: SliceUsageProcessor) {
|
||||||
|
InflowSlicer(element, uniqueProcessor, parent).processChildren(parent.forcedExpressionMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val slicePresentationPrefix: String
|
||||||
|
get() = KotlinBundle.message("slicer.text.tracking.enclosing.lambda")
|
||||||
|
|
||||||
|
override val testPresentationPrefix: String
|
||||||
|
get() = "[LAMBDA] "
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,10 +43,11 @@ object KotlinSliceUsageCellRenderer : SliceUsageCellRendererBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
append(
|
var behaviour = sliceUsage.behaviour
|
||||||
KotlinBundle.message("slicer.text.tracking.enclosing.lambda").repeat(sliceUsage.lambdaLevel),
|
while (behaviour != null) {
|
||||||
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 {
|
||||||
it is KtClass ||
|
it is KtClass ||
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ class OutflowSlicer(
|
|||||||
parentUsage: KotlinSliceUsage
|
parentUsage: KotlinSliceUsage
|
||||||
) : Slicer(element, processor, parentUsage) {
|
) : Slicer(element, processor, parentUsage) {
|
||||||
|
|
||||||
override fun processChildren() {
|
override fun processChildren(forcedExpressionMode: Boolean) {
|
||||||
if (parentUsage.forcedExpressionMode) {
|
if (forcedExpressionMode) {
|
||||||
(element as? KtExpression)?.let { processExpression(it) }
|
(element as? KtExpression)?.let { processExpression(it) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,9 @@ class OutflowSlicer(
|
|||||||
parameters[parameterIndex + shift].passToProcessor()
|
parameters[parameterIndex + shift].passToProcessor()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {} // not supported
|
else -> {
|
||||||
|
// not supported
|
||||||
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -153,7 +155,8 @@ class OutflowSlicer(
|
|||||||
null -> (usageInfo.reference as? LightMemberReference)?.element?.passToProcessor()
|
null -> (usageInfo.reference as? LightMemberReference)?.element?.passToProcessor()
|
||||||
is KtExpression -> {
|
is KtExpression -> {
|
||||||
refElement.getCallElementForExactCallee()?.passToProcessor()
|
refElement.getCallElementForExactCallee()?.passToProcessor()
|
||||||
refElement.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1)
|
refElement.getCallableReferenceForExactCallee()
|
||||||
|
?.passToProcessor(LambdaResultOutflowBehaviour(behaviour))
|
||||||
}
|
}
|
||||||
else -> refElement.passToProcessor()
|
else -> refElement.passToProcessor()
|
||||||
}
|
}
|
||||||
@@ -166,7 +169,7 @@ class OutflowSlicer(
|
|||||||
is KtNamedFunction -> function
|
is KtNamedFunction -> function
|
||||||
else -> null
|
else -> null
|
||||||
} ?: return
|
} ?: return
|
||||||
funExpression.passToProcessor(parentUsage.lambdaLevel + 1, true)
|
funExpression.passToProcessor(LambdaResultOutflowBehaviour(behaviour), forcedExpressionMode = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processExtensionReceiver(declaration: KtCallableDeclaration, declarationWithBody: KtDeclarationWithBody) {
|
private fun processExtensionReceiver(declaration: KtCallableDeclaration, declarationWithBody: KtDeclarationWithBody) {
|
||||||
@@ -229,8 +232,8 @@ class OutflowSlicer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Call.CallType.INVOKE -> {
|
Call.CallType.INVOKE -> {
|
||||||
if (parentUsage.lambdaLevel > 0 && receiverValue == resolvedCall.dispatchReceiver) {
|
if (receiverValue == resolvedCall.dispatchReceiver && behaviour is LambdaResultOutflowBehaviour) {
|
||||||
instruction.element.passToProcessor(parentUsage.lambdaLevel - 1)
|
instruction.element.passToProcessor(behaviour.originalBehaviour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +278,7 @@ class OutflowSlicer(
|
|||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
|
if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
|
||||||
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, parentUsage.lambdaLevel))
|
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, behaviour))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,10 @@ abstract class Slicer(
|
|||||||
protected val processor: SliceUsageProcessor,
|
protected val processor: SliceUsageProcessor,
|
||||||
protected val parentUsage: KotlinSliceUsage
|
protected val parentUsage: KotlinSliceUsage
|
||||||
) {
|
) {
|
||||||
abstract fun processChildren()
|
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 project = element.project
|
protected val project = element.project
|
||||||
|
|
||||||
protected class PseudocodeCache {
|
protected class PseudocodeCache {
|
||||||
@@ -57,10 +58,14 @@ abstract class Slicer(
|
|||||||
protected val pseudocodeCache = PseudocodeCache()
|
protected val pseudocodeCache = PseudocodeCache()
|
||||||
|
|
||||||
protected fun PsiElement.passToProcessor(
|
protected fun PsiElement.passToProcessor(
|
||||||
lambdaLevel: Int = parentUsage.lambdaLevel,
|
behaviour: KotlinSliceUsage.SpecialBehaviour? = this@Slicer.behaviour,
|
||||||
forcedExpressionMode: Boolean = false
|
forcedExpressionMode: Boolean = false,
|
||||||
) {
|
) {
|
||||||
processor.process(KotlinSliceUsage(this, parentUsage, lambdaLevel, forcedExpressionMode))
|
processor.process(KotlinSliceUsage(this, parentUsage, behaviour, forcedExpressionMode))
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun PsiElement.passToProcessorAsValue(behaviour: KotlinSliceUsage.SpecialBehaviour? = this@Slicer.behaviour) {
|
||||||
|
passToProcessor(behaviour, forcedExpressionMode = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun processCalls(
|
protected fun processCalls(
|
||||||
|
|||||||
@@ -62,7 +62,11 @@ internal fun buildTreeRepresentation(rootNode: SliceNode): String {
|
|||||||
append("DEREFERENCE: ")
|
append("DEREFERENCE: ")
|
||||||
}
|
}
|
||||||
if (usage is KotlinSliceUsage) {
|
if (usage is KotlinSliceUsage) {
|
||||||
append("[LAMBDA] ".repeat(usage.lambdaLevel))
|
var behaviour = usage.behaviour
|
||||||
|
while (behaviour != null) {
|
||||||
|
append(behaviour.testPresentationPrefix)
|
||||||
|
behaviour = behaviour.originalBehaviour
|
||||||
|
}
|
||||||
}
|
}
|
||||||
chunks.slice(1 until chunks.size).joinTo(
|
chunks.slice(1 until chunks.size).joinTo(
|
||||||
this,
|
this,
|
||||||
|
|||||||
Reference in New Issue
Block a user