From 42b71ae90c8313942592226c58f17a279cc66d51 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 27 May 2016 15:07:56 +0300 Subject: [PATCH] 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 --- ChangeLog.md | 1 + .../rename/AutomaticOverloadsRenamer.kt | 55 ++++++++++--------- .../after/test/test.kt | 7 +++ ...ticRenamerOverloadsExtensionAndMember.test | 6 ++ .../before/test/test.kt | 7 +++ .../after/test/test.kt | 7 +++ ...ticRenamerOverloadsMemberAndExtension.test | 6 ++ .../before/test/test.kt | 7 +++ .../rename/RenameTestGenerated.java | 12 ++++ 9 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/after/test/test.kt create mode 100644 idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/automaticRenamerOverloadsExtensionAndMember.test create mode 100644 idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/before/test/test.kt create mode 100644 idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/after/test/test.kt create mode 100644 idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/automaticRenamerOverloadsMemberAndExtension.test create mode 100644 idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/before/test/test.kt diff --git a/ChangeLog.md b/ChangeLog.md index c429660b67d..ced371087c0 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -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 diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/AutomaticOverloadsRenamer.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/AutomaticOverloadsRenamer.kt index 783ecd4e3e0..44a835fa593 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/AutomaticOverloadsRenamer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/rename/AutomaticOverloadsRenamer.kt @@ -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 { - 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().filter { it.name == this.name } - } - } - return emptyList() +private fun KtNamedFunction.getOverloads(): Collection { + 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") diff --git a/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/after/test/test.kt b/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/after/test/test.kt new file mode 100644 index 00000000000..942c7dd9d0f --- /dev/null +++ b/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/after/test/test.kt @@ -0,0 +1,7 @@ +package test + +class MemberExtension { + fun funMe2(p: Int) {} +} + +fun MemberExtension.funMe2(p: String) {} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/automaticRenamerOverloadsExtensionAndMember.test b/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/automaticRenamerOverloadsExtensionAndMember.test new file mode 100644 index 00000000000..b119a405a82 --- /dev/null +++ b/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/automaticRenamerOverloadsExtensionAndMember.test @@ -0,0 +1,6 @@ +{ + "type": "MARKED_ELEMENT", + "mainFile": "test/test.kt", + "newName": "funMe2", + "withRuntime": "true" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/before/test/test.kt b/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/before/test/test.kt new file mode 100644 index 00000000000..36627800aab --- /dev/null +++ b/idea/testData/refactoring/rename/automaticRenamerOverloadsExtensionAndMember/before/test/test.kt @@ -0,0 +1,7 @@ +package test + +class MemberExtension { + fun funMe(p: Int) {} +} + +fun MemberExtension./*rename*/funMe(p: String) {} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/after/test/test.kt b/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/after/test/test.kt new file mode 100644 index 00000000000..942c7dd9d0f --- /dev/null +++ b/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/after/test/test.kt @@ -0,0 +1,7 @@ +package test + +class MemberExtension { + fun funMe2(p: Int) {} +} + +fun MemberExtension.funMe2(p: String) {} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/automaticRenamerOverloadsMemberAndExtension.test b/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/automaticRenamerOverloadsMemberAndExtension.test new file mode 100644 index 00000000000..b119a405a82 --- /dev/null +++ b/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/automaticRenamerOverloadsMemberAndExtension.test @@ -0,0 +1,6 @@ +{ + "type": "MARKED_ELEMENT", + "mainFile": "test/test.kt", + "newName": "funMe2", + "withRuntime": "true" +} \ No newline at end of file diff --git a/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/before/test/test.kt b/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/before/test/test.kt new file mode 100644 index 00000000000..54e08483dd0 --- /dev/null +++ b/idea/testData/refactoring/rename/automaticRenamerOverloadsMemberAndExtension/before/test/test.kt @@ -0,0 +1,7 @@ +package test + +class MemberExtension { + fun /*rename*/funMe(p: Int) {} +} + +fun MemberExtension.funMe(p: String) {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java index 051c85dee4e..bbece237a4d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/rename/RenameTestGenerated.java @@ -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");