fix broken merge; support for renaming primary constructor parameter which declares an overridden property

This commit is contained in:
Dmitry Jemerov
2015-08-27 15:41:31 +02:00
parent 3e5c687e9d
commit 63d477e355
10 changed files with 114 additions and 28 deletions
@@ -151,6 +151,12 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
return null return null
} }
private fun searchPropertyMethods(queryParameters: ReferencesSearch.SearchParameters, parameter: JetParameter) {
val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(parameter) }
searchNamedElement(queryParameters, propertyMethods.getter)
searchNamedElement(queryParameters, propertyMethods.setter)
}
private fun searchLightElements(queryParameters: ReferencesSearch.SearchParameters, element: PsiElement) { private fun searchLightElements(queryParameters: ReferencesSearch.SearchParameters, element: PsiElement) {
when (element) { when (element) {
is JetClassOrObject -> processJetClassOrObject(element, queryParameters) is JetClassOrObject -> processJetClassOrObject(element, queryParameters)
@@ -167,17 +173,18 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
searchNamedElement(queryParameters, staticFromCompanionObject) searchNamedElement(queryParameters, staticFromCompanionObject)
} }
} }
is JetProperty -> { is JetProperty -> {
val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(element) } val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(element) }
searchNamedElement(queryParameters, propertyMethods.getGetter()) searchNamedElement(queryParameters, propertyMethods.getter)
searchNamedElement(queryParameters, propertyMethods.getSetter()) searchNamedElement(queryParameters, propertyMethods.setter)
searchNamedElement(queryParameters, propertyMethods.backingField)
} }
is JetParameter -> { is JetParameter -> {
val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(element) } searchPropertyMethods(queryParameters, element)
searchNamedElement(queryParameters, propertyMethods.getGetter())
searchNamedElement(queryParameters, propertyMethods.getSetter())
searchNamedElement(queryParameters, propertyMethods.getBackingField())
} }
is KotlinLightMethod -> { is KotlinLightMethod -> {
val declaration = element.getOrigin() val declaration = element.getOrigin()
if (declaration is JetProperty || (declaration is JetParameter && declaration.hasValOrVar())) { if (declaration is JetProperty || (declaration is JetParameter && declaration.hasValOrVar())) {
@@ -193,6 +200,7 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
} }
} }
} }
is KotlinLightParameter -> { is KotlinLightParameter -> {
val origin = element.getOrigin() ?: return val origin = element.getOrigin() ?: return
val componentFunctionDescriptor = origin.dataClassComponentFunction() val componentFunctionDescriptor = origin.dataClassComponentFunction()
@@ -206,9 +214,7 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
} }
} }
val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(origin) } searchPropertyMethods(queryParameters, origin)
searchNamedElement(queryParameters, propertyMethods.getGetter())
searchNamedElement(queryParameters, propertyMethods.getSetter())
} }
} }
} }
@@ -33,11 +33,13 @@ import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.lexer.JetTokens
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetCallableDeclaration
import org.jetbrains.kotlin.psi.JetClassOrObject import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.psi.JetParameter import org.jetbrains.kotlin.psi.JetParameter
import org.jetbrains.kotlin.psi.JetProperty import org.jetbrains.kotlin.psi.JetProperty
@@ -56,35 +58,32 @@ public class RenameKotlinPropertyProcessor : RenamePsiElementProcessor() {
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? { override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
val namedUnwrappedElement = element?.namedUnwrappedElement val namedUnwrappedElement = element?.namedUnwrappedElement
if (namedUnwrappedElement is JetParameter) {
return namedUnwrappedElement
}
val jetProperty = namedUnwrappedElement as? JetProperty val callableDeclaration = namedUnwrappedElement as? JetCallableDeclaration
if (jetProperty == null) throw IllegalStateException("Can't be for element $element there because of canProcessElement()") if (callableDeclaration == null) throw IllegalStateException("Can't be for element $element there because of canProcessElement()")
val deepestSuperProperty = findDeepestOverriddenProperty(jetProperty) val deepestSuperDeclaration = findDeepestOverriddenDeclaration(callableDeclaration)
if (deepestSuperProperty == null || deepestSuperProperty == jetProperty) { if (deepestSuperDeclaration == null || deepestSuperDeclaration == callableDeclaration) {
return jetProperty return callableDeclaration
} }
if (ApplicationManager.getApplication()!!.isUnitTestMode()) { if (ApplicationManager.getApplication()!!.isUnitTestMode()) {
return deepestSuperProperty return deepestSuperDeclaration
} }
val containsText: String? = val containsText: String? =
deepestSuperProperty.getFqName()?.parent()?.asString() ?: deepestSuperDeclaration.getFqName()?.parent()?.asString() ?:
(deepestSuperProperty.getParent() as? JetClassOrObject)?.getName() (deepestSuperDeclaration.getParent() as? JetClassOrObject)?.getName()
val result = Messages.showYesNoCancelDialog( val result = Messages.showYesNoCancelDialog(
deepestSuperProperty.getProject(), deepestSuperDeclaration.getProject(),
if (containsText != null) "Do you want to rename base property from \n$containsText" else "Do you want to rename base property", if (containsText != null) "Do you want to rename base property from \n$containsText" else "Do you want to rename base property",
"Rename warning", "Rename warning",
Messages.getQuestionIcon()) Messages.getQuestionIcon())
return when (result) { return when (result) {
Messages.YES -> deepestSuperProperty Messages.YES -> deepestSuperDeclaration
Messages.NO -> jetProperty Messages.NO -> callableDeclaration
else -> /* Cancel rename */ null else -> /* Cancel rename */ null
} }
} }
@@ -177,10 +176,14 @@ public class RenameKotlinPropertyProcessor : RenamePsiElementProcessor() {
} }
} }
private fun findDeepestOverriddenProperty(jetProperty: JetProperty): JetProperty? { private fun findDeepestOverriddenDeclaration(declaration: JetCallableDeclaration): JetCallableDeclaration? {
if (jetProperty.getModifierList()?.hasModifier(JetTokens.OVERRIDE_KEYWORD) == true) { if (declaration.getModifierList()?.hasModifier(JetTokens.OVERRIDE_KEYWORD) == true) {
val bindingContext = jetProperty.analyze() val bindingContext = declaration.analyze()
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, jetProperty] var descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
if (descriptor is ValueParameterDescriptor) {
descriptor = bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor]
?: return declaration
}
if (descriptor != null) { if (descriptor != null) {
assert(descriptor is PropertyDescriptor, "Property descriptor is expected") assert(descriptor is PropertyDescriptor, "Property descriptor is expected")
@@ -191,7 +194,7 @@ public class RenameKotlinPropertyProcessor : RenamePsiElementProcessor() {
val deepest = supers.first() val deepest = supers.first()
if (deepest != descriptor) { if (deepest != descriptor) {
val superPsiElement = DescriptorToSourceUtils.descriptorToDeclaration(deepest) val superPsiElement = DescriptorToSourceUtils.descriptorToDeclaration(deepest)
return superPsiElement as? JetProperty return superPsiElement as? JetCallableDeclaration
} }
} }
} }
@@ -0,0 +1,10 @@
package testing.rename
public open class Foo(public open val second: String)
public class Bar(public override val /*rename*/second: String) : Foo(second) {
}
fun usages(f: Foo, b: Bar): String {
return f.second + b.second
}
@@ -0,0 +1,9 @@
package testing;
import testing.rename.*;
class JavaClient {
public String foo(Foo f) {
return f.getSecond();
}
}
@@ -0,0 +1,14 @@
package testng;
import testing.rename.Foo;
public class FooImpl extends Foo {
public FooImpl(String first) {
super(first);
}
@Override
public int getSecond() {
return "abc";
}
}
@@ -0,0 +1,10 @@
package testing.rename
public open class Foo(public open val first: String)
public class Bar(public override val /*rename*/first: String) : Foo(first) {
}
fun usages(f: Foo, b: Bar): String {
return f.first + b.first
}
@@ -0,0 +1,9 @@
package testing;
import testing.rename.*;
class JavaClient {
public String foo(Foo f) {
return f.getFirst();
}
}
@@ -0,0 +1,14 @@
package testng;
import testing.rename.Foo;
public class FooImpl extends Foo {
public FooImpl(String first) {
super(first);
}
@Override
public int getFirst() {
return "abc";
}
}
@@ -0,0 +1,5 @@
{
"type": "MARKED_ELEMENT",
"newName": "second",
"mainFile": "RenameKotlinPrimaryConstructorPropertyFromOverride.kt"
}
@@ -317,6 +317,12 @@ public class RenameTestGenerated extends AbstractRenameTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("renameKotlinPrimaryConstructorPropertyFromOverride/renameKotlinPrimaryConstructorPropertyFromOverride.test")
public void testRenameKotlinPrimaryConstructorPropertyFromOverride_RenameKotlinPrimaryConstructorPropertyFromOverride() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameKotlinPrimaryConstructorPropertyFromOverride/renameKotlinPrimaryConstructorPropertyFromOverride.test");
doTest(fileName);
}
@TestMetadata("renameKotlinStaticMethod/renameKotlinStaticMethod.test") @TestMetadata("renameKotlinStaticMethod/renameKotlinStaticMethod.test")
public void testRenameKotlinStaticMethod_RenameKotlinStaticMethod() throws Exception { public void testRenameKotlinStaticMethod_RenameKotlinStaticMethod() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameKotlinStaticMethod/renameKotlinStaticMethod.test"); String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameKotlinStaticMethod/renameKotlinStaticMethod.test");