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:
Alexey Sedunov
2016-05-27 15:07:56 +03:00
parent 9e7222906d
commit 42b71ae90c
9 changed files with 82 additions and 26 deletions
+1
View File
@@ -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
@@ -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")
@@ -0,0 +1,7 @@
package test
class MemberExtension {
fun funMe2(p: Int) {}
}
fun MemberExtension.funMe2(p: String) {}
@@ -0,0 +1,6 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test/test.kt",
"newName": "funMe2",
"withRuntime": "true"
}
@@ -0,0 +1,7 @@
package test
class MemberExtension {
fun funMe(p: Int) {}
}
fun MemberExtension./*rename*/funMe(p: String) {}
@@ -0,0 +1,7 @@
package test
class MemberExtension {
fun funMe2(p: Int) {}
}
fun MemberExtension.funMe2(p: String) {}
@@ -0,0 +1,6 @@
{
"type": "MARKED_ELEMENT",
"mainFile": "test/test.kt",
"newName": "funMe2",
"withRuntime": "true"
}
@@ -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");