Rename: Fix rename of ambiguous import reference to class/function when some referenced declarations are not changed
#KT-6663 Fixed (cherry picked from commit 9ba8ecd)
This commit is contained in:
@@ -224,6 +224,7 @@
|
||||
|
||||
###### Issues fixed
|
||||
- [`KT-6363`](https://youtrack.jetbrains.com/issue/KT-6363) Do not rename ambiguous references in import directives
|
||||
- [`KT-6663`](https://youtrack.jetbrains.com/issue/KT-6663) Fixed rename of ambiguous import reference to class/function when some referenced declarations are not changed
|
||||
- [`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-8544`](https://youtrack.jetbrains.com/issue/KT-8544) Show more detailed description in Rename dialog
|
||||
- [`KT-8562`](https://youtrack.jetbrains.com/issue/KT-8562) Show conflicts dialog on attempt of redeclaration
|
||||
|
||||
+14
-1
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import java.util.*
|
||||
|
||||
class RenameKotlinClassProcessor : RenameKotlinPsiProcessor() {
|
||||
override fun canProcessElement(element: PsiElement): Boolean {
|
||||
@@ -108,7 +109,19 @@ class RenameKotlinClassProcessor : RenameKotlinPsiProcessor() {
|
||||
}
|
||||
|
||||
override fun renameElement(element: PsiElement, newName: String?, usages: Array<out UsageInfo>, listener: RefactoringElementListener?) {
|
||||
super.renameElement(element, newName, usages, listener)
|
||||
val simpleUsages = ArrayList<UsageInfo>(usages.size)
|
||||
val ambiguousImportUsages = com.intellij.util.SmartList<UsageInfo>()
|
||||
for (usage in usages) {
|
||||
if (usage.isAmbiguousImportUsage()) {
|
||||
ambiguousImportUsages += usage
|
||||
}
|
||||
else {
|
||||
simpleUsages += usage
|
||||
}
|
||||
}
|
||||
element.ambiguousImportUsages = ambiguousImportUsages
|
||||
|
||||
super.renameElement(element, newName, simpleUsages.toTypedArray(), listener)
|
||||
|
||||
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
|
||||
}
|
||||
|
||||
+4
-37
@@ -17,8 +17,9 @@
|
||||
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListener
|
||||
import com.intellij.refactoring.rename.RenameJavaMethodProcessor
|
||||
@@ -34,12 +35,8 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.refactoring.dropOverrideKeywordIfNecessary
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import java.util.*
|
||||
|
||||
class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
@@ -94,33 +91,6 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
}
|
||||
}
|
||||
|
||||
private var PsiElement.ambiguousImportUsages: List<UsageInfo>? by UserDataProperty(Key.create("AMBIGUOUS_IMPORT_USAGES"))
|
||||
|
||||
override fun getPostRenameCallback(element: PsiElement, newName: String?, elementListener: RefactoringElementListener?): Runnable? {
|
||||
if (newName == null) return null
|
||||
|
||||
return Runnable {
|
||||
element.ambiguousImportUsages?.forEach {
|
||||
val ref = it.reference as? PsiPolyVariantReference ?: return@forEach
|
||||
if (ref.multiResolve(false).isEmpty()) {
|
||||
ref.handleElementRename(newName)
|
||||
}
|
||||
else {
|
||||
ref.element?.getStrictParentOfType<KtImportDirective>()?.let { importDirective ->
|
||||
val fqName = importDirective.importedFqName!!
|
||||
val newFqName = fqName.parent().child(Name.identifier(newName))
|
||||
val importList = importDirective.parent as KtImportList
|
||||
if (importList.imports.none { it.importedFqName == newFqName }) {
|
||||
val newImportDirective = KtPsiFactory(element).createImportDirective(ImportPath(newFqName, false))
|
||||
importDirective.parent.addAfter(newImportDirective, importDirective)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
element.ambiguousImportUsages = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun renameElement(element: PsiElement, newName: String?, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
|
||||
val simpleUsages = ArrayList<UsageInfo>(usages.size)
|
||||
val ambiguousImportUsages = SmartList<UsageInfo>()
|
||||
@@ -130,10 +100,7 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
||||
continue
|
||||
}
|
||||
|
||||
val ref = usage.reference as? PsiPolyVariantReference ?: continue
|
||||
val refElement = ref.element
|
||||
if (refElement.parents.any { (it is KtImportDirective && !it.isAllUnder) || (it is PsiImportStaticStatement && !it.isOnDemand) }
|
||||
&& ref.multiResolve(false).size > 1) {
|
||||
if (usage.isAmbiguousImportUsage()) {
|
||||
ambiguousImportUsages += usage
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -16,18 +16,24 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiImportStaticStatement
|
||||
import com.intellij.psi.PsiPolyVariantReference
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListener
|
||||
import com.intellij.refactoring.rename.RenamePsiElementProcessor
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
||||
@@ -48,4 +54,38 @@ abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
||||
allRenames[element] = newName.quoteIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
protected var PsiElement.ambiguousImportUsages: List<UsageInfo>? by UserDataProperty(Key.create("AMBIGUOUS_IMPORT_USAGES"))
|
||||
|
||||
protected fun UsageInfo.isAmbiguousImportUsage(): Boolean {
|
||||
val ref = reference as? PsiPolyVariantReference ?: return false
|
||||
val refElement = ref.element
|
||||
return refElement.parents.any { (it is KtImportDirective && !it.isAllUnder) || (it is PsiImportStaticStatement && !it.isOnDemand) }
|
||||
&& ref.multiResolve(false).size > 1
|
||||
}
|
||||
|
||||
override fun getPostRenameCallback(element: PsiElement, newName: String?, elementListener: RefactoringElementListener?): Runnable? {
|
||||
if (newName == null) return null
|
||||
|
||||
return Runnable {
|
||||
element.ambiguousImportUsages?.forEach {
|
||||
val ref = it.reference as? PsiPolyVariantReference ?: return@forEach
|
||||
if (ref.multiResolve(false).isEmpty()) {
|
||||
ref.handleElementRename(newName)
|
||||
}
|
||||
else {
|
||||
ref.element?.getStrictParentOfType<KtImportDirective>()?.let { importDirective ->
|
||||
val fqName = importDirective.importedFqName!!
|
||||
val newFqName = fqName.parent().child(Name.identifier(newName))
|
||||
val importList = importDirective.parent as KtImportList
|
||||
if (importList.imports.none { it.importedFqName == newFqName }) {
|
||||
val newImportDirective = KtPsiFactory(element).createImportDirective(ImportPath(newFqName, false))
|
||||
importDirective.parent.addAfter(newImportDirective, importDirective)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
element.ambiguousImportUsages = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package lib
|
||||
|
||||
class Foo2
|
||||
|
||||
fun Foo(p: Int): Foo2 = Foo2()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package usage
|
||||
|
||||
import lib.Foo
|
||||
import lib.Foo2
|
||||
|
||||
fun test() {
|
||||
val v: Foo2 = Foo(1)
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "lib/lib.kt",
|
||||
"newName": "Foo2",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package lib
|
||||
|
||||
class /*rename*/Foo
|
||||
|
||||
fun Foo(p: Int): Foo = Foo()
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package usage
|
||||
|
||||
import lib.Foo
|
||||
|
||||
fun test() {
|
||||
val v: Foo = Foo(1)
|
||||
}
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package lib
|
||||
|
||||
class Foo
|
||||
|
||||
fun Foo2(p: Int): Foo = Foo()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package usage
|
||||
|
||||
import lib.Foo
|
||||
import lib.Foo2
|
||||
|
||||
fun test() {
|
||||
val v: Foo = Foo2(1)
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "lib/lib.kt",
|
||||
"newName": "Foo2",
|
||||
"withRuntime": "true"
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package lib
|
||||
|
||||
class Foo
|
||||
|
||||
fun /*rename*/Foo(p: Int): Foo = Foo()
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package usage
|
||||
|
||||
import lib.Foo
|
||||
|
||||
fun test() {
|
||||
val v: Foo = Foo(1)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,18 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
KotlinTestUtils.assertAllTestsPresentInSingleGeneratedClass(this.getClass(), new File("idea/testData/refactoring/rename"), Pattern.compile("^(.+)\\.test$"));
|
||||
}
|
||||
|
||||
@TestMetadata("ambiguousClassFunImportRenameClass/ambiguousClassFunImportRenameClass.test")
|
||||
public void testAmbiguousClassFunImportRenameClass_AmbiguousClassFunImportRenameClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/ambiguousClassFunImportRenameClass/ambiguousClassFunImportRenameClass.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ambiguousClassFunImportRenameFun/ambiguousClassFunImportRenameFun.test")
|
||||
public void testAmbiguousClassFunImportRenameFun_AmbiguousClassFunImportRenameFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/ambiguousClassFunImportRenameFun/ambiguousClassFunImportRenameFun.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("automaticRenamer/simple.test")
|
||||
public void testAutomaticRenamer_Simple() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamer/simple.test");
|
||||
|
||||
Reference in New Issue
Block a user