Refactoring
This commit is contained in:
+30
-50
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.replacement
|
package org.jetbrains.kotlin.idea.replacement
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
@@ -46,21 +45,20 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object ReplacementEngine {
|
class CallReplacementEngine<TCallElement : KtElement>(
|
||||||
fun <TCallElement : KtElement> performCallReplacement(
|
private val nameExpression: KtSimpleNameExpression,
|
||||||
element: KtSimpleNameExpression,
|
private val bindingContext: BindingContext,
|
||||||
bindingContext: BindingContext,
|
private val resolvedCall: ResolvedCall<out CallableDescriptor>,
|
||||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
private val callElement: TCallElement,
|
||||||
callElement: TCallElement,
|
replacement: ReplacementCode
|
||||||
replacement: ReplacementCode
|
) {
|
||||||
): KtElement {
|
private val replacement = replacement.toMutable()
|
||||||
@Suppress("NAME_SHADOWING")
|
private val project = nameExpression.project
|
||||||
val replacement = replacement.toMutable()
|
private val psiFactory = KtPsiFactory(project)
|
||||||
|
|
||||||
val project = element.project
|
fun performReplacement(): KtElement {
|
||||||
val psiFactory = KtPsiFactory(project)
|
|
||||||
val descriptor = resolvedCall.resultingDescriptor
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
val file = element.getContainingKtFile()
|
val file = nameExpression.getContainingKtFile()
|
||||||
|
|
||||||
val elementToBeReplaced = when (callElement) {
|
val elementToBeReplaced = when (callElement) {
|
||||||
is KtExpression -> callElement.getQualifiedExpressionForSelectorOrThis()
|
is KtExpression -> callElement.getQualifiedExpressionForSelectorOrThis()
|
||||||
@@ -69,7 +67,7 @@ object ReplacementEngine {
|
|||||||
|
|
||||||
val commentSaver = CommentSaver(elementToBeReplaced, saveLineBreaks = true)
|
val commentSaver = CommentSaver(elementToBeReplaced, saveLineBreaks = true)
|
||||||
|
|
||||||
var receiver = element.getReceiverExpression()?.marked(USER_CODE_KEY)
|
var receiver = nameExpression.getReceiverExpression()?.marked(USER_CODE_KEY)
|
||||||
var receiverType = if (receiver != null) bindingContext.getType(receiver) else null
|
var receiverType = if (receiver != null) bindingContext.getType(receiver) else null
|
||||||
|
|
||||||
if (receiver == null) {
|
if (receiver == null) {
|
||||||
@@ -93,15 +91,15 @@ object ReplacementEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val introduceValuesForParameters = processValueParameterUsages(replacement, resolvedCall, bindingContext, project)
|
val introduceValuesForParameters = processValueParameterUsages()
|
||||||
|
|
||||||
processTypeParameterUsages(replacement, resolvedCall)
|
processTypeParameterUsages()
|
||||||
|
|
||||||
if (elementToBeReplaced is KtSafeQualifiedExpression) {
|
if (elementToBeReplaced is KtSafeQualifiedExpression) {
|
||||||
wrapCodeForSafeCall(replacement, receiver!!, receiverType, elementToBeReplaced, bindingContext)
|
wrapCodeForSafeCall(receiver!!, receiverType, elementToBeReplaced)
|
||||||
}
|
}
|
||||||
else if (callElement is KtBinaryExpression && callElement.operationToken == KtTokens.IDENTIFIER) {
|
else if (callElement is KtBinaryExpression && callElement.operationToken == KtTokens.IDENTIFIER) {
|
||||||
keepInfixFormIfPossible(replacement)
|
keepInfixFormIfPossible()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementToBeReplaced is KtExpression) {
|
if (elementToBeReplaced is KtExpression) {
|
||||||
@@ -135,18 +133,13 @@ object ReplacementEngine {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processValueParameterUsages(
|
private fun processValueParameterUsages(): Collection<IntroduceValueForParameter> {
|
||||||
replacement: MutableReplacementCode,
|
|
||||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
|
||||||
bindingContext: BindingContext,
|
|
||||||
project: Project
|
|
||||||
): Collection<IntroduceValueForParameter> {
|
|
||||||
val introduceValuesForParameters = ArrayList<IntroduceValueForParameter>()
|
val introduceValuesForParameters = ArrayList<IntroduceValueForParameter>()
|
||||||
|
|
||||||
// process parameters in reverse order because default values can use previous parameters
|
// process parameters in reverse order because default values can use previous parameters
|
||||||
val parameters = resolvedCall.resultingDescriptor.valueParameters
|
val parameters = resolvedCall.resultingDescriptor.valueParameters
|
||||||
for (parameter in parameters.asReversed()) {
|
for (parameter in parameters.asReversed()) {
|
||||||
val argument = argumentForParameter(parameter, resolvedCall, bindingContext, project) ?: continue
|
val argument = argumentForParameter(parameter) ?: continue
|
||||||
|
|
||||||
argument.expression.put(PARAMETER_VALUE_KEY, parameter)
|
argument.expression.put(PARAMETER_VALUE_KEY, parameter)
|
||||||
|
|
||||||
@@ -180,7 +173,7 @@ object ReplacementEngine {
|
|||||||
val value: KtExpression,
|
val value: KtExpression,
|
||||||
val valueType: KotlinType?)
|
val valueType: KotlinType?)
|
||||||
|
|
||||||
private fun processTypeParameterUsages(replacement: MutableReplacementCode, resolvedCall: ResolvedCall<out CallableDescriptor>) {
|
private fun processTypeParameterUsages() {
|
||||||
val typeParameters = resolvedCall.resultingDescriptor.original.typeParameters
|
val typeParameters = resolvedCall.resultingDescriptor.original.typeParameters
|
||||||
|
|
||||||
val callElement = resolvedCall.call.callElement
|
val callElement = resolvedCall.call.callElement
|
||||||
@@ -194,14 +187,13 @@ object ReplacementEngine {
|
|||||||
it[ReplacementCode.TYPE_PARAMETER_USAGE_KEY] == parameterName
|
it[ReplacementCode.TYPE_PARAMETER_USAGE_KEY] == parameterName
|
||||||
}
|
}
|
||||||
|
|
||||||
val factory = KtPsiFactory(callElement)
|
|
||||||
val type = resolvedCall.typeArguments[typeParameter]!!
|
val type = resolvedCall.typeArguments[typeParameter]!!
|
||||||
val typeElement = if (explicitTypeArgs != null) { // we use explicit type arguments if available to avoid shortening
|
val typeElement = if (explicitTypeArgs != null) { // we use explicit type arguments if available to avoid shortening
|
||||||
val _typeElement = explicitTypeArgs[index].typeReference?.typeElement ?: continue
|
val _typeElement = explicitTypeArgs[index].typeReference?.typeElement ?: continue
|
||||||
_typeElement.marked(USER_CODE_KEY)
|
_typeElement.marked(USER_CODE_KEY)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
factory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)).typeElement!!
|
psiFactory.createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)).typeElement!!
|
||||||
}
|
}
|
||||||
|
|
||||||
val typeClassifier = type.constructor.declarationDescriptor
|
val typeClassifier = type.constructor.declarationDescriptor
|
||||||
@@ -213,7 +205,7 @@ object ReplacementEngine {
|
|||||||
val arguments =
|
val arguments =
|
||||||
if (typeElement is KtUserType && KotlinBuiltIns.isArray(type)) typeElement.typeArgumentList?.text.orEmpty()
|
if (typeElement is KtUserType && KotlinBuiltIns.isArray(type)) typeElement.typeArgumentList?.text.orEmpty()
|
||||||
else ""
|
else ""
|
||||||
replacement.replaceExpression(usage, KtPsiFactory(usage).createExpression(
|
replacement.replaceExpression(usage, psiFactory.createExpression(
|
||||||
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(typeClassifier) + arguments
|
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(typeClassifier) + arguments
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -222,19 +214,13 @@ object ReplacementEngine {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//TODO: tests for this?
|
//TODO: tests for this?
|
||||||
replacement.replaceExpression(usage, KtPsiFactory(usage).createExpression(typeElement.text))
|
replacement.replaceExpression(usage, psiFactory.createExpression(typeElement.text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapCodeForSafeCall(
|
private fun wrapCodeForSafeCall(receiver: KtExpression, receiverType: KotlinType?, expressionToBeReplaced: KtExpression) {
|
||||||
replacement: MutableReplacementCode,
|
|
||||||
receiver: KtExpression,
|
|
||||||
receiverType: KotlinType?,
|
|
||||||
expressionToBeReplaced: KtExpression,
|
|
||||||
bindingContext: BindingContext
|
|
||||||
) {
|
|
||||||
if (replacement.statementsBefore.isEmpty()) {
|
if (replacement.statementsBefore.isEmpty()) {
|
||||||
val qualified = replacement.mainExpression as? KtQualifiedExpression
|
val qualified = replacement.mainExpression as? KtQualifiedExpression
|
||||||
if (qualified != null) {
|
if (qualified != null) {
|
||||||
@@ -242,7 +228,7 @@ object ReplacementEngine {
|
|||||||
if (qualified is KtSafeQualifiedExpression) return // already safe
|
if (qualified is KtSafeQualifiedExpression) return // already safe
|
||||||
val selector = qualified.selectorExpression
|
val selector = qualified.selectorExpression
|
||||||
if (selector != null) {
|
if (selector != null) {
|
||||||
replacement.mainExpression = KtPsiFactory(receiver).createExpressionByPattern("$0?.$1", receiver, selector)
|
replacement.mainExpression = psiFactory.createExpressionByPattern("$0?.$1", receiver, selector)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +240,7 @@ object ReplacementEngine {
|
|||||||
replacement.introduceValue(receiver, receiverType, thisReplaced, expressionToBeReplaced, safeCall = true)
|
replacement.introduceValue(receiver, receiverType, thisReplaced, expressionToBeReplaced, safeCall = true)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val ifExpression = KtPsiFactory(receiver).buildExpression {
|
val ifExpression = psiFactory.buildExpression {
|
||||||
appendFixedText("if (")
|
appendFixedText("if (")
|
||||||
appendExpression(receiver)
|
appendExpression(receiver)
|
||||||
appendFixedText("!=null) {")
|
appendFixedText("!=null) {")
|
||||||
@@ -273,7 +259,7 @@ object ReplacementEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun keepInfixFormIfPossible(replacement: MutableReplacementCode) {
|
private fun keepInfixFormIfPossible() {
|
||||||
if (replacement.statementsBefore.isNotEmpty()) return
|
if (replacement.statementsBefore.isNotEmpty()) return
|
||||||
val dotQualified = replacement.mainExpression as? KtDotQualifiedExpression ?: return
|
val dotQualified = replacement.mainExpression as? KtDotQualifiedExpression ?: return
|
||||||
val receiver = dotQualified.receiverExpression
|
val receiver = dotQualified.receiverExpression
|
||||||
@@ -283,7 +269,7 @@ object ReplacementEngine {
|
|||||||
val argument = call.valueArguments.singleOrNull() ?: return
|
val argument = call.valueArguments.singleOrNull() ?: return
|
||||||
if (argument.getArgumentName() != null) return
|
if (argument.getArgumentName() != null) return
|
||||||
val argumentExpression = argument.getArgumentExpression() ?: return
|
val argumentExpression = argument.getArgumentExpression() ?: return
|
||||||
replacement.mainExpression = KtPsiFactory(receiver).createExpressionByPattern("$0 ${nameExpression.text} $1", receiver, argumentExpression)
|
replacement.mainExpression = psiFactory.createExpressionByPattern("$0 ${nameExpression.text} $1", receiver, argumentExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtExpression?.shouldKeepValue(usageCount: Int): Boolean {
|
private fun KtExpression?.shouldKeepValue(usageCount: Int): Boolean {
|
||||||
@@ -311,11 +297,7 @@ object ReplacementEngine {
|
|||||||
val isNamed: Boolean = false,
|
val isNamed: Boolean = false,
|
||||||
val isDefaultValue: Boolean = false)
|
val isDefaultValue: Boolean = false)
|
||||||
|
|
||||||
private fun argumentForParameter(
|
private fun argumentForParameter(parameter: ValueParameterDescriptor): Argument? {
|
||||||
parameter: ValueParameterDescriptor,
|
|
||||||
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
|
||||||
bindingContext: BindingContext,
|
|
||||||
project: Project): Argument? {
|
|
||||||
val resolvedArgument = resolvedCall.valueArguments[parameter]!!
|
val resolvedArgument = resolvedCall.valueArguments[parameter]!!
|
||||||
when (resolvedArgument) {
|
when (resolvedArgument) {
|
||||||
is ExpressionValueArgument -> {
|
is ExpressionValueArgument -> {
|
||||||
@@ -353,7 +335,7 @@ object ReplacementEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val elementType = parameter.varargElementType!!
|
val elementType = parameter.varargElementType!!
|
||||||
val expression = KtPsiFactory(project).buildExpression {
|
val expression = psiFactory.buildExpression {
|
||||||
appendFixedText(arrayOfFunctionName(elementType))
|
appendFixedText(arrayOfFunctionName(elementType))
|
||||||
appendFixedText("(")
|
appendFixedText("(")
|
||||||
for ((i, argument) in arguments.withIndex()) {
|
for ((i, argument) in arguments.withIndex()) {
|
||||||
@@ -434,8 +416,6 @@ object ReplacementEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val psiFactory = KtPsiFactory(result)
|
|
||||||
|
|
||||||
for (callExpression in callsToProcess) {
|
for (callExpression in callsToProcess) {
|
||||||
val bindingContext = callExpression.analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = callExpression.analyze(BodyResolveMode.PARTIAL)
|
||||||
val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return
|
val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return
|
||||||
+1
-2
@@ -44,8 +44,7 @@ class CallableUsageReplacementStrategy(
|
|||||||
createReplacer(nameExpression)!!.invoke()
|
createReplacer(nameExpression)!!.invoke()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@Suppress("UNCHECKED_CAST")
|
CallReplacementEngine(usage, bindingContext, resolvedCall, callElement, replacement).performReplacement()
|
||||||
ReplacementEngine.performCallReplacement(usage, bindingContext, resolvedCall, callElement, replacement)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user