Initial implementation of renaming extension property usages on getter or setter rename
This commit is contained in:
+13
-7
@@ -151,13 +151,19 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
|
||||
return Name.identifier("set" + propertyName.getIdentifier().capitalize())
|
||||
}
|
||||
|
||||
private fun fromGetMethodName(methodName: Name): Name? {
|
||||
if (methodName.isSpecial()) return null
|
||||
val identifier = methodName.getIdentifier()
|
||||
if (!identifier.startsWith("get")) return null
|
||||
val name = identifier.removePrefix("get").decapitalize()
|
||||
if (!Name.isValidIdentifier(name)) return null
|
||||
return Name.identifier(name)
|
||||
companion object {
|
||||
public fun fromGetMethodName(methodName: Name): Name? = fromAccessorMethodName(methodName, "get")
|
||||
|
||||
public fun fromSetMethodName(methodName: Name): Name? = fromAccessorMethodName(methodName, "set")
|
||||
|
||||
private fun fromAccessorMethodName(methodName: Name, prefix: String): Name? {
|
||||
if (methodName.isSpecial()) return null
|
||||
val identifier = methodName.getIdentifier()
|
||||
if (!identifier.startsWith(prefix)) return null
|
||||
val name = identifier.removePrefix(prefix).decapitalize()
|
||||
if (!Name.isValidIdentifier(name)) return null
|
||||
return Name.identifier(name)
|
||||
}
|
||||
}
|
||||
|
||||
private class MyPropertyDescriptor(
|
||||
|
||||
+30
-14
@@ -38,7 +38,9 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticExtensionPropertyDescriptor
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticExtensionsScope
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
||||
@@ -135,6 +137,22 @@ public class JetSimpleNameReference(
|
||||
}
|
||||
}
|
||||
|
||||
@suppress("NAME_SHADOWING")
|
||||
var newElementName = newElementName!!
|
||||
|
||||
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
if (bindingContext[BindingContext.REFERENCE_TARGET, expression] is SyntheticExtensionPropertyDescriptor) {
|
||||
if (Name.isValidIdentifier(newElementName)) {
|
||||
val newNameAsName = Name.identifier(newElementName)
|
||||
val newName = when (access()) {
|
||||
Access.READ -> SyntheticExtensionsScope.fromGetMethodName(newNameAsName)
|
||||
Access.WRITE -> SyntheticExtensionsScope.fromSetMethodName(newNameAsName)
|
||||
Access.READ_WRITE -> SyntheticExtensionsScope.fromGetMethodName(newNameAsName) ?: SyntheticExtensionsScope.fromSetMethodName(newNameAsName)
|
||||
} ?: return expression //TODO: handle the case when get/set becomes ordinary method
|
||||
newElementName = newName.getIdentifier()
|
||||
}
|
||||
}
|
||||
|
||||
val psiFactory = JetPsiFactory(expression)
|
||||
val element = when (expression.getReferencedNameElementType()) {
|
||||
JetTokens.FIELD_IDENTIFIER -> psiFactory.createFieldIdentifier(newElementName)
|
||||
@@ -156,23 +174,21 @@ public class JetSimpleNameReference(
|
||||
var nameElement = expression.getReferencedNameElement()
|
||||
|
||||
val elementType = nameElement.getNode()?.getElementType()
|
||||
val opExpression =
|
||||
PsiTreeUtil.getParentOfType<JetExpression>(expression, javaClass<JetUnaryExpression>(), javaClass<JetBinaryExpression>())
|
||||
val opExpression = PsiTreeUtil.getParentOfType<JetExpression>(expression, javaClass<JetUnaryExpression>(), javaClass<JetBinaryExpression>())
|
||||
if (elementType is JetToken && OperatorConventions.getNameForOperationSymbol(elementType) != null && opExpression != null) {
|
||||
val oldDescriptor = expression.analyze()[BindingContext.REFERENCE_TARGET, expression]
|
||||
val oldDescriptor = bindingContext[BindingContext.REFERENCE_TARGET, expression]
|
||||
val newExpression = OperatorToFunctionIntention.convert(opExpression)
|
||||
newExpression.accept(
|
||||
object: JetTreeVisitorVoid() {
|
||||
override fun visitCallExpression(expression: JetCallExpression) {
|
||||
val callee = expression.getCalleeExpression() as? JetSimpleNameExpression
|
||||
if (callee != null && callee.analyze()[BindingContext.REFERENCE_TARGET, callee] == oldDescriptor) {
|
||||
nameElement = callee.getReferencedNameElement()
|
||||
}
|
||||
else {
|
||||
super.visitCallExpression(expression)
|
||||
}
|
||||
}
|
||||
newExpression.accept(object : JetTreeVisitorVoid() {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import testing.JavaClass
|
||||
|
||||
fun usages(javaClass: JavaClass) {
|
||||
javaClass.something = javaClass.somethingNew + 1
|
||||
javaClass.somethingNew++
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package testing;
|
||||
|
||||
public class JavaClass {
|
||||
public int getSomethingNew() { return 1; }
|
||||
public void setSomething(int value) {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import testing.JavaClass
|
||||
|
||||
fun usages(javaClass: JavaClass) {
|
||||
javaClass.something = javaClass.something + 1
|
||||
javaClass.something++
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package testing;
|
||||
|
||||
public class JavaClass {
|
||||
public int getSomething() { return 1; }
|
||||
public void setSomething(int value) {}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "JAVA_METHOD",
|
||||
"classId": "testing/JavaClass",
|
||||
"methodSignature": "int getSomething()",
|
||||
"newName": "getSomethingNew"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import testing.JavaClass
|
||||
|
||||
fun usages(javaClass: JavaClass) {
|
||||
javaClass.somethingNew = javaClass.something + 1
|
||||
javaClass.somethingNew++
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package testing;
|
||||
|
||||
public class JavaClass {
|
||||
public int getSomething() { return 1; }
|
||||
public void setSomethingNew(int value) {}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import testing.JavaClass
|
||||
|
||||
fun usages(javaClass: JavaClass) {
|
||||
javaClass.somethingNew = javaClass.something + 1
|
||||
javaClass.somethingNew++
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package testing;
|
||||
|
||||
public class JavaClass {
|
||||
public int getSomething() { return 1; }
|
||||
public void setSomething(int value) {}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "JAVA_METHOD",
|
||||
"classId": "testing/JavaClass",
|
||||
"methodSignature": "void setSomething(int value)",
|
||||
"newName": "setSomethingNew"
|
||||
}
|
||||
@@ -299,11 +299,7 @@ public abstract class AbstractRenameTest : KotlinMultiFileTestCase() {
|
||||
|
||||
|
||||
private fun String.toClassId(): ClassId {
|
||||
val lastSlash = lastIndexOf("/")
|
||||
if (lastSlash == -1) {
|
||||
throw IllegalArgumentException("Class id should contain slash: $this")
|
||||
}
|
||||
val relativeClassName = FqName(substring(lastSlash + 1))
|
||||
val packageFqName = FqName(substring(0, lastSlash).replace('/', '.'))
|
||||
val relativeClassName = FqName(substringAfterLast('/'))
|
||||
val packageFqName = FqName(substringBeforeLast('/', "").replace('/', '.'))
|
||||
return ClassId(packageFqName, relativeClassName, false)
|
||||
}
|
||||
|
||||
@@ -370,4 +370,16 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameUnaryMinus/unaryMinus.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("syntheticPropertyUsages1/renameGetMethod.test")
|
||||
public void testSyntheticPropertyUsages1_RenameGetMethod() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/syntheticPropertyUsages1/renameGetMethod.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("syntheticPropertyUsages2/renameSetMethod.test")
|
||||
public void testSyntheticPropertyUsages2_RenameSetMethod() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/syntheticPropertyUsages2/renameSetMethod.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user