diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt index a27a236dea7..9182fe73174 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt @@ -7,6 +7,7 @@ import com.intellij.psi.search.SearchScope import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.slicer.SliceUsage import com.intellij.util.Processor +import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* @@ -22,6 +23,8 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar import org.jetbrains.kotlin.idea.references.KtPropertyDelegationMethodsReference import org.jetbrains.kotlin.idea.references.ReferenceAccess import org.jetbrains.kotlin.idea.references.readWriteAccessWithFullExpression +import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest +import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType @@ -45,10 +48,17 @@ class InflowSlicer( processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() } } + private fun PsiElement.processHierarchyDownward(scope: SearchScope, processor: PsiElement.() -> Unit) { + processor() + HierarchySearchRequest(this, scope).searchOverriders().forEach { + it.namedUnwrappedElement?.processor() + } + } + private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true) - private fun KtDeclaration.processAssignments(accessSearchScope: SearchScope) { - processVariableAccesses(accessSearchScope, AccessKind.WRITE_WITH_OPTIONAL_READ) body@{ + 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 @@ -82,47 +92,44 @@ class InflowSlicer( private fun KtProperty.processPropertyAssignments() { val analysisScope = parentUsage.scope.toSearchScope() - val accessSearchScope = if (isVar) analysisScope - else { - val containerScope = getStrictParentOfType()?.let { - LocalSearchScope( - it - ) - } ?: return + val accessSearchScope = if (isVar) { + analysisScope + } else { + val containerScope = getStrictParentOfType()?.let { LocalSearchScope(it) } ?: return analysisScope.intersectWith(containerScope) } - processAssignments(accessSearchScope) + processAssignments(this, accessSearchScope) } - private fun KtProperty.processProperty() { - val bindingContext by lazy { analyzeWithContent() } + private fun processProperty(property: KtProperty) { + val bindingContext by lazy { property.analyzeWithContent() } - if (hasDelegateExpression()) { - val getter = (unsafeResolveToDescriptor() as VariableDescriptorWithAccessors).getter + if (property.hasDelegateExpression()) { + val getter = (property.unsafeResolveToDescriptor() as VariableDescriptorWithAccessors).getter val delegateGetterResolvedCall = getter?.let { bindingContext[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, it] } delegateGetterResolvedCall?.resultingDescriptor?.originalSource?.getPsi()?.passToProcessor() return } - initializer?.passToProcessor() + property.initializer?.passToProcessor() - getter?.processFunction() + property.getter?.processBody() - val isDefaultGetter = getter?.bodyExpression == null - val isDefaultSetter = setter?.bodyExpression == null + val isDefaultGetter = property.getter?.bodyExpression == null + val isDefaultSetter = property.setter?.bodyExpression == null if (isDefaultGetter) { if (isDefaultSetter) { - processPropertyAssignments() + property.processPropertyAssignments() } else { - setter!!.processBackingFieldAssignments() + property.setter!!.processBackingFieldAssignments() } } } - private fun KtParameter.processParameter(includeOverriders: Boolean) { - if (!canProcess()) return + private fun processParameter(parameter: KtParameter, includeOverriders: Boolean) { + if (!parameter.canProcess()) return - val function = ownerFunction ?: return + val function = parameter.ownerFunction ?: return if (function is KtPropertyAccessor && function.isSetter) { function.property.processPropertyAssignments() @@ -139,7 +146,7 @@ class InflowSlicer( .forEach { (it.element.parent as? KtProperty)?.processPropertyAssignments() } } - val parameterDescriptor = resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return + val parameterDescriptor = parameter.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return (function as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope(), includeOverriders) body@{ val refElement = it.element ?: return@body @@ -152,25 +159,25 @@ class InflowSlicer( val callParameterDescriptor = resolvedCall.resultingDescriptor.valueParameters[parameterDescriptor.index] val resolvedArgument = resolvedCall.valueArguments[callParameterDescriptor] ?: return@body when (resolvedArgument) { - is DefaultValueArgument -> defaultValue + is DefaultValueArgument -> parameter.defaultValue is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression() else -> null } } - refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(this@processParameter.parameterIndex()) + refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(parameter.parameterIndex()) else -> null } argumentExpression?.passToProcessorAsValue() } - if (valOrVarKeyword.toValVar() == KotlinValVar.Var) { - processAssignments(parentUsage.scope.toSearchScope()) + if (parameter.valOrVarKeyword.toValVar() == KotlinValVar.Var) { + processAssignments(parameter, parentUsage.scope.toSearchScope()) } } - private fun KtDeclarationWithBody.processFunction() { + private fun KtDeclarationWithBody.processBody() { val bodyExpression = bodyExpression ?: return val pseudocode = pseudocodeCache[bodyExpression] ?: return pseudocode.traverse(TraversalOrder.FORWARD) { instr -> @@ -194,10 +201,10 @@ class InflowSlicer( resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor } - private fun KtExpression.processExpression() { - val lambda = when (this) { - is KtLambdaExpression -> functionLiteral - is KtNamedFunction -> if (name == null) this else null + private fun processExpression(expression: KtExpression) { + val lambda = when (expression) { + is KtLambdaExpression -> expression.functionLiteral + is KtNamedFunction -> if (expression.name == null) expression else null else -> null } if (lambda != null) { @@ -207,14 +214,14 @@ class InflowSlicer( return } - val pseudocode = pseudocodeCache[this] ?: return - val expressionValue = pseudocode.getElementValue(this) ?: return + val pseudocode = pseudocodeCache[expression] ?: return + val expressionValue = pseudocode.getElementValue(expression) ?: return when (val createdAt = expressionValue.createdAt) { is ReadValueInstruction -> { if (createdAt.target == AccessTarget.BlackBox) { val originalElement = expressionValue.element as? KtExpression ?: return - if (originalElement != this) { - originalElement.processExpression() + if (originalElement != expression) { + processExpression(originalElement) } return } @@ -239,7 +246,7 @@ class InflowSlicer( MagicKind.BOUND_CALLABLE_REFERENCE, MagicKind.UNBOUND_CALLABLE_REFERENCE -> { val callableRefExpr = expressionValue.element as? KtCallableReferenceExpression ?: return - val referencedDescriptor = analyze()[BindingContext.REFERENCE_TARGET, callableRefExpr.callableReference] ?: return + val referencedDescriptor = expression.analyze()[BindingContext.REFERENCE_TARGET, callableRefExpr.callableReference] ?: return val referencedDeclaration = (referencedDescriptor as? DeclarationDescriptorWithSource)?.originalSource?.getPsi() ?: return referencedDeclaration.passToProcessor(parentUsage.lambdaLevel - 1) } @@ -259,14 +266,14 @@ class InflowSlicer( } override fun processChildren() { - if (parentUsage.forcedExpressionMode) return element.processExpression() + if (parentUsage.forcedExpressionMode) return processExpression(element) when (element) { - is KtProperty -> element.processProperty() + is KtProperty -> processProperty(element) // for parameter, we include overriders only when the feature is invoked on parameter itself - is KtParameter -> element.processParameter(includeOverriders = parentUsage.parent == null) - is KtDeclarationWithBody -> element.processFunction() - else -> element.processExpression() + is KtParameter -> processParameter(parameter = element, includeOverriders = parentUsage.parent == null) + is KtDeclarationWithBody -> element.processBody() + else -> processExpression(element) } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt index 44f16015713..b033e491bd3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt @@ -21,12 +21,17 @@ class OutflowSlicer( processor: Processor, parentUsage: KotlinSliceUsage ) : Slicer(element, processor, parentUsage) { - private fun KtCallableDeclaration.processVariable() { - if (this is KtParameter && !canProcess()) return + + private fun processVariable(variable: KtCallableDeclaration) { + if (variable is KtParameter && !variable.canProcess()) return val withDereferences = parentUsage.params.showInstanceDereferences val accessKind = if (withDereferences) AccessKind.READ_OR_WRITE else AccessKind.READ_ONLY - processVariableAccesses(parentUsage.scope.toSearchScope(), accessKind) body@{ + processVariableAccesses( + variable, + parentUsage.scope.toSearchScope(), + accessKind + ) body@{ val refElement = it.element if (refElement !is KtExpression) { refElement?.passToProcessor() @@ -62,14 +67,14 @@ class OutflowSlicer( return if (callee == this) callableRef else null } - private fun KtFunction.processFunction() { - if (this is KtConstructor<*> || this is KtNamedFunction && name != null) { - processCalls(parentUsage.scope.toSearchScope(), includeOverriders = false) { + private fun processFunction(function: KtFunction) { + if (function is KtConstructor<*> || function is KtNamedFunction && function.name != null) { + function.processCalls(this.parentUsage.scope.toSearchScope(), includeOverriders = false) { when (val refElement = it.element) { null -> (it.reference as? LightMemberReference)?.element?.passToProcessor() is KtExpression -> { refElement.getCallElementForExactCallee()?.passToProcessor() - refElement.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1) + refElement.getCallableReferenceForExactCallee()?.passToProcessor(this.parentUsage.lambdaLevel + 1) } else -> refElement.passToProcessor() } @@ -77,9 +82,9 @@ class OutflowSlicer( return } - val funExpression = when (this) { - is KtFunctionLiteral -> parent as? KtLambdaExpression - is KtNamedFunction -> this + val funExpression = when (function) { + is KtFunctionLiteral -> function.parent as? KtLambdaExpression + is KtNamedFunction -> function else -> null } ?: return (funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true) @@ -125,13 +130,13 @@ class OutflowSlicer( } } - private fun KtExpression.processExpression() { - processPseudocodeUsages { pseudoValue, instr -> + private fun processExpression(expression: KtExpression) { + expression.processPseudocodeUsages { pseudoValue, instr -> when (instr) { is WriteValueInstruction -> instr.target.accessedDescriptor?.originalSource?.getPsi()?.passToProcessor() is CallInstruction -> { - if (parentUsage.lambdaLevel > 0 && instr.receiverValues[pseudoValue] != null) { - instr.element.passToProcessor(parentUsage.lambdaLevel - 1) + if (this.parentUsage.lambdaLevel > 0 && instr.receiverValues[pseudoValue] != null) { + instr.element.passToProcessor(this.parentUsage.lambdaLevel - 1) } else { instr.arguments[pseudoValue]?.originalSource?.getPsi()?.passToProcessor() } @@ -147,16 +152,16 @@ class OutflowSlicer( } override fun processChildren() { - if (parentUsage.forcedExpressionMode) return element.processExpression() + if (parentUsage.forcedExpressionMode) return processExpression(element) when (element) { - is KtProperty -> element.processVariable() - is KtParameter -> element.processVariable() - is KtFunction -> element.processFunction() + is KtProperty -> processVariable(element) + is KtParameter -> processVariable(element) + is KtFunction -> processFunction(element) is KtPropertyAccessor -> if (element.isGetter) { - element.property.processVariable() + processVariable(element.property) } - else -> element.processExpression() + else -> processExpression(element) } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt index 1759346aa06..aafac3c880e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt @@ -9,8 +9,9 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.search.SearchScope import com.intellij.slicer.JavaSliceUsage +import com.intellij.slicer.SliceUsage import com.intellij.usageView.UsageInfo -import org.jetbrains.kotlin.asJava.namedUnwrappedElement +import com.intellij.util.Processor import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode import org.jetbrains.kotlin.cfg.pseudocode.getContainingPseudocode @@ -22,11 +23,8 @@ import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions -import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor import org.jetbrains.kotlin.idea.findUsages.processAllExactUsages import org.jetbrains.kotlin.idea.findUsages.processAllUsages -import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest -import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.contains import org.jetbrains.kotlin.resolve.DescriptorUtils @@ -35,7 +33,7 @@ import java.util.* abstract class Slicer( protected val element: KtExpression, - protected val processor: SliceUsageProcessor, + protected val processor: Processor, protected val parentUsage: KotlinSliceUsage ) { protected class PseudocodeCache { @@ -99,39 +97,33 @@ abstract class Slicer( } } - protected fun PsiElement.processHierarchyDownward(scope: SearchScope, processor: PsiElement.() -> Unit) { - processor() - HierarchySearchRequest(this, scope).searchOverriders().forEach { - it.namedUnwrappedElement?.processor() - } - } - protected enum class AccessKind { READ_ONLY, WRITE_ONLY, WRITE_WITH_OPTIONAL_READ, READ_OR_WRITE } - protected fun KtDeclaration.processVariableAccesses( + protected fun processVariableAccesses( + declaration: KtCallableDeclaration, scope: SearchScope, kind: AccessKind, usageProcessor: (UsageInfo) -> Unit ) { - val allDeclarations = mutableListOf(this) - val descriptor = unsafeResolveToDescriptor() + val allDeclarations = mutableListOf(declaration) + val descriptor = declaration.unsafeResolveToDescriptor() if (descriptor is CallableMemberDescriptor) { DescriptorUtils.getAllOverriddenDeclarations(descriptor).mapNotNullTo(allDeclarations) { - it.originalSource.getPsi() as? KtDeclaration + it.originalSource.getPsi() as? KtCallableDeclaration } } - for (declaration in allDeclarations) { - declaration.processAllExactUsages( - KotlinPropertyFindUsagesOptions(project).apply { + for (aDeclaration in allDeclarations) { + aDeclaration.processAllExactUsages( + KotlinPropertyFindUsagesOptions(aDeclaration.project).apply { isReadAccess = kind == AccessKind.READ_ONLY || kind == AccessKind.READ_OR_WRITE isWriteAccess = kind == AccessKind.WRITE_ONLY || kind == AccessKind.WRITE_WITH_OPTIONAL_READ || kind == AccessKind.READ_OR_WRITE isReadWriteAccess = kind == AccessKind.WRITE_WITH_OPTIONAL_READ || kind == AccessKind.READ_OR_WRITE isSearchForTextOccurrences = false isSkipImportStatements = true - searchScope = scope.intersectWith(declaration.useScope) + searchScope = scope.intersectWith(aDeclaration.useScope) }, usageProcessor )