Fixed rename of operator functions

This commit is contained in:
Valentin Kipyatkov
2015-07-11 14:28:41 +03:00
parent 28e9fbf9b8
commit e52b524d9a
3 changed files with 36 additions and 31 deletions
@@ -22,8 +22,9 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpression>(javaClass(), "Replace overloaded operator with function call") { public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpression>(javaClass(), "Replace overloaded operator with function call") {
@@ -126,7 +127,7 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpressi
return element return element
} }
val context = element.analyze() val context = element.analyze(BodyResolveMode.PARTIAL)
val functionCandidate = element.getResolvedCall(context) val functionCandidate = element.getResolvedCall(context)
val functionName = functionCandidate?.getCandidateDescriptor()?.getName().toString() val functionName = functionCandidate?.getCandidateDescriptor()?.getName().toString()
val elemType = context.getType(left) val elemType = context.getType(left)
@@ -195,14 +196,31 @@ public class OperatorToFunctionIntention : JetSelfTargetingIntention<JetExpressi
return callee.getParent()!!.replace(transformed) as JetExpression return callee.getParent()!!.replace(transformed) as JetExpression
} }
public fun convert(element: JetExpression): JetExpression { public fun convert(element: JetExpression): Pair<JetExpression, JetSimpleNameExpression> {
return when (element) { val result = when (element) {
is JetPrefixExpression -> convertPrefix(element) is JetPrefixExpression -> convertPrefix(element)
is JetPostfixExpression -> convertPostFix(element) is JetPostfixExpression -> convertPostFix(element)
is JetBinaryExpression -> convertBinary(element) is JetBinaryExpression -> convertBinary(element)
is JetArrayAccessExpression -> convertArrayAccess(element) is JetArrayAccessExpression -> convertArrayAccess(element)
is JetCallExpression -> convertCall(element) is JetCallExpression -> convertCall(element)
else -> element else -> throw IllegalArgumentException(element.toString())
}
return result to findCallName(result)
}
private fun findCallName(result: JetExpression): JetSimpleNameExpression {
return when (result) {
is JetBinaryExpression -> {
if (JetPsiUtil.isAssignment(result))
findCallName(result.getRight()!!)
else
findCallName(result.getLeft()!!)
}
is JetUnaryExpression -> findCallName(result.getBaseExpression()!!)
else -> result.getQualifiedElementSelector() as JetSimpleNameExpression
} }
} }
} }
@@ -33,10 +33,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -98,26 +95,16 @@ class JetSimpleNameReference(expression: JetSimpleNameExpression) : JetSimpleRef
} }
} }
var nameElement = expression.getReferencedNameElement() val nameElement = expression.getReferencedNameElement()
val elementType = nameElement.getNode()?.getElementType() val elementType = nameElement.getNode().getElementType()
val opExpression = PsiTreeUtil.getParentOfType<JetExpression>(expression, javaClass<JetUnaryExpression>(), javaClass<JetBinaryExpression>()) if (elementType is JetToken && OperatorConventions.getNameForOperationSymbol(elementType) != null) {
if (elementType is JetToken && OperatorConventions.getNameForOperationSymbol(elementType) != null && opExpression != null) { val opExpression = expression.getParent() as? JetOperationExpression
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL) if (opExpression != null) {
val oldDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, expression] val (newExpression, newNameElement) = OperatorToFunctionIntention.convert(opExpression)
val newExpression = OperatorToFunctionIntention.convert(opExpression) newNameElement.replace(element)
newExpression.accept(object : JetTreeVisitorVoid() { return newExpression
override fun visitCallExpression(expression: JetCallExpression) {
val callee = expression.getCalleeExpression() as? JetSimpleNameExpression
if (callee != null && bindingContext[BindingContext.REFERENCE_TARGET, callee] == oldDescriptor) {
nameElement = callee.getReferencedNameElement()
}
else {
super.visitCallExpression(expression)
}
}
} }
)
} }
nameElement.replace(element) nameElement.replace(element)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
@@ -112,10 +113,9 @@ private fun PsiElement.isConstructorOf(unwrappedCandidate: PsiElement) =
fun AbstractJetReference<out JetExpression>.renameImplicitConventionalCall(newName: String?): JetExpression { fun AbstractJetReference<out JetExpression>.renameImplicitConventionalCall(newName: String?): JetExpression {
if (newName == null) return expression if (newName == null) return expression
val expr = OperatorToFunctionIntention.convert(expression) as JetQualifiedExpression val (newExpression, newNameElement) = OperatorToFunctionIntention.convert(expression)
val callee = (expr.getSelectorExpression() as JetCallExpression).getCalleeExpression() as JetSimpleNameExpression newNameElement.mainReference.handleElementRename(newName)
val newCallee = callee.mainReference.handleElementRename(newName) return newExpression
return newCallee.getStrictParentOfType<JetQualifiedExpression>() as JetExpression
} }
val JetSimpleNameExpression.mainReference: JetSimpleNameReference val JetSimpleNameExpression.mainReference: JetSimpleNameReference