Refactoring - converting extensions to normal functions
This commit is contained in:
@@ -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<KtDeclaration>()?.let {
|
||||
LocalSearchScope(
|
||||
it
|
||||
)
|
||||
} ?: return
|
||||
val accessSearchScope = if (isVar) {
|
||||
analysisScope
|
||||
} else {
|
||||
val containerScope = getStrictParentOfType<KtDeclaration>()?.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,17 @@ class OutflowSlicer(
|
||||
processor: Processor<SliceUsage>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<SliceUsage>,
|
||||
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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user