Fix "Introduce import alias" on extensions
#KT-30214 Fixed
This commit is contained in:
+20
-9
@@ -40,8 +40,10 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||||
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
|
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
|
||||||
@@ -58,12 +60,14 @@ object KotlinIntroduceImportAliasHandler : RefactoringActionHandler {
|
|||||||
val file = element.containingKtFile
|
val file = element.containingKtFile
|
||||||
val declarationDescriptors = file.resolveImportReference(fqName)
|
val declarationDescriptors = file.resolveImportReference(fqName)
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
val usages = declarationDescriptors.flatMap { descriptor ->
|
||||||
val usages = declarationDescriptors
|
val isExtension = descriptor.isExtension
|
||||||
.flatMap { findPsiElements(project, file, it) }
|
findPsiElements(project, file, descriptor).flatMap {
|
||||||
.flatMap {
|
ReferencesSearch.search(it, file.useScope)
|
||||||
ReferencesSearch.search(it, file.useScope).findAll() as List<KtSimpleNameReference>
|
.findAll()
|
||||||
|
.map { reference -> UsageContext(reference as KtSimpleNameReference, isExtension = isExtension) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val suggestedName = suggestedName(element.mainReference.value, file.getResolutionScope())
|
val suggestedName = suggestedName(element.mainReference.value, file.getResolutionScope())
|
||||||
ImportInsertHelperImpl.addImport(project, file, fqName, false, Name.identifier(suggestedName))
|
ImportInsertHelperImpl.addImport(project, file, fqName, false, Name.identifier(suggestedName))
|
||||||
@@ -87,6 +91,8 @@ object KotlinIntroduceImportAliasHandler : RefactoringActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class UsageContext(val reference: KtSimpleNameReference, val isExtension: Boolean)
|
||||||
|
|
||||||
private fun cleanImport(file: KtFile, fqName: FqName) {
|
private fun cleanImport(file: KtFile, fqName: FqName) {
|
||||||
file.importDirectives.find { it.alias == null && fqName == it.importedFqName }?.delete()
|
file.importDirectives.find { it.alias == null && fqName == it.importedFqName }?.delete()
|
||||||
}
|
}
|
||||||
@@ -125,11 +131,16 @@ private fun invokeRename(project: Project, editor: Editor, file: KtFile) {
|
|||||||
KotlinRenameDispatcherHandler().invoke(project, editor, file, dataContext)
|
KotlinRenameDispatcherHandler().invoke(project, editor, file, dataContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replaceUsages(usages: List<KtSimpleNameReference>, newName: String) {
|
private fun replaceUsages(usages: List<UsageContext>, newName: String) {
|
||||||
usages.filter { !it.isImportUsage() }
|
usages.filter { !it.reference.isImportUsage() }
|
||||||
.reversed() // case: inner element
|
.reversed() // case: inner element
|
||||||
.map {
|
.forEach {
|
||||||
val newExpression = it.handleElementRename(newName) as KtNameReferenceExpression
|
val newExpression = it.reference.handleElementRename(newName) as KtNameReferenceExpression
|
||||||
|
if (it.isExtension) {
|
||||||
|
newExpression.getQualifiedElementSelector()?.replace(newExpression)
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
val qualifiedElement = newExpression.getQualifiedElement()
|
val qualifiedElement = newExpression.getQualifiedElement()
|
||||||
if (qualifiedElement != newExpression) {
|
if (qualifiedElement != newExpression) {
|
||||||
val parent = newExpression.parent
|
val parent = newExpression.parent
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package my.sample
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun A.check() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val a = A()
|
||||||
|
a.check<caret>()
|
||||||
|
A().check()
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package my.sample
|
||||||
|
|
||||||
|
import my.sample.check as check1
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun A.check() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val a = A()
|
||||||
|
a.check1()
|
||||||
|
A().check1()
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
package my.sample
|
||||||
|
|
||||||
|
val Any.foo: Any get() = this
|
||||||
|
val Any.bar: Any get() = this
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
1.foo.foo.bar<caret>.foo.bar.toString()
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
package my.sample
|
||||||
|
|
||||||
|
import my.sample.bar as bar1
|
||||||
|
|
||||||
|
val Any.foo: Any get() = this
|
||||||
|
val Any.bar: Any get() = this
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
1.foo.foo.bar1.foo.bar1.toString()
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
package my.sample
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
0.let { true }.let<caret> { println(it) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
package my.sample
|
||||||
|
|
||||||
|
import kotlin.let as let1
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
0.let1 { true }.let1 { println(it) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package my.sample
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun A.check() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
(my.sample.A::check<caret>)(A())
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package my.sample
|
||||||
|
|
||||||
|
import my.sample.check as check1
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun A.check() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
(my.sample.A::check1)(A())
|
||||||
|
}
|
||||||
@@ -10074,6 +10074,26 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
public void testVariable() throws Exception {
|
public void testVariable() throws Exception {
|
||||||
runTest("idea/testData/intentions/introduceImportAlias/variable.kt");
|
runTest("idea/testData/intentions/introduceImportAlias/variable.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withReceiver.kt")
|
||||||
|
public void testWithReceiver() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/introduceImportAlias/withReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withReceiver2.kt")
|
||||||
|
public void testWithReceiver2() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/introduceImportAlias/withReceiver2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withReceiver3.kt")
|
||||||
|
public void testWithReceiver3() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/introduceImportAlias/withReceiver3.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("withReceiver4.kt")
|
||||||
|
public void testWithReceiver4() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/introduceImportAlias/withReceiver4.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/intentions/introduceVariable")
|
@TestMetadata("idea/testData/intentions/introduceVariable")
|
||||||
|
|||||||
Reference in New Issue
Block a user