Reordered methods

This commit is contained in:
Valentin Kipyatkov
2020-02-10 11:03:13 +02:00
parent ff39880677
commit 8f7648c60a
3 changed files with 141 additions and 140 deletions
@@ -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