Add import for member: don't suggest if a class with the same name has been imported

#KT-38492 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-05-02 12:01:21 +09:00
committed by Yan Zhulanow
parent 329f0227ec
commit 45d60baeb0
4 changed files with 67 additions and 6 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
@@ -16,7 +17,6 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors
import org.jetbrains.kotlin.idea.util.ImportDescriptorResult
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
@@ -33,7 +33,14 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
if (element.isInImportDirective()) return false
val fqName = targetFqName(qualifiedExpression) ?: return false
val target = target(qualifiedExpression) ?: return false
val fqName = target.importableFqName ?: return false
val file = element.containingKtFile
val project = file.project
val dummyFile = KtPsiFactory(project).createAnalyzableFile("Dummy.kt", file.text, file)
val helper = ImportInsertHelper.getInstance(project)
if (helper.importDescriptor(dummyFile, target) == ImportDescriptorResult.FAIL) return false
setTextGetter(KotlinBundle.lazyMessage("add.import.for.0", fqName.asString()))
return true
@@ -57,18 +64,18 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
val qualifiedExpressions = file.collectDescendantsOfType<KtDotQualifiedExpression> { qualifiedExpression ->
val selector = qualifiedExpression.getQualifiedElementSelector() as? KtNameReferenceExpression
selector?.getReferencedNameAsName() == fqName.shortName() && targetFqName(qualifiedExpression) == fqName
selector?.getReferencedNameAsName() == fqName.shortName() && target(qualifiedExpression)?.importableFqName == fqName
}
val userTypes = file.collectDescendantsOfType<KtUserType> { userType ->
val selector = userType.getQualifiedElementSelector() as? KtNameReferenceExpression
selector?.getReferencedNameAsName() == fqName.shortName() && targetFqName(userType) == fqName
selector?.getReferencedNameAsName() == fqName.shortName() && target(userType)?.importableFqName == fqName
}
//TODO: not deep
ShortenReferences.DEFAULT.process(qualifiedExpressions + userTypes)
}
private fun targetFqName(qualifiedElement: KtElement): FqName? {
private fun target(qualifiedElement: KtElement): DeclarationDescriptor? {
val nameExpression = qualifiedElement.getQualifiedElementSelector() as? KtNameReferenceExpression ?: return null
val receiver = nameExpression.getReceiverExpression() ?: return null
val bindingContext = qualifiedElement.analyze(BodyResolveMode.PARTIAL)
@@ -77,6 +84,6 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
val targets = nameExpression.mainReference.resolveToDescriptors(bindingContext)
if (targets.isEmpty()) return null
if (!targets.all { it.canBeAddedToImport() }) return null
return targets.map { it.importableFqName }.singleOrNull()
return targets.singleOrNull()
}
}
@@ -0,0 +1,22 @@
// IS_APPLICABLE: false
package foo.bar
import foo.bar.A.SUCCESS
fun test() {
foo(SUCCESS)
bar(B.SUCCESS<caret>)
}
fun foo(a: A) {}
fun bar(b: B) {}
enum class A {
SUCCESS, ERROR
}
enum class B {
SUCCESS, ERROR
}
@@ -0,0 +1,22 @@
// IS_APPLICABLE: false
package foo.bar
import foo.bar.A.*
fun test() {
foo(SUCCESS)
bar(B.SUCCESS<caret>)
}
fun foo(a: A) {}
fun bar(b: B) {}
enum class A {
SUCCESS, ERROR
}
enum class B {
SUCCESS, ERROR
}
@@ -8973,6 +8973,16 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/importMember"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
}
@TestMetadata("AlreadyImportedSameNameClass.kt")
public void testAlreadyImportedSameNameClass() throws Exception {
runTest("idea/testData/intentions/importMember/AlreadyImportedSameNameClass.kt");
}
@TestMetadata("AlreadyImportedSameNameClass2.kt")
public void testAlreadyImportedSameNameClass2() throws Exception {
runTest("idea/testData/intentions/importMember/AlreadyImportedSameNameClass2.kt");
}
@TestMetadata("ClassCallChain.kt")
public void testClassCallChain() throws Exception {
runTest("idea/testData/intentions/importMember/ClassCallChain.kt");