Rename: Copy default values if function to be renamed inherits default values from some base function which is excluded from rename
#KT-9446 Fixed
This commit is contained in:
@@ -192,6 +192,7 @@
|
||||
- [`KT-9157`](https://youtrack.jetbrains.com/issue/KT-9157) Fixed in-place rename of Kotlin expression referring Java declaration
|
||||
- [`KT-9241`](https://youtrack.jetbrains.com/issue/KT-9241) Do not replace Java references to synthetic component functions when renaming constructor parameter
|
||||
- [`KT-9444`](https://youtrack.jetbrains.com/issue/KT-9444) Rename dialog: Allow typing any identifier without backquotes
|
||||
- [`KT-9446`](https://youtrack.jetbrains.com/issue/KT-9446) Warn about calls with default arguments if function to be renamed inherits default values from some base function which is excluded from rename
|
||||
- [`KT-10713`](https://youtrack.jetbrains.com/issue/KT-10713) Skip read-only declarations when renaming parameters
|
||||
|
||||
#### Java to Kotlin converter
|
||||
|
||||
+16
-5
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import java.util.*
|
||||
|
||||
class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
private val javaMethodProcessorInstance = RenameJavaMethodProcessor()
|
||||
@@ -59,12 +60,12 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
}
|
||||
|
||||
override fun findCollisions(
|
||||
element: PsiElement?,
|
||||
element: PsiElement,
|
||||
newName: String?,
|
||||
allRenames: Map<out PsiElement?, String>,
|
||||
allRenames: Map<out PsiElement, String>,
|
||||
result: MutableList<UsageInfo>
|
||||
) {
|
||||
checkConflictsAndReplaceUsageInfos(result)
|
||||
checkConflictsAndReplaceUsageInfos(element, allRenames, result)
|
||||
}
|
||||
|
||||
override fun substituteElementToRename(element: PsiElement?, editor: Editor?): PsiElement? {
|
||||
@@ -88,10 +89,20 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun renameElement(element: PsiElement?, newName: String?, usages: Array<out UsageInfo>?, listener: RefactoringElementListener?) {
|
||||
override fun renameElement(element: PsiElement, newName: String?, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
|
||||
val simpleUsages = ArrayList<UsageInfo>(usages.size)
|
||||
for (usage in usages) {
|
||||
if (usage is LostDefaultValuesInOverridingFunctionUsageInfo) {
|
||||
usage.apply()
|
||||
continue
|
||||
}
|
||||
|
||||
simpleUsages += usage
|
||||
}
|
||||
|
||||
super.renameElement(element, newName, usages, listener)
|
||||
|
||||
(element?.unwrapped as? KtNamedDeclaration)?.let { dropOverrideKeywordIfNecessary(it) }
|
||||
(element.unwrapped as? KtNamedDeclaration)?.let { dropOverrideKeywordIfNecessary(it) }
|
||||
}
|
||||
|
||||
private fun wrapPsiMethod(element: PsiElement?): PsiMethod? = when (element) {
|
||||
|
||||
@@ -17,31 +17,47 @@
|
||||
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.refactoring.rename.ResolvableCollisionUsageInfo
|
||||
import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.dropDefaultValue
|
||||
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle
|
||||
import org.jetbrains.kotlin.idea.references.AbstractKtReference
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
fun checkConflictsAndReplaceUsageInfos(result: MutableList<UsageInfo>) {
|
||||
val usagesToAdd = ArrayList<UsageInfo>()
|
||||
val usagesToRemove = ArrayList<UsageInfo>()
|
||||
|
||||
for (usageInfo in result) {
|
||||
val ref = usageInfo.reference
|
||||
if (usageInfo !is MoveRenameUsageInfo || ref !is AbstractKtReference<*> || ref.canRename()) continue
|
||||
|
||||
val refElement = usageInfo.element
|
||||
val referencedElement = usageInfo.referencedElement
|
||||
if (refElement != null && referencedElement != null) {
|
||||
usagesToAdd.add(UnresolvableConventionViolationUsageInfo(refElement, referencedElement))
|
||||
usagesToRemove.add(usageInfo)
|
||||
}
|
||||
fun checkConflictsAndReplaceUsageInfos(
|
||||
element: PsiElement,
|
||||
allRenames: Map<out PsiElement?, String>,
|
||||
result: MutableList<UsageInfo>
|
||||
) {
|
||||
element.getOverriddenFunctionWithDefaultValues(allRenames)?.let { baseFunction ->
|
||||
result += LostDefaultValuesInOverridingFunctionUsageInfo(element.unwrapped as KtNamedFunction, baseFunction)
|
||||
}
|
||||
|
||||
result.removeAll(usagesToRemove)
|
||||
result.addAll(usagesToAdd)
|
||||
val usageIterator = result.listIterator()
|
||||
while (usageIterator.hasNext()) {
|
||||
val usageInfo = usageIterator.next() as? MoveRenameUsageInfo ?: continue
|
||||
val ref = usageInfo.reference as? AbstractKtReference<*> ?: continue
|
||||
if (!ref.canRename()) {
|
||||
val refElement = usageInfo.element ?: continue
|
||||
val referencedElement = usageInfo.referencedElement ?: continue
|
||||
usageIterator.set(UnresolvableConventionViolationUsageInfo(refElement, referencedElement))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.getOverriddenFunctionWithDefaultValues(allRenames: Map<out PsiElement?, String>): KtNamedFunction? {
|
||||
val elementsToRename = allRenames.keys.mapNotNull { it?.unwrapped }
|
||||
val function = unwrapped as? KtNamedFunction ?: return null
|
||||
val descriptor = function.resolveToDescriptor() as FunctionDescriptor
|
||||
return descriptor.overriddenDescriptors
|
||||
.mapNotNull { it.source.getPsi() as? KtNamedFunction }
|
||||
.firstOrNull { it !in elementsToRename && it.valueParameters.any { it.hasDefaultValue() }}
|
||||
}
|
||||
|
||||
class UnresolvableConventionViolationUsageInfo(
|
||||
@@ -50,3 +66,17 @@ class UnresolvableConventionViolationUsageInfo(
|
||||
) : UnresolvableCollisionUsageInfo(element, referencedElement) {
|
||||
override fun getDescription(): String = KotlinRefactoringBundle.message("naming.convention.will.be.violated.after.rename")
|
||||
}
|
||||
|
||||
class LostDefaultValuesInOverridingFunctionUsageInfo(
|
||||
function: KtNamedFunction,
|
||||
private val baseFunction: KtNamedFunction
|
||||
) : ResolvableCollisionUsageInfo(function, function) {
|
||||
fun apply() {
|
||||
val function = element as? KtNamedFunction ?: return
|
||||
for ((subParam, superParam) in (function.valueParameters zip baseFunction.valueParameters)) {
|
||||
val defaultValue = superParam.defaultValue ?: continue
|
||||
subParam.dropDefaultValue()
|
||||
subParam.addRange(superParam.equalsToken, defaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user