From fe7f79428d2df96da3cefdfc60b6fdac4117a093 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 10 Nov 2015 13:25:16 +0300 Subject: [PATCH] Intention to import members with '*' --- .../kotlin/idea/util/ImportInsertHelper.kt | 12 +-- .../kotlin/idea/util/ShortenReferences.kt | 21 +++-- .../after.kt.template | 7 ++ .../before.kt.template | 6 ++ .../description.html | 5 ++ idea/src/META-INF/plugin.xml | 5 ++ .../intentions/ImportAllMembersIntention.kt | 81 +++++++++++++++++++ .../idea/util/ImportInsertHelperImpl.kt | 69 ++++++++++++---- .../intentions/importAllMembers/.intention | 1 + .../importAllMembers/AlreadyImported.kt | 17 ++++ .../importAllMembers/AlreadyImported.kt.after | 17 ++++ .../AlreadyImportedWithStar.kt | 17 ++++ .../AlreadyImportedWithStar.kt.after | 17 ++++ .../importAllMembers/AmbiguousCalls.kt | 17 ++++ .../importAllMembers/AmbiguousCalls.kt.after | 18 +++++ .../importAllMembers/EnumMembers.kt | 11 +++ .../importAllMembers/EnumMembers.kt.after | 13 +++ .../EnumMembersValues.kt.todo | 4 + .../NotFromCompanionObject.kt | 8 ++ .../importAllMembers/NotFromObject.kt | 8 ++ .../importAllMembers/QualifiedName.kt | 6 ++ .../importAllMembers/QualifiedName.kt.after | 8 ++ .../importAllMembers/QualifiedName2.kt | 6 ++ .../importAllMembers/QualifiedName2.kt.after | 8 ++ .../importAllMembers/RemoveSingleImports.kt | 17 ++++ .../RemoveSingleImports.kt.after | 17 ++++ .../importAllMembers/StaticJavaMembers.kt | 19 +++++ .../StaticJavaMembers.kt.after | 20 +++++ .../importAllMembers/UnresolvedMember.kt | 7 ++ .../intentions/IntentionTestGenerated.java | 75 +++++++++++++++++ 30 files changed, 510 insertions(+), 27 deletions(-) create mode 100644 idea/resources/intentionDescriptions/ImportAllMembersIntention/after.kt.template create mode 100644 idea/resources/intentionDescriptions/ImportAllMembersIntention/before.kt.template create mode 100644 idea/resources/intentionDescriptions/ImportAllMembersIntention/description.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/intentions/ImportAllMembersIntention.kt create mode 100644 idea/testData/intentions/importAllMembers/.intention create mode 100644 idea/testData/intentions/importAllMembers/AlreadyImported.kt create mode 100644 idea/testData/intentions/importAllMembers/AlreadyImported.kt.after create mode 100644 idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt create mode 100644 idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt.after create mode 100644 idea/testData/intentions/importAllMembers/AmbiguousCalls.kt create mode 100644 idea/testData/intentions/importAllMembers/AmbiguousCalls.kt.after create mode 100644 idea/testData/intentions/importAllMembers/EnumMembers.kt create mode 100644 idea/testData/intentions/importAllMembers/EnumMembers.kt.after create mode 100644 idea/testData/intentions/importAllMembers/EnumMembersValues.kt.todo create mode 100644 idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt create mode 100644 idea/testData/intentions/importAllMembers/NotFromObject.kt create mode 100644 idea/testData/intentions/importAllMembers/QualifiedName.kt create mode 100644 idea/testData/intentions/importAllMembers/QualifiedName.kt.after create mode 100644 idea/testData/intentions/importAllMembers/QualifiedName2.kt create mode 100644 idea/testData/intentions/importAllMembers/QualifiedName2.kt.after create mode 100644 idea/testData/intentions/importAllMembers/RemoveSingleImports.kt create mode 100644 idea/testData/intentions/importAllMembers/RemoveSingleImports.kt.after create mode 100644 idea/testData/intentions/importAllMembers/StaticJavaMembers.kt create mode 100644 idea/testData/intentions/importAllMembers/StaticJavaMembers.kt.after create mode 100644 idea/testData/intentions/importAllMembers/UnresolvedMember.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ImportInsertHelper.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ImportInsertHelper.kt index dd7fc1fca0f..4a86f802837 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ImportInsertHelper.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ImportInsertHelper.kt @@ -23,21 +23,21 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.ImportPath import java.util.* -public abstract class ImportInsertHelper { +abstract class ImportInsertHelper { /*TODO: implementation is not quite correct*/ - public abstract fun isImportedWithDefault(importPath: ImportPath, contextFile: KtFile): Boolean + abstract fun isImportedWithDefault(importPath: ImportPath, contextFile: KtFile): Boolean - public abstract fun mayImportOnShortenReferences(descriptor: DeclarationDescriptor): Boolean + abstract fun mayImportOnShortenReferences(descriptor: DeclarationDescriptor): Boolean - public abstract val importSortComparator: Comparator + abstract val importSortComparator: Comparator - public enum class ImportDescriptorResult { + enum class ImportDescriptorResult { FAIL, IMPORT_ADDED, ALREADY_IMPORTED } - public abstract fun importDescriptor(file: KtFile, descriptor: DeclarationDescriptor): ImportDescriptorResult + abstract fun importDescriptor(file: KtFile, descriptor: DeclarationDescriptor, forceAllUnderImport: Boolean = false): ImportDescriptorResult companion object { @JvmStatic diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt index f960417ef2f..703655fe2b0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ShortenReferences.kt @@ -207,11 +207,11 @@ public class ShortenReferences(val options: (KtElement) -> Options = { Options.D protected fun analyze(element: KtElement) = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL) - protected fun processQualifiedElement(element: T, target: DeclarationDescriptor, canShortenNow: Boolean) { + protected fun processQualifiedElement(element: T, target: DeclarationDescriptor?, canShortenNow: Boolean) { if (canShortenNow) { addElementToShorten(element) } - else if (target !in failedToImportDescriptors && mayImport(target, file)) { + else if (target != null && target !in failedToImportDescriptors && mayImport(target, file)) { descriptorsToImport.add(target) } else { @@ -340,13 +340,14 @@ public class ShortenReferences(val options: (KtElement) -> Options = { Options.D val selector = qualifiedExpression.getSelectorExpression() ?: return false val callee = selector.getCalleeExpressionIfAny() as? KtReferenceExpression ?: return false - val target = callee.targets(bindingContext).singleOrNull() ?: return false + val targets = callee.targets(bindingContext) + if (targets.isEmpty()) return false val scope = qualifiedExpression.getResolutionScope(bindingContext, resolutionFacade) val selectorCopy = selector.copy() as KtReferenceExpression val newContext = selectorCopy.analyzeInContext(scope, selector) val targetsWhenShort = (selectorCopy.getCalleeExpressionIfAny() as KtReferenceExpression).targets(newContext) - val targetsMatch = targetsWhenShort.singleOrNull()?.asString() == target.asString() + val targetsMatch = targetsMatch(targets, targetsWhenShort) if (receiver is KtThisExpression) { if (!targetsMatch) return false @@ -368,10 +369,20 @@ public class ShortenReferences(val options: (KtElement) -> Options = { Options.D return false } - processQualifiedElement(qualifiedExpression, target, targetsMatch) + processQualifiedElement(qualifiedExpression, targets.singleOrNull(), targetsMatch) return true } + private fun targetsMatch(targets1: Collection, targets2: Collection): Boolean { + if (targets1.size != targets2.size) return false + if (targets1.size == 1) { + return targets1.single().asString() == targets2.single().asString() + } + else { + return targets1.map { it.asString() }.toSet() == targets2.map { it.asString() }.toSet() + } + } + override fun shortenElement(element: KtDotQualifiedExpression): KtElement { return element.replace(element.getSelectorExpression()!!) as KtElement } diff --git a/idea/resources/intentionDescriptions/ImportAllMembersIntention/after.kt.template b/idea/resources/intentionDescriptions/ImportAllMembersIntention/after.kt.template new file mode 100644 index 00000000000..8c1b2d2555f --- /dev/null +++ b/idea/resources/intentionDescriptions/ImportAllMembersIntention/after.kt.template @@ -0,0 +1,7 @@ +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.* + +fun foo() { + SwingUtilities.invokeLater { } + SwingUtilities.invokeAndWait() +} diff --git a/idea/resources/intentionDescriptions/ImportAllMembersIntention/before.kt.template b/idea/resources/intentionDescriptions/ImportAllMembersIntention/before.kt.template new file mode 100644 index 00000000000..6fa7ea870c7 --- /dev/null +++ b/idea/resources/intentionDescriptions/ImportAllMembersIntention/before.kt.template @@ -0,0 +1,6 @@ +import javax.swing.SwingUtilities + +fun foo() { + SwingUtilities.invokeLater { } + SwingUtilities.invokeAndWait() +} diff --git a/idea/resources/intentionDescriptions/ImportAllMembersIntention/description.html b/idea/resources/intentionDescriptions/ImportAllMembersIntention/description.html new file mode 100644 index 00000000000..ee526aef7d0 --- /dev/null +++ b/idea/resources/intentionDescriptions/ImportAllMembersIntention/description.html @@ -0,0 +1,5 @@ + + +This intention converts selected qualified reference into simple reference and adds import for corresponding class. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 826c7e74452..0fd8395d19c 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -632,6 +632,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.ImportAllMembersIntention + Kotlin + + org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention Kotlin diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ImportAllMembersIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ImportAllMembersIntention.kt new file mode 100644 index 00000000000..bf219d62f4d --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ImportAllMembersIntention.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.intentions + +import com.intellij.openapi.editor.Editor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.conversion.copy.range +import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.util.ImportInsertHelper +import org.jetbrains.kotlin.idea.util.ShortenReferences +import org.jetbrains.kotlin.psi.KtDotQualifiedExpression +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.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.scopes.receivers.ClassifierQualifier + +class ImportAllMembersIntention : SelfTargetingIntention( + KtDotQualifiedExpression::class.java, + "Import members with '*'" +){ + override fun isApplicableTo(element: KtDotQualifiedExpression, caretOffset: Int): Boolean { + if (!element.receiverExpression.range.containsOffset(caretOffset)) return false + + val target = target(element) ?: return false + val targetFqName = target.importableFqName ?: return false + + val file = element.getContainingKtFile() + val project = file.project + val dummyFileText = (file.packageDirective?.text ?: "") + "\n" + (file.importList?.text ?: "") + val dummyFile = KtPsiFactory(project).createAnalyzableFile("Dummy.kt", dummyFileText, file) + val helper = ImportInsertHelper.getInstance(project) + if (helper.importDescriptor(dummyFile, target, forceAllUnderImport = true) == ImportInsertHelper.ImportDescriptorResult.FAIL) return false + + text = "Import members from '${targetFqName.parent().asString()}'" + return true + } + + override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) { + val target = target(element)!! + val classFqName = target.importableFqName!!.parent() + + ImportInsertHelper.getInstance(element.project).importDescriptor(element.getContainingKtFile(), target, forceAllUnderImport = true) + + val qualifiedExpressions = element.getContainingKtFile().collectDescendantsOfType { qualifiedExpression -> + val qualifierName = qualifiedExpression.receiverExpression.getQualifiedElementSelector() as? KtNameReferenceExpression + ?: return@collectDescendantsOfType false + qualifierName.getReferencedNameAsName() == classFqName.shortName() && target(qualifiedExpression)?.importableFqName?.parent() == classFqName + } + + //TODO: not deep + ShortenReferences.DEFAULT.process(qualifiedExpressions) + } + + private fun target(expression: KtDotQualifiedExpression): DeclarationDescriptor? { + val bindingContext = expression.analyze(BodyResolveMode.PARTIAL) + val qualifier = bindingContext[BindingContext.QUALIFIER, expression.receiverExpression] as? ClassifierQualifier ?: return null + if (qualifier.descriptor !is ClassDescriptor) return null + val selector = expression.getQualifiedElementSelector() as? KtNameReferenceExpression ?: return null + return selector.mainReference.resolveToDescriptors(bindingContext).firstOrNull() + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt b/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt index 97c19aedf0d..cef5898e600 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt @@ -21,7 +21,6 @@ import com.intellij.psi.PsiElement import com.intellij.psi.impl.PsiModificationTrackerImpl import com.intellij.psi.util.PsiModificationTracker import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.util.getFileResolutionScope import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings import org.jetbrains.kotlin.idea.core.targetDescriptors @@ -30,6 +29,7 @@ import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.project.platform import org.jetbrains.kotlin.idea.refactoring.fqName.isImported import org.jetbrains.kotlin.idea.util.ImportInsertHelper +import org.jetbrains.kotlin.idea.util.getFileResolutionScope import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* @@ -38,8 +38,8 @@ import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier @@ -99,8 +99,15 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert } } - override fun importDescriptor(file: KtFile, descriptor: DeclarationDescriptor) - = Importer(file).importDescriptor(descriptor) + override fun importDescriptor(file: KtFile, descriptor: DeclarationDescriptor, forceAllUnderImport: Boolean): ImportDescriptorResult { + val importer = Importer(file) + if (forceAllUnderImport) { + return importer.importDescriptorWithStarImport(descriptor) + } + else { + return importer.importDescriptor(descriptor) + } + } private inner class Importer( private val file: KtFile @@ -135,10 +142,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert val targetFqName = target.importableFqName ?: return ImportDescriptorResult.FAIL if (isAlreadyImported(target, topLevelScope, targetFqName)) return ImportDescriptorResult.ALREADY_IMPORTED - val imports = if (file is KtCodeFragment) - file.importsAsImportList()?.getImports() ?: listOf() - else - file.getImportDirectives() + val imports = getImports(file) if (imports.any { !it.isAllUnder && it.importPath?.fqnPart() == targetFqName }) { return ImportDescriptorResult.FAIL @@ -159,9 +163,9 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert } val fqName = target.importableFqName!! - val packageFqName = fqName.parent() + val containerFqName = fqName.parent() - val tryStarImport = shouldTryStarImport(packageFqName, target, imports) + val tryStarImport = shouldTryStarImport(containerFqName, target, imports) && when (target) { // this check does not give a guarantee that import with * will import the class - for example, // there can be classes with conflicting name in more than one import with * @@ -178,14 +182,31 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert return addExplicitImport(target) } - private fun shouldTryStarImport(containerFqName: FqName, target: DeclarationDescriptor, imports: Collection): Boolean { - if (containerFqName.isRoot) return false + fun importDescriptorWithStarImport(descriptor: DeclarationDescriptor): ImportDescriptorResult { + val target = descriptor.getImportableDescriptor() - val container = target.containingDeclaration - if (container is ClassDescriptor && container.kind == ClassKind.OBJECT) return false // cannot import with '*' from object + val fqName = target.importableFqName ?: return ImportDescriptorResult.FAIL + val containerFqName = fqName.parent() + val imports = getImports(file) val starImportPath = ImportPath(containerFqName, true) - if (imports.any { it.getImportPath() == starImportPath }) return false + if (imports.any { it.importPath == starImportPath }) { + return if (isAlreadyImported(target, resolutionFacade.getFileResolutionScope(file), fqName)) + ImportDescriptorResult.ALREADY_IMPORTED + else + ImportDescriptorResult.FAIL + } + + if (!canImportWithStar(containerFqName, target)) return ImportDescriptorResult.FAIL + + return addStarImport(target) + } + + private fun shouldTryStarImport(containerFqName: FqName, target: DeclarationDescriptor, imports: Collection): Boolean { + if (!canImportWithStar(containerFqName, target)) return false + + val starImportPath = ImportPath(containerFqName, true) + if (imports.any { it.importPath == starImportPath }) return false if (containerFqName.asString() in codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS) return true @@ -193,13 +214,22 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert val path = it.getImportPath() path != null && !path.isAllUnder() && !path.hasAlias() && path.fqnPart().parent() == containerFqName } - val nameCountToUseStar = if (container is ClassDescriptor) + val nameCountToUseStar = if (target.containingDeclaration is ClassDescriptor) codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS else codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT return importsFromPackage + 1 >= nameCountToUseStar } + private fun canImportWithStar(containerFqName: FqName, target: DeclarationDescriptor): Boolean { + if (containerFqName.isRoot) return false + + val container = target.containingDeclaration + if (container is ClassDescriptor && container.kind == ClassKind.OBJECT) return false // cannot import with '*' from object + + return true + } + private fun addStarImport(target: DeclarationDescriptor): ImportDescriptorResult { val targetFqName = target.importableFqName!! val parentFqName = targetFqName.parent() @@ -397,4 +427,11 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert } } } + + private fun getImports(file: KtFile): List { + return if (file is KtCodeFragment) + file.importsAsImportList()?.imports ?: listOf() + else + file.importDirectives + } } diff --git a/idea/testData/intentions/importAllMembers/.intention b/idea/testData/intentions/importAllMembers/.intention new file mode 100644 index 00000000000..98dac6ca10f --- /dev/null +++ b/idea/testData/intentions/importAllMembers/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.ImportAllMembersIntention diff --git a/idea/testData/intentions/importAllMembers/AlreadyImported.kt b/idea/testData/intentions/importAllMembers/AlreadyImported.kt new file mode 100644 index 00000000000..cc4e80f201d --- /dev/null +++ b/idea/testData/intentions/importAllMembers/AlreadyImported.kt @@ -0,0 +1,17 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.invokeLater + +fun foo() { + SwingUtilities.invokeLater { } + + val bottom = SwingUtilities.BOTTOM + + SwingUtilities.invokeAndWait { + SwingUtilities.invokeLater { } + } + + val horizontal = javax.swing.SwingUtilities.HORIZONTAL +} diff --git a/idea/testData/intentions/importAllMembers/AlreadyImported.kt.after b/idea/testData/intentions/importAllMembers/AlreadyImported.kt.after new file mode 100644 index 00000000000..4c0d0c50194 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/AlreadyImported.kt.after @@ -0,0 +1,17 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.* + +fun foo() { + invokeLater { } + + val bottom = BOTTOM + + invokeAndWait { + invokeLater { } + } + + val horizontal = HORIZONTAL +} diff --git a/idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt b/idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt new file mode 100644 index 00000000000..5eb10651070 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt @@ -0,0 +1,17 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.* + +fun foo() { + SwingUtilities.invokeLater { } + + val bottom = SwingUtilities.BOTTOM + + SwingUtilities.invokeAndWait { + SwingUtilities.invokeLater { } + } + + val horizontal = javax.swing.SwingUtilities.HORIZONTAL +} diff --git a/idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt.after b/idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt.after new file mode 100644 index 00000000000..4c0d0c50194 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt.after @@ -0,0 +1,17 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.* + +fun foo() { + invokeLater { } + + val bottom = BOTTOM + + invokeAndWait { + invokeLater { } + } + + val horizontal = HORIZONTAL +} diff --git a/idea/testData/intentions/importAllMembers/AmbiguousCalls.kt b/idea/testData/intentions/importAllMembers/AmbiguousCalls.kt new file mode 100644 index 00000000000..92117bef95e --- /dev/null +++ b/idea/testData/intentions/importAllMembers/AmbiguousCalls.kt @@ -0,0 +1,17 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME +// ERROR: None of the following functions can be called with the arguments supplied:
public open fun convertPoint(p0: java.awt.Component!, p1: [ERROR : Unresolved java classifier: Point]!, p2: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities
public open fun convertPoint(p0: java.awt.Component!, p1: kotlin.Int, p2: kotlin.Int, p3: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities +// ERROR: None of the following functions can be called with the arguments supplied:
public open fun convertPoint(p0: java.awt.Component!, p1: [ERROR : Unresolved java classifier: Point]!, p2: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities
public open fun convertPoint(p0: java.awt.Component!, p1: kotlin.Int, p2: kotlin.Int, p3: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities +// ERROR: Unresolved reference: unresolved + +import javax.swing.SwingUtilities + +fun foo() { + SwingUtilities.convertPoint() + + val bottom = SwingUtilities.BOTTOM + + SwingUtilities.convertPoint() + + SwingUtilities.unresolved +} diff --git a/idea/testData/intentions/importAllMembers/AmbiguousCalls.kt.after b/idea/testData/intentions/importAllMembers/AmbiguousCalls.kt.after new file mode 100644 index 00000000000..bd68b0dd642 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/AmbiguousCalls.kt.after @@ -0,0 +1,18 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME +// ERROR: None of the following functions can be called with the arguments supplied:
public open fun convertPoint(p0: java.awt.Component!, p1: [ERROR : Unresolved java classifier: Point]!, p2: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities
public open fun convertPoint(p0: java.awt.Component!, p1: kotlin.Int, p2: kotlin.Int, p3: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities +// ERROR: None of the following functions can be called with the arguments supplied:
public open fun convertPoint(p0: java.awt.Component!, p1: [ERROR : Unresolved java classifier: Point]!, p2: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities
public open fun convertPoint(p0: java.awt.Component!, p1: kotlin.Int, p2: kotlin.Int, p3: java.awt.Component!): [ERROR : Unresolved java classifier: Point]! defined in javax.swing.SwingUtilities +// ERROR: Unresolved reference: unresolved + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.* + +fun foo() { + convertPoint() + + val bottom = BOTTOM + + convertPoint() + + SwingUtilities.unresolved +} diff --git a/idea/testData/intentions/importAllMembers/EnumMembers.kt b/idea/testData/intentions/importAllMembers/EnumMembers.kt new file mode 100644 index 00000000000..1e8d8992e73 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/EnumMembers.kt @@ -0,0 +1,11 @@ +// INTENTION_TEXT: "Import members from 'kotlin.LazyThreadSafetyMode'" +// WITH_RUNTIME + +class A { + val v1: Int by lazy(LazyThreadSafetyMode.NONE) { 1 } + val v2: Int by lazy(LazyThreadSafetyMode.PUBLICATION) { 1 } +/* + val v3 = LazyThreadSafetyMode.values + val v4 = LazyThreadSafetyMode.valueOf("") +*/ +} \ No newline at end of file diff --git a/idea/testData/intentions/importAllMembers/EnumMembers.kt.after b/idea/testData/intentions/importAllMembers/EnumMembers.kt.after new file mode 100644 index 00000000000..c71925c58de --- /dev/null +++ b/idea/testData/intentions/importAllMembers/EnumMembers.kt.after @@ -0,0 +1,13 @@ +import kotlin.LazyThreadSafetyMode.* + +// INTENTION_TEXT: "Import members from 'kotlin.LazyThreadSafetyMode'" +// WITH_RUNTIME + +class A { + val v1: Int by lazy(NONE) { 1 } + val v2: Int by lazy(PUBLICATION) { 1 } +/* + val v3 = LazyThreadSafetyMode.values + val v4 = LazyThreadSafetyMode.valueOf("") +*/ +} \ No newline at end of file diff --git a/idea/testData/intentions/importAllMembers/EnumMembersValues.kt.todo b/idea/testData/intentions/importAllMembers/EnumMembersValues.kt.todo new file mode 100644 index 00000000000..b9d8cb97d72 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/EnumMembersValues.kt.todo @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME + +val v = LazyThreadSafetyMode.values diff --git a/idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt b/idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt new file mode 100644 index 00000000000..b995d5fc32d --- /dev/null +++ b/idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME + +import kotlin.text.Regex + +fun foo() { + Regex.escape("") +} \ No newline at end of file diff --git a/idea/testData/intentions/importAllMembers/NotFromObject.kt b/idea/testData/intentions/importAllMembers/NotFromObject.kt new file mode 100644 index 00000000000..d2886babc63 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/NotFromObject.kt @@ -0,0 +1,8 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME + +import kotlin.properties.Delegates + +class A { + val v1: Int by Delegates.notNull() +} \ No newline at end of file diff --git a/idea/testData/intentions/importAllMembers/QualifiedName.kt b/idea/testData/intentions/importAllMembers/QualifiedName.kt new file mode 100644 index 00000000000..5b3c8394202 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/QualifiedName.kt @@ -0,0 +1,6 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +fun foo() { + javax.swing.SwingUtilities.invokeLater { } +} diff --git a/idea/testData/intentions/importAllMembers/QualifiedName.kt.after b/idea/testData/intentions/importAllMembers/QualifiedName.kt.after new file mode 100644 index 00000000000..5af68b3b649 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/QualifiedName.kt.after @@ -0,0 +1,8 @@ +import javax.swing.SwingUtilities.* + +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +fun foo() { + invokeLater { } +} diff --git a/idea/testData/intentions/importAllMembers/QualifiedName2.kt b/idea/testData/intentions/importAllMembers/QualifiedName2.kt new file mode 100644 index 00000000000..d8d149db65a --- /dev/null +++ b/idea/testData/intentions/importAllMembers/QualifiedName2.kt @@ -0,0 +1,6 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +fun foo() { + javax.swing.SwingUtilities.invokeLater { } +} diff --git a/idea/testData/intentions/importAllMembers/QualifiedName2.kt.after b/idea/testData/intentions/importAllMembers/QualifiedName2.kt.after new file mode 100644 index 00000000000..5af68b3b649 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/QualifiedName2.kt.after @@ -0,0 +1,8 @@ +import javax.swing.SwingUtilities.* + +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +fun foo() { + invokeLater { } +} diff --git a/idea/testData/intentions/importAllMembers/RemoveSingleImports.kt b/idea/testData/intentions/importAllMembers/RemoveSingleImports.kt new file mode 100644 index 00000000000..7827e2a1f56 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/RemoveSingleImports.kt @@ -0,0 +1,17 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.invokeLater + +fun foo() { + invokeLater { } + + val bottom = SwingUtilities.BOTTOM + + SwingUtilities.invokeAndWait { + invokeLater { } + } + + val horizontal = javax.swing.SwingUtilities.HORIZONTAL +} diff --git a/idea/testData/intentions/importAllMembers/RemoveSingleImports.kt.after b/idea/testData/intentions/importAllMembers/RemoveSingleImports.kt.after new file mode 100644 index 00000000000..aa1967a1312 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/RemoveSingleImports.kt.after @@ -0,0 +1,17 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.* + +fun foo() { + invokeLater { } + + val bottom = BOTTOM + + invokeAndWait { + invokeLater { } + } + + val horizontal = HORIZONTAL +} diff --git a/idea/testData/intentions/importAllMembers/StaticJavaMembers.kt b/idea/testData/intentions/importAllMembers/StaticJavaMembers.kt new file mode 100644 index 00000000000..66dfeef1429 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/StaticJavaMembers.kt @@ -0,0 +1,19 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME +// ERROR: Unresolved reference: unresolved + +import javax.swing.SwingUtilities + +fun foo() { + SwingUtilities.invokeLater { } + + val bottom = SwingUtilities.BOTTOM + + SwingUtilities.invokeAndWait { + SwingUtilities.invokeLater { } + } + + val horizontal = javax.swing.SwingUtilities.HORIZONTAL + + SwingUtilities.unresolved +} diff --git a/idea/testData/intentions/importAllMembers/StaticJavaMembers.kt.after b/idea/testData/intentions/importAllMembers/StaticJavaMembers.kt.after new file mode 100644 index 00000000000..d1e0a761c0a --- /dev/null +++ b/idea/testData/intentions/importAllMembers/StaticJavaMembers.kt.after @@ -0,0 +1,20 @@ +// INTENTION_TEXT: "Import members from 'javax.swing.SwingUtilities'" +// WITH_RUNTIME +// ERROR: Unresolved reference: unresolved + +import javax.swing.SwingUtilities +import javax.swing.SwingUtilities.* + +fun foo() { + invokeLater { } + + val bottom = BOTTOM + + invokeAndWait { + invokeLater { } + } + + val horizontal = HORIZONTAL + + SwingUtilities.unresolved +} diff --git a/idea/testData/intentions/importAllMembers/UnresolvedMember.kt b/idea/testData/intentions/importAllMembers/UnresolvedMember.kt new file mode 100644 index 00000000000..232e592b642 --- /dev/null +++ b/idea/testData/intentions/importAllMembers/UnresolvedMember.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME +// ERROR: Unresolved reference: unresolved + +import javax.swing.SwingUtilities + +val v = SwingUtilities.unresolved() \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 6167d831e90..c0570ce4cf7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -5098,6 +5098,81 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/importAllMembers") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ImportAllMembers extends AbstractIntentionTest { + public void testAllFilesPresentInImportAllMembers() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/importAllMembers"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("AlreadyImported.kt") + public void testAlreadyImported() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/AlreadyImported.kt"); + doTest(fileName); + } + + @TestMetadata("AlreadyImportedWithStar.kt") + public void testAlreadyImportedWithStar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/AlreadyImportedWithStar.kt"); + doTest(fileName); + } + + @TestMetadata("AmbiguousCalls.kt") + public void testAmbiguousCalls() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/AmbiguousCalls.kt"); + doTest(fileName); + } + + @TestMetadata("EnumMembers.kt") + public void testEnumMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/EnumMembers.kt"); + doTest(fileName); + } + + @TestMetadata("NotFromCompanionObject.kt") + public void testNotFromCompanionObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/NotFromCompanionObject.kt"); + doTest(fileName); + } + + @TestMetadata("NotFromObject.kt") + public void testNotFromObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/NotFromObject.kt"); + doTest(fileName); + } + + @TestMetadata("QualifiedName.kt") + public void testQualifiedName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/QualifiedName.kt"); + doTest(fileName); + } + + @TestMetadata("QualifiedName2.kt") + public void testQualifiedName2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/QualifiedName2.kt"); + doTest(fileName); + } + + @TestMetadata("RemoveSingleImports.kt") + public void testRemoveSingleImports() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/RemoveSingleImports.kt"); + doTest(fileName); + } + + @TestMetadata("StaticJavaMembers.kt") + public void testStaticJavaMembers() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/StaticJavaMembers.kt"); + doTest(fileName); + } + + @TestMetadata("UnresolvedMember.kt") + public void testUnresolvedMember() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/importAllMembers/UnresolvedMember.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/importMember") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)