From 6928700320918f0f91c9ebe65f38f7d6d735d303 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Sat, 11 Apr 2020 12:46:30 +0300 Subject: [PATCH] Moving declarations --- .../idea/slicer/ArgumentSliceProducer.kt | 68 +++++++++++ .../kotlin/idea/slicer/CallSliceProducer.kt | 61 ++++++++++ .../kotlin/idea/slicer/InflowSlicer.kt | 106 +----------------- .../kotlin/idea/slicer/OutflowSlicer.kt | 58 +--------- .../idea/slicer/ReceiverSliceProducer.kt | 62 ++++++++++ .../jetbrains/kotlin/idea/slicer/Slicer.kt | 21 ++-- 6 files changed, 205 insertions(+), 171 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/slicer/ArgumentSliceProducer.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/slicer/CallSliceProducer.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/slicer/ReceiverSliceProducer.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/ArgumentSliceProducer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/ArgumentSliceProducer.kt new file mode 100644 index 00000000000..8b5ca351eb1 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/ArgumentSliceProducer.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.slicer + +import com.intellij.psi.PsiCall +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.slicer.SliceUsage +import com.intellij.usageView.UsageInfo +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall +import org.jetbrains.kotlin.psi.KtCallElement +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch +import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument +import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument +import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension +import org.jetbrains.kotlin.resolve.source.getPsi + +@Suppress("DataClassPrivateConstructor") // we have modifier data to get equals&hashCode only +data class ArgumentSliceProducer private constructor( + private val parameterIndex: Int, + private val isExtension: Boolean +) : SliceProducer +{ + constructor(parameterDescriptor: ValueParameterDescriptor) : this( + parameterDescriptor.index, + parameterDescriptor.containingDeclaration.isExtension + ) + + override fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection? { + val element = usage.element ?: return emptyList() + val argumentExpression = extractArgumentExpression(element) ?: return emptyList() + return listOf(KotlinSliceUsage(argumentExpression, parent, behaviour, forcedExpressionMode = true)) + } + + private fun extractArgumentExpression(refElement: PsiElement): PsiElement? { + val refParent = refElement.parent + return when { + refElement is KtExpression -> { + val callElement = refElement as? KtCallElement + ?: refElement.getParentOfTypeAndBranch { calleeExpression } + ?: return null + val resolvedCall = callElement.resolveToCall() ?: return null + val resultingDescriptor = resolvedCall.resultingDescriptor + val parameterIndexToUse = parameterIndex + + (if (isExtension && resultingDescriptor.extensionReceiverParameter == null) 1 else 0) + val parameterDescriptor = resultingDescriptor.valueParameters[parameterIndexToUse] + val resolvedArgument = resolvedCall.valueArguments[parameterDescriptor] ?: return null + when (resolvedArgument) { + is DefaultValueArgument -> (parameterDescriptor.source.getPsi() as? KtParameter)?.defaultValue + is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression() + else -> null + } + } + + refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(parameterIndex + (if (isExtension) 1 else 0)) + + refElement is PsiMethod -> refElement.parameterList.parameters.getOrNull(parameterIndex + (if (isExtension) 1 else 0)) + + else -> null + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/CallSliceProducer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/CallSliceProducer.kt new file mode 100644 index 00000000000..ce6af976432 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/CallSliceProducer.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.slicer + +import com.intellij.psi.PsiElement +import com.intellij.psi.impl.light.LightMemberReference +import com.intellij.slicer.SliceUsage +import com.intellij.usageView.UsageInfo +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch +import org.jetbrains.kotlin.psi.psiUtil.isAncestor + +object CallSliceProducer : SliceProducer { + override fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection? { + when (val refElement = usage.element) { + null -> { + val element = (usage.reference as? LightMemberReference)?.element ?: return emptyList() + return listOf(KotlinSliceUsage(element, parent, behaviour, false)) + } + + is KtExpression -> { + return mutableListOf().apply { + refElement.getCallElementForExactCallee() + ?.let { this += KotlinSliceUsage(it, parent, behaviour, false) } + refElement.getCallableReferenceForExactCallee() + ?.let { this += KotlinSliceUsage(it, parent, LambdaCallsBehaviour(SliceProducer.Trivial, behaviour), false) } + } + } + + else -> { + return null // unknown type of usage - return null to process it "as is" + } + } + } + + override fun equals(other: Any?) = other === this + override fun hashCode() = 0 + + private fun PsiElement.getCallElementForExactCallee(): PsiElement? { + if (this is KtArrayAccessExpression) return this + + val operationRefExpr = getNonStrictParentOfType() + if (operationRefExpr != null) return operationRefExpr.parent as? KtOperationExpression + + val parentCall = getParentOfTypeAndBranch { calleeExpression } ?: return null + val callee = parentCall.calleeExpression?.let { KtPsiUtil.safeDeparenthesize(it) } + if (callee == this || callee is KtConstructorCalleeExpression && callee.isAncestor(this, strict = true)) return parentCall + + return null + } + + private fun PsiElement.getCallableReferenceForExactCallee(): KtCallableReferenceExpression? { + val callableRef = getParentOfTypeAndBranch { callableReference } ?: return null + val callee = KtPsiUtil.safeDeparenthesize(callableRef.callableReference) + return if (callee == this) callableRef else null + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt index ff46dd6774a..111ca587d86 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/InflowSlicer.kt @@ -7,11 +7,9 @@ package org.jetbrains.kotlin.idea.slicer import com.intellij.psi.PsiCall import com.intellij.psi.PsiElement -import com.intellij.psi.PsiMethod import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.SearchScope import com.intellij.psi.search.searches.ReferencesSearch -import com.intellij.slicer.SliceUsage import com.intellij.usageView.UsageInfo import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor @@ -37,15 +35,10 @@ import org.jetbrains.kotlin.idea.util.isExpectDeclaration import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType -import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument -import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument -import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.util.OperatorNameConventions @@ -327,101 +320,4 @@ class InflowSlicer( } } } - - @Suppress("DataClassPrivateConstructor") // we have modifier data to get equals&hashCode only - private data class ArgumentSliceProducer private constructor( - private val parameterIndex: Int, - private val isExtension: Boolean - ) : SliceProducer - { - constructor(parameterDescriptor: ValueParameterDescriptor) : this( - parameterDescriptor.index, - parameterDescriptor.containingDeclaration.isExtension - ) - - override fun produce( - usage: UsageInfo, - behaviour: KotlinSliceUsage.SpecialBehaviour?, - parent: SliceUsage - ): Collection? { - val element = usage.element ?: return emptyList() - val argumentExpression = extractArgumentExpression(element) ?: return emptyList() - return listOf(KotlinSliceUsage(argumentExpression, parent, behaviour, forcedExpressionMode = true)) - } - - private fun extractArgumentExpression(refElement: PsiElement): PsiElement? { - val refParent = refElement.parent - return when { - refElement is KtExpression -> { - val callElement = refElement as? KtCallElement - ?: refElement.getParentOfTypeAndBranch { calleeExpression } - ?: return null - val resolvedCall = callElement.resolveToCall() ?: return null - val resultingDescriptor = resolvedCall.resultingDescriptor - val parameterIndexToUse = parameterIndex + - (if (isExtension && resultingDescriptor.extensionReceiverParameter == null) 1 else 0) - val parameterDescriptor = resultingDescriptor.valueParameters[parameterIndexToUse] - val resolvedArgument = resolvedCall.valueArguments[parameterDescriptor] ?: return null - when (resolvedArgument) { - is DefaultValueArgument -> (parameterDescriptor.source.getPsi() as? KtParameter)?.defaultValue - is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression() - else -> null - } - } - - refParent is PsiCall -> refParent.argumentList?.expressions?.getOrNull(parameterIndex + (if (isExtension) 1 else 0)) - - refElement is PsiMethod -> refElement.parameterList.parameters.getOrNull(parameterIndex + (if (isExtension) 1 else 0)) - - else -> null - } - } - } - - private object ReceiverSliceProducer : SliceProducer { - override fun produce( - usage: UsageInfo, - behaviour: KotlinSliceUsage.SpecialBehaviour?, - parent: SliceUsage - ): Collection? { - val refElement = usage.element ?: return emptyList() - when (refElement) { - is KtExpression -> { - val resolvedCall = refElement.resolveToCall() ?: return emptyList() - when (val receiver = resolvedCall.extensionReceiver) { - is ExpressionReceiver -> { - return listOf(KotlinSliceUsage(receiver.expression, parent, behaviour, forcedExpressionMode = true)) - } - - is ImplicitReceiver -> { - val callableDescriptor = receiver.declarationDescriptor as? CallableDescriptor ?: return emptyList() - when (val callableDeclaration = callableDescriptor.originalSource.getPsi()) { - is KtFunctionLiteral -> { - val newBehaviour = LambdaCallsBehaviour(ReceiverSliceProducer, behaviour) - return listOf(KotlinSliceUsage(callableDeclaration, parent, newBehaviour, forcedExpressionMode = true)) - } - - is KtCallableDeclaration -> { - val receiverTypeReference = callableDeclaration.receiverTypeReference ?: return emptyList() - return listOf(KotlinSliceUsage(receiverTypeReference, parent, behaviour, false)) - } - - else -> return emptyList() - } - } - - else -> return emptyList() - } - } - - else -> { - val argument = (refElement.parent as? PsiCall)?.argumentList?.expressions?.getOrNull(0) ?: return emptyList() - return listOf(KotlinSliceUsage(argument, parent, behaviour, true)) - } - } - } - - override fun equals(other: Any?) = other === this - override fun hashCode() = 0 - } -} \ 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 7a14b9fa64e..27c38fa7b31 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt @@ -6,10 +6,7 @@ package org.jetbrains.kotlin.idea.slicer import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access -import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod -import com.intellij.psi.impl.light.LightMemberReference -import com.intellij.slicer.SliceUsage import com.intellij.usageView.UsageInfo import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction @@ -27,7 +24,8 @@ import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDete import org.jetbrains.kotlin.idea.util.actualsForExpected import org.jetbrains.kotlin.idea.util.isExpectDeclaration import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType +import org.jetbrains.kotlin.psi.psiUtil.parameterIndex import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.source.getPsi @@ -267,54 +265,4 @@ class OutflowSlicer( } } } - - private object CallSliceProducer : SliceProducer { - override fun produce( - usage: UsageInfo, - behaviour: KotlinSliceUsage.SpecialBehaviour?, - parent: SliceUsage - ): Collection? { - when (val refElement = usage.element) { - null -> { - val element = (usage.reference as? LightMemberReference)?.element ?: return emptyList() - return listOf(KotlinSliceUsage(element, parent, behaviour, false)) - } - - is KtExpression -> { - return mutableListOf().apply { - refElement.getCallElementForExactCallee() - ?.let { this += KotlinSliceUsage(it, parent, behaviour, false) } - refElement.getCallableReferenceForExactCallee() - ?.let { this += KotlinSliceUsage(it, parent, LambdaCallsBehaviour(SliceProducer.Trivial, behaviour), false) } - } - } - - else -> { - return null // unknown type of usage - return null to process it "as is" - } - } - } - - override fun equals(other: Any?) = other === this - override fun hashCode() = 0 - - private fun PsiElement.getCallElementForExactCallee(): PsiElement? { - if (this is KtArrayAccessExpression) return this - - val operationRefExpr = getNonStrictParentOfType() - if (operationRefExpr != null) return operationRefExpr.parent as? KtOperationExpression - - val parentCall = getParentOfTypeAndBranch { calleeExpression } ?: return null - val callee = parentCall.calleeExpression?.let { KtPsiUtil.safeDeparenthesize(it) } - if (callee == this || callee is KtConstructorCalleeExpression && callee.isAncestor(this, strict = true)) return parentCall - - return null - } - - private fun PsiElement.getCallableReferenceForExactCallee(): KtCallableReferenceExpression? { - val callableRef = getParentOfTypeAndBranch { callableReference } ?: return null - val callee = KtPsiUtil.safeDeparenthesize(callableRef.callableReference) - return if (callee == this) callableRef else null - } - } -} \ No newline at end of file +} diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/ReceiverSliceProducer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/ReceiverSliceProducer.kt new file mode 100644 index 00000000000..f76fc6ad729 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/ReceiverSliceProducer.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.slicer + +import com.intellij.psi.PsiCall +import com.intellij.slicer.SliceUsage +import com.intellij.usageView.UsageInfo +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall +import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFunctionLiteral +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver +import org.jetbrains.kotlin.resolve.source.getPsi + +object ReceiverSliceProducer : SliceProducer { + override fun produce(usage: UsageInfo, behaviour: KotlinSliceUsage.SpecialBehaviour?, parent: SliceUsage): Collection? { + val refElement = usage.element ?: return emptyList() + when (refElement) { + is KtExpression -> { + val resolvedCall = refElement.resolveToCall() ?: return emptyList() + when (val receiver = resolvedCall.extensionReceiver) { + is ExpressionReceiver -> { + return listOf(KotlinSliceUsage(receiver.expression, parent, behaviour, forcedExpressionMode = true)) + } + + is ImplicitReceiver -> { + val callableDescriptor = receiver.declarationDescriptor as? CallableDescriptor + ?: return emptyList() + when (val callableDeclaration = callableDescriptor.originalSource.getPsi()) { + is KtFunctionLiteral -> { + val newBehaviour = LambdaCallsBehaviour(ReceiverSliceProducer, behaviour) + return listOf(KotlinSliceUsage(callableDeclaration, parent, newBehaviour, forcedExpressionMode = true)) + } + + is KtCallableDeclaration -> { + val receiverTypeReference = callableDeclaration.receiverTypeReference ?: return emptyList() + return listOf(KotlinSliceUsage(receiverTypeReference, parent, behaviour, false)) + } + + else -> return emptyList() + } + } + + else -> return emptyList() + } + } + + else -> { + val argument = (refElement.parent as? PsiCall)?.argumentList?.expressions?.getOrNull(0) ?: return emptyList() + return listOf(KotlinSliceUsage(argument, parent, behaviour, true)) + } + } + } + + override fun equals(other: Any?) = other === this + override fun hashCode() = 0 +} \ 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 a1c7b7e638b..62752dae57e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt @@ -178,15 +178,14 @@ abstract class Slicer( } protected fun canProcessParameter(parameter: KtParameter) = !parameter.isVarArg - - protected companion object { - val DeclarationDescriptorWithSource.originalSource: SourceElement - get() { - var descriptor = this - while (descriptor.original != descriptor) { - descriptor = descriptor.original - } - return descriptor.source - } - } } + +val DeclarationDescriptorWithSource.originalSource: SourceElement + get() { + var descriptor = this + while (descriptor.original != descriptor) { + descriptor = descriptor.original + } + return descriptor.source + } +