Moving declarations
This commit is contained in:
@@ -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<SliceUsage>? {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<SliceUsage>? {
|
||||
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<SliceUsage>().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<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, strict = 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
|
||||
}
|
||||
}
|
||||
@@ -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<SliceUsage>? {
|
||||
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<SliceUsage>? {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SliceUsage>? {
|
||||
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<SliceUsage>().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<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, strict = 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SliceUsage>? {
|
||||
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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user