diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index c653e5f406e..78b43a12356 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -19,12 +19,17 @@ package org.jetbrains.kotlin.idea.completion import com.intellij.codeInsight.completion.* import com.intellij.patterns.PatternCondition import com.intellij.patterns.StandardPatterns +import com.intellij.psi.JavaPsiFacade import com.intellij.psi.util.PsiTreeUtil import com.intellij.util.ProcessingContext import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.project.ProjectStructureUtil +import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType @@ -70,7 +75,10 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, private val completionKind = calcCompletionKind() - override val descriptorKindFilter = completionKind.descriptorKindFilter + override val descriptorKindFilter = if (isNoQualifierContext()) + completionKind.descriptorKindFilter?.withoutKinds(DescriptorKindFilter.PACKAGES_MASK) + else + completionKind.descriptorKindFilter private val parameterNameAndTypeCompletion = if (shouldCompleteParameterNameAndType()) ParameterNameAndTypeCompletion(collector, lookupElementFactory, prefixMatcher, resolutionFacade) @@ -193,6 +201,26 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, } } + // getting root packages from scope is very slow so we do this in alternative way + if (isNoQualifierContext() && (completionKind.descriptorKindFilter?.kindMask ?: 0).and(DescriptorKindFilter.PACKAGES_MASK) != 0) { + //TODO: move this code somewhere else + //TODO: filter by prefix for better performance? + val packageNames = PackageIndexUtil.getSubPackageFqNames(FqName.ROOT, originalSearchScope, project) + .map { it.shortName() } + .toMutableSet() + + if (!ProjectStructureUtil.isJsKotlinModule(parameters.getOriginalFile() as JetFile)) { + JavaPsiFacade.getInstance(project).findPackage("")?.getSubPackages(originalSearchScope)?.forEach { psiPackage -> + val name = psiPackage.getName() + if (Name.isValidIdentifier(name!!)) { + packageNames.add(Name.identifier(name)) + } + } + } + + packageNames.forEach { collector.addElement(lookupElementFactory.createLookupElementForPackage(it)) } + } + if (completionKind != CompletionKind.KEYWORDS_ONLY) { flushToResultSet() diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 019630f52db..5d1cf31aa7a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -238,7 +238,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC } protected fun getRuntimeReceiverTypeReferenceVariants(): Collection { - val descriptors = referenceVariantsHelper.getReferenceVariants(nameExpression!!, descriptorKindFilter!!, prefixMatcher.asNameFilter(), useRuntimeReceiverType = true) + val restrictedKindFilter = descriptorKindFilter!!.restrictedToKinds(DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK) // optimization + val descriptors = referenceVariantsHelper.getReferenceVariants(nameExpression!!, restrictedKindFilter, prefixMatcher.asNameFilter(), useRuntimeReceiverType = true) return descriptors.filter { descriptor -> referenceVariants.none { comparePossiblyOverridingDescriptors(project, it, descriptor) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt index 6371f9ae533..892eed26ee8 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt @@ -143,11 +143,10 @@ private class DeclarationRemotenessWeigher(private val file: JetFile) : LookupEl return Weight.thisFile } - val qualifiedName = o.qualifiedName() + val fqName = o.importableFqName // Invalid name can be met for companion object descriptor: Test.MyTest.A..testOther - if (qualifiedName != null && isValidJavaFqName(qualifiedName)) { - val importPath = ImportPath(qualifiedName) - val fqName = importPath.fqnPart() + if (fqName != null) { + val importPath = ImportPath(fqName, false) return when { JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty() -> Weight.notToBeUsedInKotlin ImportInsertHelper.getInstance(file.getProject()).isImportedWithDefault(importPath, file) -> Weight.kotlinDefaultImport diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt index 82fc10112bc..0b81c5d001f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/DeclarationLookupObjectImpl.kt @@ -18,12 +18,17 @@ package org.jetbrains.kotlin.idea.completion import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.Iconable +import com.intellij.psi.PsiClass import com.intellij.psi.PsiDocCommentOwner import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNamedElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject +import org.jetbrains.kotlin.idea.imports.importableFqName +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution import javax.swing.Icon @@ -40,6 +45,17 @@ public abstract class DeclarationLookupObjectImpl( assert(descriptor != null || psiElement != null) } + override val name: Name? + get() = descriptor?.getName() ?: (psiElement as? PsiNamedElement)?.getName()?.let { Name.identifier(it) } + + override val importableFqName: FqName? + get() { + return if (descriptor != null) + descriptor.importableFqName + else + (psiElement as? PsiClass)?.getQualifiedName()?.let { FqName(it) } + } + override fun toString() = super.toString() + " " + (descriptor ?: psiElement) override fun hashCode(): Int { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinExcludeFromCompletionLookupActionProvider.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinExcludeFromCompletionLookupActionProvider.kt index 2277782fa35..079030bd870 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinExcludeFromCompletionLookupActionProvider.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinExcludeFromCompletionLookupActionProvider.kt @@ -35,16 +35,10 @@ public class KotlinExcludeFromCompletionLookupActionProvider : LookupActionProvi val project = lookup.getPsiFile().getProject() - lookupObject.descriptor?.importableFqName?.let { + lookupObject.importableFqName?.let { addExcludes(consumer, project, it.asString()) return } - - val psiElement = lookupObject.psiElement - if (psiElement is PsiClass) { - val qualifiedName = psiElement.getQualifiedName() ?: return - addExcludes(consumer, project, qualifiedName) - } } private fun addExcludes(consumer: Consumer, project: Project, fqName: String) { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt index 2a5d7d25f20..8563e7e7b0b 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt @@ -21,15 +21,18 @@ import com.intellij.codeInsight.lookup.* import com.intellij.codeInsight.lookup.impl.LookupCellRenderer import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement +import com.intellij.util.PlatformIcons import org.jetbrains.kotlin.asJava.KotlinLightClass import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.JetDescriptorIconProvider import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.completion.handlers.* +import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject import org.jetbrains.kotlin.types.typeUtil.TypeNullability import org.jetbrains.kotlin.types.typeUtil.nullability import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils @@ -37,6 +40,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.synthetic.SyntheticJavaBeansPropertyDescriptor import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils +import javax.swing.Icon public class LookupElementFactory( private val resolutionFacade: ResolutionFacade, @@ -137,6 +141,24 @@ public class LookupElementFactory( return element.withIconFromLookupObject() } + public fun createLookupElementForPackage(shortName: Name): LookupElement { + return LookupElementBuilder.create(PackageLookupObject(shortName), shortName.asString()) + .withInsertHandler(BaseDeclarationInsertHandler()) + .withIconFromLookupObject() + } + + private data class PackageLookupObject(override val name: Name) : DeclarationLookupObject { + override val psiElement: PsiElement? get() = null + + override val descriptor: DeclarationDescriptor? get() = null + + override val importableFqName: FqName? get() = null + + override val isDeprecated: Boolean get() = false + + override fun getIcon(flags: Int) = PlatformIcons.PACKAGE_ICON + } + private fun createLookupElement( descriptor: DeclarationDescriptor, declaration: PsiElement?, @@ -152,6 +174,10 @@ public class LookupElementFactory( return createLookupElementForJavaClass(declaration, qualifyNestedClasses, includeClassTypeArguments) } + if (descriptor is PackageViewDescriptor || descriptor is PackageFragmentDescriptor) { + return createLookupElementForPackage(descriptor.getName()) + } + // for constructor use name and icon of containing class val nameAndIconDescriptor: DeclarationDescriptor val iconDeclaration: PsiElement? diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt index 83b231a7145..c5e97cceca3 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt @@ -26,9 +26,8 @@ import org.jetbrains.kotlin.renderer.render open class BaseDeclarationInsertHandler : InsertHandler { override fun handleInsert(context: InsertionContext, item: LookupElement) { - val descriptor = (item.getObject() as? DeclarationLookupObject)?.descriptor - if (descriptor != null) { - val name = descriptor.getName() + val name = (item.getObject() as? DeclarationLookupObject)?.name + if (name != null) { val nameInCode = name.render() val document = context.getDocument() val needEscaping = nameInCode != name.asString() diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/completion/DeclarationLookupObject.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/completion/DeclarationLookupObject.kt index 654eafb4247..d775f073b8f 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/completion/DeclarationLookupObject.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/completion/DeclarationLookupObject.kt @@ -19,9 +19,13 @@ package org.jetbrains.kotlin.idea.core.completion import com.intellij.openapi.util.Iconable import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name public interface DeclarationLookupObject : Iconable { public val psiElement: PsiElement? public val descriptor: DeclarationDescriptor? + public val name: Name? + public val importableFqName: FqName? public val isDeprecated: Boolean }