Ban import member intentions from import directives (KT-13710)
#KT-13710 Fixed
This commit is contained in:
@@ -347,6 +347,10 @@ fun KtSimpleNameExpression.isPackageDirectiveExpression(): Boolean {
|
|||||||
return parent is KtPackageDirective || parent?.parent is KtPackageDirective
|
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 {
|
fun KtExpression.isLambdaOutsideParentheses(): Boolean {
|
||||||
val parent = parent
|
val parent = parent
|
||||||
return when (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.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
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.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
|
||||||
@@ -44,7 +45,9 @@ class ImportAllMembersIntention : SelfTargetingIntention<KtDotQualifiedExpressio
|
|||||||
val target = target(element) ?: return false
|
val target = target(element) ?: return false
|
||||||
val targetFqName = target.importableFqName ?: 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 project = file.project
|
||||||
val dummyFileText = (file.packageDirective?.text ?: "") + "\n" + (file.importList?.text ?: "")
|
val dummyFileText = (file.packageDirective?.text ?: "") + "\n" + (file.importList?.text ?: "")
|
||||||
val dummyFile = KtPsiFactory(project).createAnalyzableFile("Dummy.kt", dummyFileText, file)
|
val dummyFile = KtPsiFactory(project).createAnalyzableFile("Dummy.kt", dummyFileText, file)
|
||||||
@@ -59,9 +62,9 @@ class ImportAllMembersIntention : SelfTargetingIntention<KtDotQualifiedExpressio
|
|||||||
val target = target(element)!!
|
val target = target(element)!!
|
||||||
val classFqName = target.importableFqName!!.parent()
|
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
|
val qualifierName = qualifiedExpression.receiverExpression.getQualifiedElementSelector() as? KtNameReferenceExpression
|
||||||
qualifierName?.getReferencedNameAsName() == classFqName.shortName() && target(qualifiedExpression)?.importableFqName?.parent() == classFqName
|
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 com.intellij.openapi.editor.Editor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
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.canBeReferencedViaImport
|
||||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.util.ImportDescriptorResult
|
import org.jetbrains.kotlin.idea.util.ImportDescriptorResult
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||||
import org.jetbrains.kotlin.psi.KtUserType
|
import org.jetbrains.kotlin.psi.KtUserType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
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.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
|
||||||
@@ -44,6 +41,8 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
|
|||||||
val qualifiedElement = element.getQualifiedElement()
|
val qualifiedElement = element.getQualifiedElement()
|
||||||
if (qualifiedElement == element) return false
|
if (qualifiedElement == element) return false
|
||||||
|
|
||||||
|
if (element.isInImportDirective()) return false
|
||||||
|
|
||||||
val fqName = targetFqName(qualifiedElement) ?: return false
|
val fqName = targetFqName(qualifiedElement) ?: return false
|
||||||
|
|
||||||
text = "Add import for '${fqName.asString()}'"
|
text = "Add import for '${fqName.asString()}'"
|
||||||
@@ -55,7 +54,7 @@ class ImportMemberIntention : SelfTargetingOffsetIndependentIntention<KtNameRefe
|
|||||||
val targets = element.mainReference.resolveToDescriptors(bindingContext)
|
val targets = element.mainReference.resolveToDescriptors(bindingContext)
|
||||||
val fqName = targets.map { it.importableFqName!! }.single()
|
val fqName = targets.map { it.importableFqName!! }.single()
|
||||||
|
|
||||||
val file = element.getContainingKtFile()
|
val file = element.containingKtFile
|
||||||
val helper = ImportInsertHelper.getInstance(element.project)
|
val helper = ImportInsertHelper.getInstance(element.project)
|
||||||
if (helper.importDescriptor(file, targets.first()) == ImportDescriptorResult.FAIL) return
|
if (helper.importDescriptor(file, targets.first()) == ImportDescriptorResult.FAIL) return
|
||||||
|
|
||||||
|
|||||||
+2
-7
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
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.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||||
import java.util.Arrays
|
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 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> {
|
override fun getPossibleClassKinds(element: KtSimpleNameExpression, diagnostic: Diagnostic): List<ClassKind> {
|
||||||
fun isEnum(element: PsiElement): Boolean {
|
fun isEnum(element: PsiElement): Boolean {
|
||||||
return when (element) {
|
return when (element) {
|
||||||
@@ -120,7 +115,7 @@ object CreateClassFromReferenceExpressionActionFactory : CreateClassFromUsageFac
|
|||||||
|
|
||||||
val fullCallExpr = getFullCallExpression(element) ?: return null
|
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 receiverSelector = (fullCallExpr as? KtQualifiedExpression)?.receiverExpression?.getQualifiedElementSelector() as? KtReferenceExpression
|
||||||
val qualifierDescriptor = receiverSelector?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
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);
|
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")
|
@TestMetadata("NotFromCompanionObject.kt")
|
||||||
public void testNotFromCompanionObject() throws Exception {
|
public void testNotFromCompanionObject() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt");
|
||||||
@@ -7802,6 +7808,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("NestedClass1.kt")
|
||||||
public void testNestedClass1() throws Exception {
|
public void testNestedClass1() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importMember/NestedClass1.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importMember/NestedClass1.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user