Reordered methods
This commit is contained in:
@@ -44,63 +44,21 @@ class InflowSlicer(
|
||||
processor: Processor<SliceUsage>,
|
||||
parentUsage: KotlinSliceUsage
|
||||
) : Slicer(element, processor, parentUsage) {
|
||||
private fun PsiElement.processHierarchyDownwardAndPass() {
|
||||
processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() }
|
||||
}
|
||||
|
||||
private fun PsiElement.processHierarchyDownward(scope: SearchScope, processor: PsiElement.() -> Unit) {
|
||||
processor()
|
||||
HierarchySearchRequest(this, scope).searchOverriders().forEach {
|
||||
it.namedUnwrappedElement?.processor()
|
||||
override fun processChildren() {
|
||||
if (parentUsage.forcedExpressionMode) {
|
||||
return processExpression(element)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true)
|
||||
|
||||
private fun processAssignments(variableDeclaration: KtCallableDeclaration, accessSearchScope: SearchScope) {
|
||||
processVariableAccesses(variableDeclaration, accessSearchScope, AccessKind.WRITE_WITH_OPTIONAL_READ) body@{
|
||||
val refElement = it.element ?: return@body
|
||||
val refParent = refElement.parent
|
||||
|
||||
val rhsValue = when {
|
||||
refElement is KtExpression -> {
|
||||
val (accessKind, accessExpression) = refElement.readWriteAccessWithFullExpression(true)
|
||||
if (accessKind == ReferenceAccess.WRITE && accessExpression is KtBinaryExpression && accessExpression.operationToken == KtTokens.EQ) {
|
||||
accessExpression.right
|
||||
} else {
|
||||
accessExpression
|
||||
}
|
||||
}
|
||||
|
||||
refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(0)
|
||||
|
||||
else -> null
|
||||
}
|
||||
rhsValue?.passToProcessorAsValue()
|
||||
when (element) {
|
||||
is KtProperty -> processProperty(element)
|
||||
// for parameter, we include overriders only when the feature is invoked on parameter itself
|
||||
is KtParameter -> processParameter(parameter = element, includeOverriders = parentUsage.parent == null)
|
||||
is KtDeclarationWithBody -> element.processBody()
|
||||
else -> processExpression(element)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtPropertyAccessor.processBackingFieldAssignments() {
|
||||
forEachDescendantOfType<KtBinaryExpression> body@{
|
||||
if (it.operationToken != KtTokens.EQ) return@body
|
||||
val lhs = it.left?.let { expression -> KtPsiUtil.safeDeparenthesize(expression) } ?: return@body
|
||||
val rhs = it.right ?: return@body
|
||||
if (!lhs.isBackingFieldReference()) return@body
|
||||
rhs.passToProcessor()
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtProperty.processPropertyAssignments() {
|
||||
val analysisScope = parentUsage.scope.toSearchScope()
|
||||
val accessSearchScope = if (isVar) {
|
||||
analysisScope
|
||||
} else {
|
||||
val containerScope = getStrictParentOfType<KtDeclaration>()?.let { LocalSearchScope(it) } ?: return
|
||||
analysisScope.intersectWith(containerScope)
|
||||
}
|
||||
processAssignments(this, accessSearchScope)
|
||||
}
|
||||
|
||||
private fun processProperty(property: KtProperty) {
|
||||
val bindingContext by lazy { property.analyzeWithContent() }
|
||||
|
||||
@@ -177,30 +135,6 @@ class InflowSlicer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtDeclarationWithBody.processBody() {
|
||||
val bodyExpression = bodyExpression ?: return
|
||||
val pseudocode = pseudocodeCache[bodyExpression] ?: return
|
||||
pseudocode.traverse(TraversalOrder.FORWARD) { instr ->
|
||||
if (instr is ReturnValueInstruction && instr.subroutine == this) {
|
||||
(instr.returnExpressionIfAny?.returnedExpression ?: instr.element as? KtExpression)?.passToProcessorAsValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Instruction.passInputsToProcessor() {
|
||||
inputValues.forEach {
|
||||
if (it.createdAt != null) {
|
||||
it.element?.passToProcessorAsValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtExpression.isBackingFieldReference(): Boolean {
|
||||
return this is KtSimpleNameExpression &&
|
||||
getReferencedName() == SyntheticFieldDescriptor.NAME.asString() &&
|
||||
resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor
|
||||
}
|
||||
|
||||
private fun processExpression(expression: KtExpression) {
|
||||
val lambda = when (expression) {
|
||||
is KtLambdaExpression -> expression.functionLiteral
|
||||
@@ -265,15 +199,84 @@ class InflowSlicer(
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChildren() {
|
||||
if (parentUsage.forcedExpressionMode) return processExpression(element)
|
||||
private fun KtProperty.processPropertyAssignments() {
|
||||
val analysisScope = parentUsage.scope.toSearchScope()
|
||||
val accessSearchScope = if (isVar) {
|
||||
analysisScope
|
||||
} else {
|
||||
val containerScope = getStrictParentOfType<KtDeclaration>()?.let { LocalSearchScope(it) } ?: return
|
||||
analysisScope.intersectWith(containerScope)
|
||||
}
|
||||
processAssignments(this, accessSearchScope)
|
||||
}
|
||||
|
||||
when (element) {
|
||||
is KtProperty -> processProperty(element)
|
||||
// for parameter, we include overriders only when the feature is invoked on parameter itself
|
||||
is KtParameter -> processParameter(parameter = element, includeOverriders = parentUsage.parent == null)
|
||||
is KtDeclarationWithBody -> element.processBody()
|
||||
else -> processExpression(element)
|
||||
private fun processAssignments(variable: KtCallableDeclaration, accessSearchScope: SearchScope) {
|
||||
processVariableAccesses(variable, accessSearchScope, AccessKind.WRITE_WITH_OPTIONAL_READ) body@{
|
||||
val refElement = it.element ?: return@body
|
||||
val refParent = refElement.parent
|
||||
|
||||
val rhsValue = when {
|
||||
refElement is KtExpression -> {
|
||||
val (accessKind, accessExpression) = refElement.readWriteAccessWithFullExpression(true)
|
||||
if (accessKind == ReferenceAccess.WRITE && accessExpression is KtBinaryExpression && accessExpression.operationToken == KtTokens.EQ) {
|
||||
accessExpression.right
|
||||
} else {
|
||||
accessExpression
|
||||
}
|
||||
}
|
||||
|
||||
refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(0)
|
||||
|
||||
else -> null
|
||||
}
|
||||
rhsValue?.passToProcessorAsValue()
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtPropertyAccessor.processBackingFieldAssignments() {
|
||||
forEachDescendantOfType<KtBinaryExpression> body@{
|
||||
if (it.operationToken != KtTokens.EQ) return@body
|
||||
val lhs = it.left?.let { expression -> KtPsiUtil.safeDeparenthesize(expression) } ?: return@body
|
||||
val rhs = it.right ?: return@body
|
||||
if (!lhs.isBackingFieldReference()) return@body
|
||||
rhs.passToProcessor()
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtExpression.isBackingFieldReference(): Boolean {
|
||||
return this is KtSimpleNameExpression &&
|
||||
getReferencedName() == SyntheticFieldDescriptor.NAME.asString() &&
|
||||
resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor
|
||||
}
|
||||
|
||||
private fun KtDeclarationWithBody.processBody() {
|
||||
val bodyExpression = bodyExpression ?: return
|
||||
val pseudocode = pseudocodeCache[bodyExpression] ?: return
|
||||
pseudocode.traverse(TraversalOrder.FORWARD) { instr ->
|
||||
if (instr is ReturnValueInstruction && instr.subroutine == this) {
|
||||
(instr.returnExpressionIfAny?.returnedExpression ?: instr.element as? KtExpression)?.passToProcessorAsValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Instruction.passInputsToProcessor() {
|
||||
inputValues.forEach {
|
||||
if (it.createdAt != null) {
|
||||
it.element?.passToProcessorAsValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true)
|
||||
|
||||
private fun PsiElement.processHierarchyDownwardAndPass() {
|
||||
processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() }
|
||||
}
|
||||
|
||||
private fun PsiElement.processHierarchyDownward(scope: SearchScope, processor: PsiElement.() -> Unit) {
|
||||
processor()
|
||||
HierarchySearchRequest(this, scope).searchOverriders().forEach {
|
||||
it.namedUnwrappedElement?.processor()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,19 @@ class OutflowSlicer(
|
||||
processor: Processor<SliceUsage>,
|
||||
parentUsage: KotlinSliceUsage
|
||||
) : Slicer(element, processor, parentUsage) {
|
||||
|
||||
|
||||
override fun processChildren() {
|
||||
if (parentUsage.forcedExpressionMode) return processExpression(element)
|
||||
|
||||
when (element) {
|
||||
is KtProperty -> processVariable(element)
|
||||
is KtParameter -> processVariable(element)
|
||||
is KtFunction -> processFunction(element)
|
||||
is KtPropertyAccessor -> if (element.isGetter) processVariable(element.property)
|
||||
else -> processExpression(element)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processVariable(variable: KtCallableDeclaration) {
|
||||
if (variable is KtParameter && !variable.canProcess()) return
|
||||
|
||||
@@ -48,25 +60,6 @@ class OutflowSlicer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.getCallElementForExactCallee(): PsiElement? {
|
||||
if (this is KtArrayAccessExpression) return this
|
||||
|
||||
val operationRefExpr = getNonStrictParentOfType<KtOperationReferenceExpression>()
|
||||
if (operationRefExpr != null) return operationRefExpr.parent as? KtOperationExpression
|
||||
|
||||
val parentCall = getParentOfTypeAndBranch<KtCallElement> { calleeExpression } ?: return null
|
||||
val callee = parentCall.calleeExpression?.let { KtPsiUtil.safeDeparenthesize(it) }
|
||||
if (callee == this || callee is KtConstructorCalleeExpression && callee.isAncestor(this, true)) return parentCall
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun PsiElement.getCallableReferenceForExactCallee(): KtCallableReferenceExpression? {
|
||||
val callableRef = getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } ?: return null
|
||||
val callee = KtPsiUtil.safeDeparenthesize(callableRef.callableReference)
|
||||
return if (callee == this) callableRef else null
|
||||
}
|
||||
|
||||
private fun processFunction(function: KtFunction) {
|
||||
if (function is KtConstructor<*> || function is KtNamedFunction && function.name != null) {
|
||||
function.processCalls(this.parentUsage.scope.toSearchScope(), includeOverriders = false) {
|
||||
@@ -90,6 +83,46 @@ class OutflowSlicer(
|
||||
(funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true)
|
||||
}
|
||||
|
||||
private fun processExpression(expression: KtExpression) {
|
||||
expression.processPseudocodeUsages { pseudoValue, instr ->
|
||||
when (instr) {
|
||||
is WriteValueInstruction -> instr.target.accessedDescriptor?.originalSource?.getPsi()?.passToProcessor()
|
||||
is CallInstruction -> {
|
||||
if (this.parentUsage.lambdaLevel > 0 && instr.receiverValues[pseudoValue] != null) {
|
||||
instr.element.passToProcessor(this.parentUsage.lambdaLevel - 1)
|
||||
} else {
|
||||
instr.arguments[pseudoValue]?.originalSource?.getPsi()?.passToProcessor()
|
||||
}
|
||||
}
|
||||
is ReturnValueInstruction -> instr.subroutine.passToProcessor()
|
||||
is MagicInstruction -> when (instr.kind) {
|
||||
MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> instr.outputValue.element?.passToProcessor()
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.getCallElementForExactCallee(): PsiElement? {
|
||||
if (this is KtArrayAccessExpression) return this
|
||||
|
||||
val operationRefExpr = getNonStrictParentOfType<KtOperationReferenceExpression>()
|
||||
if (operationRefExpr != null) return operationRefExpr.parent as? KtOperationExpression
|
||||
|
||||
val parentCall = getParentOfTypeAndBranch<KtCallElement> { calleeExpression } ?: return null
|
||||
val callee = parentCall.calleeExpression?.let { KtPsiUtil.safeDeparenthesize(it) }
|
||||
if (callee == this || callee is KtConstructorCalleeExpression && callee.isAncestor(this, true)) return parentCall
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun PsiElement.getCallableReferenceForExactCallee(): KtCallableReferenceExpression? {
|
||||
val callableRef = getParentOfTypeAndBranch<KtCallableReferenceExpression> { callableReference } ?: return null
|
||||
val callee = KtPsiUtil.safeDeparenthesize(callableRef.callableReference)
|
||||
return if (callee == this) callableRef else null
|
||||
}
|
||||
|
||||
private fun processDereferenceIsNeeded(
|
||||
expression: KtExpression,
|
||||
pseudoValue: PseudoValue,
|
||||
@@ -129,39 +162,4 @@ class OutflowSlicer(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processExpression(expression: KtExpression) {
|
||||
expression.processPseudocodeUsages { pseudoValue, instr ->
|
||||
when (instr) {
|
||||
is WriteValueInstruction -> instr.target.accessedDescriptor?.originalSource?.getPsi()?.passToProcessor()
|
||||
is CallInstruction -> {
|
||||
if (this.parentUsage.lambdaLevel > 0 && instr.receiverValues[pseudoValue] != null) {
|
||||
instr.element.passToProcessor(this.parentUsage.lambdaLevel - 1)
|
||||
} else {
|
||||
instr.arguments[pseudoValue]?.originalSource?.getPsi()?.passToProcessor()
|
||||
}
|
||||
}
|
||||
is ReturnValueInstruction -> instr.subroutine.passToProcessor()
|
||||
is MagicInstruction -> when (instr.kind) {
|
||||
MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> instr.outputValue.element?.passToProcessor()
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun processChildren() {
|
||||
if (parentUsage.forcedExpressionMode) return processExpression(element)
|
||||
|
||||
when (element) {
|
||||
is KtProperty -> processVariable(element)
|
||||
is KtParameter -> processVariable(element)
|
||||
is KtFunction -> processFunction(element)
|
||||
is KtPropertyAccessor -> if (element.isGetter) {
|
||||
processVariable(element.property)
|
||||
}
|
||||
else -> processExpression(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,8 @@ abstract class Slicer(
|
||||
protected val processor: Processor<SliceUsage>,
|
||||
protected val parentUsage: KotlinSliceUsage
|
||||
) {
|
||||
abstract fun processChildren()
|
||||
|
||||
protected class PseudocodeCache {
|
||||
private val computedPseudocodes = HashMap<KtElement, Pseudocode>()
|
||||
|
||||
@@ -57,8 +59,6 @@ abstract class Slicer(
|
||||
processor.process(KotlinSliceUsage(this, parentUsage, lambdaLevel, forcedExpressionMode))
|
||||
}
|
||||
|
||||
abstract fun processChildren()
|
||||
|
||||
protected fun KtFunction.processCalls(scope: SearchScope, includeOverriders: Boolean, usageProcessor: (UsageInfo) -> Unit) {
|
||||
val options = KotlinFunctionFindUsagesOptions(project).apply {
|
||||
isSearchForTextOccurrences = false
|
||||
|
||||
Reference in New Issue
Block a user