Rename: Do not show 'Rename overloads' options if target function has no
overloads. Consider extensions and members overloads if they have the same recever class #KT-8541 Fixed #KT-8786 Fixed
This commit is contained in:
@@ -184,6 +184,7 @@
|
||||
- [`KT-8044`](https://youtrack.jetbrains.com/issue/KT-8044), [`KT-9432`](https://youtrack.jetbrains.com/issue/KT-9432) Support @JvmName annotation in rename refactoring
|
||||
|
||||
###### Issues fixed
|
||||
- [`KT-8541`](https://youtrack.jetbrains.com/issue/KT-8541), [`KT-8786`](https://youtrack.jetbrains.com/issue/KT-8786) Do now show 'Rename overloads' options if target function has no overloads
|
||||
- [`KT-8860`](https://youtrack.jetbrains.com/issue/KT-8860) Allow renaming class by constructor delegation call referencing primary constructor
|
||||
- [`KT-8892`](https://youtrack.jetbrains.com/issue/KT-8892) Suggest renaming base declarations on overriding members in object literals
|
||||
- [`KT-9156`](https://youtrack.jetbrains.com/issue/KT-9156) Quote non-identifier names in Kotlin references
|
||||
|
||||
+29
-26
@@ -16,22 +16,29 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.refactoring.JavaRefactoringSettings
|
||||
import com.intellij.refactoring.RefactoringBundle
|
||||
import com.intellij.refactoring.rename.naming.AutomaticRenamer
|
||||
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
|
||||
import org.jetbrains.kotlin.psi.KtClassBody
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.getAllAccessibleFunctions
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
class AutomaticOverloadsRenamer(function: KtNamedFunction, newName: String) : AutomaticRenamer() {
|
||||
init {
|
||||
myElements.addAll(function.getOverloads().filter { it != function })
|
||||
function.getOverloads().mapNotNullTo(myElements) {
|
||||
val candidate = it.source.getPsi() as? KtNamedFunction ?: return@mapNotNullTo null
|
||||
if (candidate != function) candidate else null
|
||||
}
|
||||
suggestAllNames(function.name, newName)
|
||||
}
|
||||
|
||||
@@ -41,30 +48,26 @@ class AutomaticOverloadsRenamer(function: KtNamedFunction, newName: String) : Au
|
||||
override fun isSelectedByDefault(): Boolean = true
|
||||
}
|
||||
|
||||
private fun KtNamedFunction.getOverloads(): Collection<KtNamedFunction> {
|
||||
val parent = parent
|
||||
when (parent) {
|
||||
is KtFile -> {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(this)
|
||||
if (module != null) {
|
||||
val searchScope = GlobalSearchScope.moduleScope(module)
|
||||
val fqName = fqName
|
||||
if (fqName != null) {
|
||||
return KotlinTopLevelFunctionFqnNameIndex.getInstance().get(fqName.asString(), project, searchScope)
|
||||
}
|
||||
}
|
||||
}
|
||||
is KtClassBody -> {
|
||||
return parent.declarations.filterIsInstance<KtNamedFunction>().filter { it.name == this.name }
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
private fun KtNamedFunction.getOverloads(): Collection<FunctionDescriptor> {
|
||||
val name = nameAsName ?: return emptyList()
|
||||
val resolutionFacade = getResolutionFacade()
|
||||
val descriptor = resolutionFacade.resolveToDescriptor(this) as CallableDescriptor
|
||||
val context = resolutionFacade.analyze(this, BodyResolveMode.FULL)
|
||||
val scope = getResolutionScope(context, resolutionFacade)
|
||||
val extensionReceiverClass = descriptor.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor
|
||||
|
||||
val overloadsFromFunctionScope = scope.getAllAccessibleFunctions(name)
|
||||
if (extensionReceiverClass == null) return overloadsFromFunctionScope
|
||||
|
||||
val overloadsFromExtensionReceiver = extensionReceiverClass.unsubstitutedMemberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
|
||||
return overloadsFromFunctionScope + overloadsFromExtensionReceiver
|
||||
}
|
||||
|
||||
class AutomaticOverloadsRenamerFactory : AutomaticRenamerFactory {
|
||||
override fun isApplicable(element: PsiElement): Boolean {
|
||||
return element is KtNamedFunction && element.name != null
|
||||
&& (element.parent is KtFile || element.parent is KtClassBody)
|
||||
if (element !is KtNamedFunction) return false
|
||||
if (element.isLocal) return false
|
||||
return element.getOverloads().size > 1
|
||||
}
|
||||
|
||||
override fun getOptionName() = RefactoringBundle.message("rename.overloads")
|
||||
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
class MemberExtension {
|
||||
fun funMe2(p: Int) {}
|
||||
}
|
||||
|
||||
fun MemberExtension.funMe2(p: String) {}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test/test.kt",
|
||||
"newName": "funMe2",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
class MemberExtension {
|
||||
fun funMe(p: Int) {}
|
||||
}
|
||||
|
||||
fun MemberExtension./*rename*/funMe(p: String) {}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
class MemberExtension {
|
||||
fun funMe2(p: Int) {}
|
||||
}
|
||||
|
||||
fun MemberExtension.funMe2(p: String) {}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "test/test.kt",
|
||||
"newName": "funMe2",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package test
|
||||
|
||||
class MemberExtension {
|
||||
fun /*rename*/funMe(p: Int) {}
|
||||
}
|
||||
|
||||
fun MemberExtension.funMe(p: String) {}
|
||||
@@ -65,12 +65,24 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("automaticRenamerOverloadsExtensionAndMember/automaticRenamerOverloadsExtensionAndMember.test")
|
||||
public void testAutomaticRenamerOverloadsExtensionAndMember_AutomaticRenamerOverloadsExtensionAndMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/automaticRenamerOverloadsExtensionAndMember.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("automaticRenamerOverloadsJavaClass/overloads.test")
|
||||
public void testAutomaticRenamerOverloadsJavaClass_Overloads() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamerOverloadsJavaClass/overloads.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("automaticRenamerOverloadsMemberAndExtension/automaticRenamerOverloadsMemberAndExtension.test")
|
||||
public void testAutomaticRenamerOverloadsMemberAndExtension_AutomaticRenamerOverloadsMemberAndExtension() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/automaticRenamerOverloadsMemberAndExtension.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("automaticRenamerOverloadsObject/object.test")
|
||||
public void testAutomaticRenamerOverloadsObject_Object() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamerOverloadsObject/object.test");
|
||||
|
||||
Reference in New Issue
Block a user