Ban import member intentions from import directives (KT-13710)

#KT-13710 Fixed
This commit is contained in:
Nikolay Krasko
2017-01-13 18:40:21 +03:00
parent ad72918ff9
commit ea7fac07c4
8 changed files with 47 additions and 16 deletions
@@ -347,6 +347,10 @@ fun KtSimpleNameExpression.isPackageDirectiveExpression(): Boolean {
return parent is KtPackageDirective || parent?.parent is KtPackageDirective
}
fun KtExpression.isInImportDirective(): Boolean {
return parents.takeWhile { it !is KtDeclaration && it !is KtBlockExpression }.any { it is KtImportDirective }
}
fun KtExpression.isLambdaOutsideParentheses(): Boolean {
val parent = parent
return when (parent) {
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.isInImportDirective
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
@@ -44,7 +45,9 @@ class ImportAllMembersIntention : SelfTargetingIntention<KtDotQualifiedExpressio
val target = target(element) ?: return false
val targetFqName = target.importableFqName ?: return false
val file = element.getContainingKtFile()
if (element.isInImportDirective()) return false
val file = element.containingKtFile
val project = file.project
val dummyFileText = (file.packageDirective?.text ?: "") + "\n" + (file.importList?.text ?: "")
val dummyFile = KtPsiFactory(project).createAnalyzableFile("Dummy.kt", dummyFileText, file)
@@ -59,9 +62,9 @@ class ImportAllMembersIntention : SelfTargetingIntention<KtDotQualifiedExpressio
val target = target(element)!!
val classFqName = target.importableFqName!!.parent()
ImportInsertHelper.getInstance(element.project).importDescriptor(element.getContainingKtFile(), target, forceAllUnderImport = true)
ImportInsertHelper.getInstance(element.project).importDescriptor(element.containingKtFile, target, forceAllUnderImport = true)
val qualifiedExpressions = element.getContainingKtFile().collectDescendantsOfType<KtDotQualifiedExpression> { qualifiedExpression ->
val qualifiedExpressions = element.containingKtFile.collectDescendantsOfType<KtDotQualifiedExpression> { qualifiedExpression ->
val qualifierName = qualifiedExpression.receiverExpression.getQualifiedElementSelector() as? KtNameReferenceExpression
qualifierName?.getReferencedNameAsName() == classFqName.shortName() && target(qualifiedExpression)?.importableFqName?.parent() == classFqName
}
@@ -18,21 +18,18 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.ImportDescriptorResult
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtUserType
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -44,6 +41,8 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
val qualifiedElement = element.getQualifiedElement()
if (qualifiedElement == element) return false
if (element.isInImportDirective()) return false
val fqName = targetFqName(qualifiedElement) ?: return false
text = "Add import for '${fqName.asString()}'"
@@ -55,7 +54,7 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
val targets = element.mainReference.resolveToDescriptors(bindingContext)
val fqName = targets.map { it.importableFqName!! }.single()
val file = element.getContainingKtFile()
val file = element.containingKtFile
val helper = ImportInsertHelper.getInstance(element.project)
if (helper.importDescriptor(file, targets.first()) == ImportDescriptorResult.FAIL) return
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.psi.psiUtil.isDotReceiver
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import java.util.Arrays
@@ -50,8 +47,6 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac
private fun isQualifierExpected(element: KtSimpleNameExpression) = element.isDotReceiver() || ((element.parent as? KtDotQualifiedExpression)?.isDotReceiver() ?: false)
private fun isInsideOfImport(element: KtSimpleNameExpression) = element.getNonStrictParentOfType<KtImportDirective>() != null
override fun getPossibleClassKinds(element: KtSimpleNameExpression, diagnostic: Diagnostic): List<ClassKind> {
fun isEnum(element: PsiElement): Boolean {
return when (element) {
@@ -120,7 +115,7 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac
val fullCallExpr = getFullCallExpression(element) ?: return null
if (isInsideOfImport(element) || isQualifierExpected(element)) {
if (element.isInImportDirective() || isQualifierExpected(element)) {
val receiverSelector = (fullCallExpr as? KtQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? KtReferenceExpression
val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] }
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
import javax.swing.<caret>SwingConstants.CENTER
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
import javax.swing.SwingConstants.<caret>CENTER
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
import javax.swing.<caret>SwingConstants.CENTER
@@ -7739,6 +7739,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("ImportAllMembersInImport.kt")
public void testImportAllMembersInImport() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/ImportAllMembersInImport.kt");
doTest(fileName);
}
@TestMetadata("NotFromCompanionObject.kt")
public void testNotFromCompanionObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt");
@@ -7802,6 +7808,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("ImportMemberInImport.kt")
public void testImportMemberInImport() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importMember/ImportMemberInImport.kt");
doTest(fileName);
}
@TestMetadata("ImportMemberInMiddleOfImport.kt")
public void testImportMemberInMiddleOfImport() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importMember/ImportMemberInMiddleOfImport.kt");
doTest(fileName);
}
@TestMetadata("NestedClass1.kt")
public void testNestedClass1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importMember/NestedClass1.kt");