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