Reordered methods
This commit is contained in:
@@ -44,63 +44,21 @@ class InflowSlicer(
|
|||||||
processor: Processor<SliceUsage>,
|
processor: Processor<SliceUsage>,
|
||||||
parentUsage: KotlinSliceUsage
|
parentUsage: KotlinSliceUsage
|
||||||
) : Slicer(element, processor, parentUsage) {
|
) : Slicer(element, processor, parentUsage) {
|
||||||
private fun PsiElement.processHierarchyDownwardAndPass() {
|
|
||||||
processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiElement.processHierarchyDownward(scope: SearchScope, processor: PsiElement.() -> Unit) {
|
override fun processChildren() {
|
||||||
processor()
|
if (parentUsage.forcedExpressionMode) {
|
||||||
HierarchySearchRequest(this, scope).searchOverriders().forEach {
|
return processExpression(element)
|
||||||
it.namedUnwrappedElement?.processor()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true)
|
when (element) {
|
||||||
|
is KtProperty -> processProperty(element)
|
||||||
private fun processAssignments(variableDeclaration: KtCallableDeclaration, accessSearchScope: SearchScope) {
|
// for parameter, we include overriders only when the feature is invoked on parameter itself
|
||||||
processVariableAccesses(variableDeclaration, accessSearchScope, AccessKind.WRITE_WITH_OPTIONAL_READ) body@{
|
is KtParameter -> processParameter(parameter = element, includeOverriders = parentUsage.parent == null)
|
||||||
val refElement = it.element ?: return@body
|
is KtDeclarationWithBody -> element.processBody()
|
||||||
val refParent = refElement.parent
|
else -> processExpression(element)
|
||||||
|
|
||||||
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 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) {
|
private fun processProperty(property: KtProperty) {
|
||||||
val bindingContext by lazy { property.analyzeWithContent() }
|
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) {
|
private fun processExpression(expression: KtExpression) {
|
||||||
val lambda = when (expression) {
|
val lambda = when (expression) {
|
||||||
is KtLambdaExpression -> expression.functionLiteral
|
is KtLambdaExpression -> expression.functionLiteral
|
||||||
@@ -265,15 +199,84 @@ class InflowSlicer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processChildren() {
|
private fun KtProperty.processPropertyAssignments() {
|
||||||
if (parentUsage.forcedExpressionMode) return processExpression(element)
|
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) {
|
private fun processAssignments(variable: KtCallableDeclaration, accessSearchScope: SearchScope) {
|
||||||
is KtProperty -> processProperty(element)
|
processVariableAccesses(variable, accessSearchScope, AccessKind.WRITE_WITH_OPTIONAL_READ) body@{
|
||||||
// for parameter, we include overriders only when the feature is invoked on parameter itself
|
val refElement = it.element ?: return@body
|
||||||
is KtParameter -> processParameter(parameter = element, includeOverriders = parentUsage.parent == null)
|
val refParent = refElement.parent
|
||||||
is KtDeclarationWithBody -> element.processBody()
|
|
||||||
else -> processExpression(element)
|
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>,
|
processor: Processor<SliceUsage>,
|
||||||
parentUsage: KotlinSliceUsage
|
parentUsage: KotlinSliceUsage
|
||||||
) : Slicer(element, processor, parentUsage) {
|
) : 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) {
|
private fun processVariable(variable: KtCallableDeclaration) {
|
||||||
if (variable is KtParameter && !variable.canProcess()) return
|
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) {
|
private fun processFunction(function: KtFunction) {
|
||||||
if (function is KtConstructor<*> || function is KtNamedFunction && function.name != null) {
|
if (function is KtConstructor<*> || function is KtNamedFunction && function.name != null) {
|
||||||
function.processCalls(this.parentUsage.scope.toSearchScope(), includeOverriders = false) {
|
function.processCalls(this.parentUsage.scope.toSearchScope(), includeOverriders = false) {
|
||||||
@@ -90,6 +83,46 @@ class OutflowSlicer(
|
|||||||
(funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true)
|
(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(
|
private fun processDereferenceIsNeeded(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
pseudoValue: PseudoValue,
|
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 processor: Processor<SliceUsage>,
|
||||||
protected val parentUsage: KotlinSliceUsage
|
protected val parentUsage: KotlinSliceUsage
|
||||||
) {
|
) {
|
||||||
|
abstract fun processChildren()
|
||||||
|
|
||||||
protected class PseudocodeCache {
|
protected class PseudocodeCache {
|
||||||
private val computedPseudocodes = HashMap<KtElement, Pseudocode>()
|
private val computedPseudocodes = HashMap<KtElement, Pseudocode>()
|
||||||
|
|
||||||
@@ -57,8 +59,6 @@ abstract class Slicer(
|
|||||||
processor.process(KotlinSliceUsage(this, parentUsage, lambdaLevel, forcedExpressionMode))
|
processor.process(KotlinSliceUsage(this, parentUsage, lambdaLevel, forcedExpressionMode))
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun processChildren()
|
|
||||||
|
|
||||||
protected fun KtFunction.processCalls(scope: SearchScope, includeOverriders: Boolean, usageProcessor: (UsageInfo) -> Unit) {
|
protected fun KtFunction.processCalls(scope: SearchScope, includeOverriders: Boolean, usageProcessor: (UsageInfo) -> Unit) {
|
||||||
val options = KotlinFunctionFindUsagesOptions(project).apply {
|
val options = KotlinFunctionFindUsagesOptions(project).apply {
|
||||||
isSearchForTextOccurrences = false
|
isSearchForTextOccurrences = false
|
||||||
|
|||||||
Reference in New Issue
Block a user