Rename: Rename all overridden members if user chooses to refactor base declaration(s)
#KT-8867 Fixed
This commit is contained in:
@@ -122,6 +122,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
|||||||
- [`KT-13216`](https://youtrack.jetbrains.com/issue/KT-13216) Move: Report separate conflicts for each property accessor
|
- [`KT-13216`](https://youtrack.jetbrains.com/issue/KT-13216) Move: Report separate conflicts for each property accessor
|
||||||
- [`KT-13216`](https://youtrack.jetbrains.com/issue/KT-13216) Move: Forbid moving of enum entries
|
- [`KT-13216`](https://youtrack.jetbrains.com/issue/KT-13216) Move: Forbid moving of enum entries
|
||||||
- [`KT-13553`](https://youtrack.jetbrains.com/issue/KT-13553) Move: Do not show directory selection dialog if target directory is already specified by drag-and-drop
|
- [`KT-13553`](https://youtrack.jetbrains.com/issue/KT-13553) Move: Do not show directory selection dialog if target directory is already specified by drag-and-drop
|
||||||
|
- [`KT-8867`](https://youtrack.jetbrains.com/issue/KT-8867) Rename: Rename all overridden members if user chooses to refactor base declaration(s)
|
||||||
|
|
||||||
##### New features
|
##### New features
|
||||||
|
|
||||||
|
|||||||
@@ -190,8 +190,6 @@ there.are.unused.methods.that.override.methods.you.delete=There are unused membe
|
|||||||
choose.the.ones.you.want.to.be.deleted=Choose the ones you want to be deleted.
|
choose.the.ones.you.want.to.be.deleted=Choose the ones you want to be deleted.
|
||||||
method.column=Member
|
method.column=Member
|
||||||
delete.param.in.method.hierarchy={0} is a part of method hierarchy. Do you want to delete multiple parameters?
|
delete.param.in.method.hierarchy={0} is a part of method hierarchy. Do you want to delete multiple parameters?
|
||||||
super.methods.delete.with.usage.search=delete (with usage search)
|
|
||||||
super.methods.action.key.find.usages=find usages of
|
|
||||||
|
|
||||||
find.what.implementing.methods.checkbox=&Implementing functions
|
find.what.implementing.methods.checkbox=&Implementing functions
|
||||||
find.what.overriding.methods.checkbox=Over&riding functions
|
find.what.overriding.methods.checkbox=Over&riding functions
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.search.searches.OverridingMethodsSearch
|
import com.intellij.psi.search.searches.OverridingMethodsSearch
|
||||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.DelegatingFindMemberUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.DelegatingFindMemberUsagesHandler
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler
|
||||||
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindMemberUsagesHandler
|
import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindMemberUsagesHandler
|
||||||
@@ -108,7 +109,7 @@ class KotlinFindUsagesHandlerFactory(project: Project) : FindUsagesHandlerFactor
|
|||||||
return KotlinFindMemberUsagesHandler.getInstance(declaration, factory = this)
|
return KotlinFindMemberUsagesHandler.getInstance(declaration, factory = this)
|
||||||
}
|
}
|
||||||
|
|
||||||
val declarationsToSearch = checkSuperMethods(declaration, null, "super.methods.action.key.find.usages")
|
val declarationsToSearch = checkSuperMethods(declaration, null, "find usages of")
|
||||||
return handlerForMultiple(declaration, declarationsToSearch)
|
return handlerForMultiple(declaration, declarationsToSearch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -805,7 +805,7 @@ val PsiElement.isInsideInjectedFragment: Boolean
|
|||||||
fun checkSuperMethods(
|
fun checkSuperMethods(
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
ignore: Collection<PsiElement>?,
|
ignore: Collection<PsiElement>?,
|
||||||
actionStringKey: String
|
actionString: String
|
||||||
): List<PsiElement> {
|
): List<PsiElement> {
|
||||||
fun getClassDescriptions(overriddenElementsToDescriptor: Map<PsiElement, CallableDescriptor>): List<String> {
|
fun getClassDescriptions(overriddenElementsToDescriptor: Map<PsiElement, CallableDescriptor>): List<String> {
|
||||||
return overriddenElementsToDescriptor.entries.map { entry ->
|
return overriddenElementsToDescriptor.entries.map { entry ->
|
||||||
@@ -834,7 +834,7 @@ fun checkSuperMethods(
|
|||||||
"x.overrides.y.in.class.list",
|
"x.overrides.y.in.class.list",
|
||||||
DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(declarationDescriptor),
|
DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(declarationDescriptor),
|
||||||
"\n${superClassDescriptions.joinToString(separator = "")}",
|
"\n${superClassDescriptions.joinToString(separator = "")}",
|
||||||
KotlinBundle.message(actionStringKey)
|
actionString
|
||||||
)
|
)
|
||||||
|
|
||||||
val exitCode = Messages.showYesNoCancelDialog(declaration.project, message, IdeBundle.message("title.warning"), Messages.getQuestionIcon())
|
val exitCode = Messages.showYesNoCancelDialog(declaration.project, message, IdeBundle.message("title.warning"), Messages.getQuestionIcon())
|
||||||
|
|||||||
+48
-7
@@ -17,13 +17,17 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.rename
|
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiMethod
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.PsiNamedElement
|
||||||
import com.intellij.psi.PsiReference
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.psi.search.SearchScope
|
import com.intellij.psi.search.SearchScope
|
||||||
import com.intellij.refactoring.JavaRefactoringSettings
|
import com.intellij.refactoring.JavaRefactoringSettings
|
||||||
import com.intellij.refactoring.listeners.RefactoringElementListener
|
import com.intellij.refactoring.listeners.RefactoringElementListener
|
||||||
|
import com.intellij.refactoring.rename.RenameDialog
|
||||||
import com.intellij.refactoring.rename.RenameJavaMethodProcessor
|
import com.intellij.refactoring.rename.RenameJavaMethodProcessor
|
||||||
|
import com.intellij.refactoring.rename.RenameProcessor
|
||||||
import com.intellij.refactoring.rename.RenameUtil
|
import com.intellij.refactoring.rename.RenameUtil
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
@@ -33,18 +37,20 @@ import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
|||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.checkSuperMethods
|
||||||
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
|
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
|
||||||
import org.jetbrains.kotlin.idea.references.KtReference
|
import org.jetbrains.kotlin.idea.references.KtReference
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import java.lang.IllegalStateException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||||
private val javaMethodProcessorInstance = RenameJavaMethodProcessor()
|
private val javaMethodProcessorInstance = RenameJavaMethodProcessor()
|
||||||
|
|
||||||
override fun canProcessElement(element: PsiElement): Boolean {
|
override fun canProcessElement(element: PsiElement): Boolean {
|
||||||
return element is KtNamedFunction || (element is KtLightMethod && element.kotlinOrigin is KtNamedFunction)
|
return element is KtNamedFunction || (element is KtLightMethod && element.kotlinOrigin is KtNamedFunction) || element is FunctionWithSupersWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isToSearchInComments(psiElement: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD
|
override fun isToSearchInComments(psiElement: PsiElement) = JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD
|
||||||
@@ -87,11 +93,30 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
|||||||
checkRedeclarations(descriptor, newName, result)
|
checkRedeclarations(descriptor, newName, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FunctionWithSupersWrapper(
|
||||||
|
val originalDeclaration: KtNamedFunction,
|
||||||
|
val supers: List<PsiElement>
|
||||||
|
) : KtLightElement<KtNamedFunction, KtNamedFunction>, PsiNamedElement by originalDeclaration {
|
||||||
|
override val kotlinOrigin: KtNamedFunction?
|
||||||
|
get() = originalDeclaration
|
||||||
|
override val clsDelegate: KtNamedFunction
|
||||||
|
get() = originalDeclaration
|
||||||
|
}
|
||||||
|
|
||||||
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
|
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
|
||||||
val wrappedMethod = wrapPsiMethod(element) ?: return element
|
val wrappedMethod = wrapPsiMethod(element) ?: return element
|
||||||
|
|
||||||
// Use java dialog to ask we should rename function with the base element
|
val deepestSuperMethods = wrappedMethod.findDeepestSuperMethods()
|
||||||
val substitutedJavaElement = javaMethodProcessorInstance.substituteElementToRename(wrappedMethod, editor)
|
val substitutedJavaElement = when {
|
||||||
|
deepestSuperMethods.isEmpty() -> return element
|
||||||
|
wrappedMethod.isConstructor || deepestSuperMethods.size == 1 || element !is KtNamedFunction -> {
|
||||||
|
javaMethodProcessorInstance.substituteElementToRename(wrappedMethod, editor)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val chosenElements = checkSuperMethods(element, null, "rename")
|
||||||
|
if (chosenElements.size > 1) FunctionWithSupersWrapper(element, chosenElements) else wrappedMethod
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (substitutedJavaElement is KtLightMethod && element is KtDeclaration) {
|
if (substitutedJavaElement is KtLightMethod && element is KtDeclaration) {
|
||||||
return substitutedJavaElement.kotlinOrigin as? KtNamedFunction
|
return substitutedJavaElement.kotlinOrigin as? KtNamedFunction
|
||||||
@@ -100,14 +125,30 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
|||||||
return substitutedJavaElement
|
return substitutedJavaElement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun createRenameDialog(project: Project, element: PsiElement, nameSuggestionContext: PsiElement?, editor: Editor?): RenameDialog {
|
||||||
|
val elementForDialog = (element as? FunctionWithSupersWrapper)?.originalDeclaration ?: element
|
||||||
|
return object : RenameDialog(project, elementForDialog, nameSuggestionContext, editor) {
|
||||||
|
override fun createRenameProcessor(newName: String) = RenameProcessor(getProject(), element, newName, isSearchInComments, isSearchInNonJavaFiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun prepareRenaming(element: PsiElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
|
override fun prepareRenaming(element: PsiElement, newName: String?, allRenames: MutableMap<PsiElement, String>, scope: SearchScope) {
|
||||||
super.prepareRenaming(element, newName, allRenames, scope)
|
super.prepareRenaming(element, newName, allRenames, scope)
|
||||||
if (element is KtLightMethod && newName != null && getJvmName(element) == null) {
|
|
||||||
|
if (newName == null) return
|
||||||
|
|
||||||
|
if (element is KtLightMethod && getJvmName(element) == null) {
|
||||||
(element.kotlinOrigin as? KtNamedFunction)?.let { allRenames[it] = newName }
|
(element.kotlinOrigin as? KtNamedFunction)?.let { allRenames[it] = newName }
|
||||||
}
|
}
|
||||||
val psiMethod = wrapPsiMethod(element)
|
if (element is FunctionWithSupersWrapper) {
|
||||||
if (psiMethod?.containingClass != null) {
|
allRenames.remove(element)
|
||||||
javaMethodProcessorInstance.prepareRenaming(psiMethod, newName, allRenames, scope)
|
}
|
||||||
|
for (declaration in (if (element is FunctionWithSupersWrapper) element.supers else listOf(element))) {
|
||||||
|
val psiMethod = wrapPsiMethod(declaration) ?: continue
|
||||||
|
allRenames[declaration] = newName
|
||||||
|
if (psiMethod.containingClass != null) {
|
||||||
|
javaMethodProcessorInstance.prepareRenaming(psiMethod, newName, allRenames, scope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-5
@@ -344,11 +344,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
|
|||||||
if (ApplicationManager.getApplication()!!.isUnitTestMode) return Collections.singletonList(element)
|
if (ApplicationManager.getApplication()!!.isUnitTestMode) return Collections.singletonList(element)
|
||||||
|
|
||||||
return when (element) {
|
return when (element) {
|
||||||
is KtNamedFunction, is KtProperty ->
|
is KtNamedFunction, is KtProperty -> checkSuperMethods(element as KtDeclaration, allElementsToDelete, "delete (with usage search)")
|
||||||
checkSuperMethods(
|
|
||||||
element as KtDeclaration, allElementsToDelete, "super.methods.delete.with.usage.search"
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> super.getElementsToSearch(element, module, allElementsToDelete)
|
else -> super.getElementsToSearch(element, module, allElementsToDelete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user