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
|
###### Issues fixed
|
||||||
- [`KT-6363`](https://youtrack.jetbrains.com/issue/KT-6363) Do not rename ambiguous references in import directives
|
- [`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-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-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
|
- [`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.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class RenameKotlinClassProcessor : RenameKotlinPsiProcessor() {
|
class RenameKotlinClassProcessor : RenameKotlinPsiProcessor() {
|
||||||
override fun canProcessElement(element: PsiElement): Boolean {
|
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?) {
|
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() }
|
usages.forEach { (it as? KtResolvableCollisionUsageInfo)?.apply() }
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-37
@@ -17,8 +17,9 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.rename
|
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||||
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.psi.search.SearchScope
|
import com.intellij.psi.search.SearchScope
|
||||||
import com.intellij.refactoring.listeners.RefactoringElementListener
|
import com.intellij.refactoring.listeners.RefactoringElementListener
|
||||||
import com.intellij.refactoring.rename.RenameJavaMethodProcessor
|
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.refactoring.dropOverrideKeywordIfNecessary
|
||||||
import org.jetbrains.kotlin.idea.references.KtReference
|
import org.jetbrains.kotlin.idea.references.KtReference
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
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.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
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?) {
|
override fun renameElement(element: PsiElement, newName: String?, usages: Array<UsageInfo>, listener: RefactoringElementListener?) {
|
||||||
val simpleUsages = ArrayList<UsageInfo>(usages.size)
|
val simpleUsages = ArrayList<UsageInfo>(usages.size)
|
||||||
val ambiguousImportUsages = SmartList<UsageInfo>()
|
val ambiguousImportUsages = SmartList<UsageInfo>()
|
||||||
@@ -130,10 +100,7 @@ class RenameKotlinFunctionProcessor : RenameKotlinPsiProcessor() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val ref = usage.reference as? PsiPolyVariantReference ?: continue
|
if (usage.isAmbiguousImportUsage()) {
|
||||||
val refElement = ref.element
|
|
||||||
if (refElement.parents.any { (it is KtImportDirective && !it.isAllUnder) || (it is PsiImportStaticStatement && !it.isOnDemand) }
|
|
||||||
&& ref.multiResolve(false).size > 1) {
|
|
||||||
ambiguousImportUsages += usage
|
ambiguousImportUsages += usage
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -16,18 +16,24 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.refactoring.rename
|
package org.jetbrains.kotlin.idea.refactoring.rename
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiImportStaticStatement
|
||||||
|
import com.intellij.psi.PsiPolyVariantReference
|
||||||
import com.intellij.psi.PsiReference
|
import com.intellij.psi.PsiReference
|
||||||
import com.intellij.psi.search.SearchScope
|
import com.intellij.psi.search.SearchScope
|
||||||
import com.intellij.psi.search.searches.MethodReferencesSearch
|
import com.intellij.psi.search.searches.MethodReferencesSearch
|
||||||
|
import com.intellij.refactoring.listeners.RefactoringElementListener
|
||||||
import com.intellij.refactoring.rename.RenamePsiElementProcessor
|
import com.intellij.refactoring.rename.RenamePsiElementProcessor
|
||||||
|
import com.intellij.usageView.UsageInfo
|
||||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
|
|
||||||
abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
||||||
@@ -48,4 +54,38 @@ abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
|
|||||||
allRenames[element] = newName.quoteIfNeeded()
|
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$"));
|
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")
|
@TestMetadata("automaticRenamer/simple.test")
|
||||||
public void testAutomaticRenamer_Simple() throws Exception {
|
public void testAutomaticRenamer_Simple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamer/simple.test");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/rename/automaticRenamer/simple.test");
|
||||||
|
|||||||
Reference in New Issue
Block a user