Optimization in completion: don't spend too much time calculating root packages
This commit is contained in:
+29
-1
@@ -19,12 +19,17 @@ package org.jetbrains.kotlin.idea.completion
|
|||||||
import com.intellij.codeInsight.completion.*
|
import com.intellij.codeInsight.completion.*
|
||||||
import com.intellij.patterns.PatternCondition
|
import com.intellij.patterns.PatternCondition
|
||||||
import com.intellij.patterns.StandardPatterns
|
import com.intellij.patterns.StandardPatterns
|
||||||
|
import com.intellij.psi.JavaPsiFacade
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.util.ProcessingContext
|
import com.intellij.util.ProcessingContext
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
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.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
@@ -70,7 +75,10 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
|||||||
|
|
||||||
private val completionKind = calcCompletionKind()
|
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())
|
private val parameterNameAndTypeCompletion = if (shouldCompleteParameterNameAndType())
|
||||||
ParameterNameAndTypeCompletion(collector, lookupElementFactory, prefixMatcher, resolutionFacade)
|
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) {
|
if (completionKind != CompletionKind.KEYWORDS_ONLY) {
|
||||||
flushToResultSet()
|
flushToResultSet()
|
||||||
|
|
||||||
|
|||||||
@@ -238,7 +238,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
|
protected fun getRuntimeReceiverTypeReferenceVariants(): Collection<DeclarationDescriptor> {
|
||||||
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 ->
|
return descriptors.filter { descriptor ->
|
||||||
referenceVariants.none { comparePossiblyOverridingDescriptors(project, it, descriptor) }
|
referenceVariants.none { comparePossiblyOverridingDescriptors(project, it, descriptor) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,11 +143,10 @@ private class DeclarationRemotenessWeigher(private val file: JetFile) : LookupEl
|
|||||||
return Weight.thisFile
|
return Weight.thisFile
|
||||||
}
|
}
|
||||||
|
|
||||||
val qualifiedName = o.qualifiedName()
|
val fqName = o.importableFqName
|
||||||
// Invalid name can be met for companion object descriptor: Test.MyTest.A.<no name provided>.testOther
|
// Invalid name can be met for companion object descriptor: Test.MyTest.A.<no name provided>.testOther
|
||||||
if (qualifiedName != null && isValidJavaFqName(qualifiedName)) {
|
if (fqName != null) {
|
||||||
val importPath = ImportPath(qualifiedName)
|
val importPath = ImportPath(fqName, false)
|
||||||
val fqName = importPath.fqnPart()
|
|
||||||
return when {
|
return when {
|
||||||
JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty() -> Weight.notToBeUsedInKotlin
|
JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty() -> Weight.notToBeUsedInKotlin
|
||||||
ImportInsertHelper.getInstance(file.getProject()).isImportedWithDefault(importPath, file) -> Weight.kotlinDefaultImport
|
ImportInsertHelper.getInstance(file.getProject()).isImportedWithDefault(importPath, file) -> Weight.kotlinDefaultImport
|
||||||
|
|||||||
+16
@@ -18,12 +18,17 @@ package org.jetbrains.kotlin.idea.completion
|
|||||||
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.util.Iconable
|
import com.intellij.openapi.util.Iconable
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiDocCommentOwner
|
import com.intellij.psi.PsiDocCommentOwner
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiNamedElement
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
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 org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
@@ -40,6 +45,17 @@ public abstract class DeclarationLookupObjectImpl(
|
|||||||
assert(descriptor != null || psiElement != null)
|
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<DeclarationLookupObject>.toString() + " " + (descriptor ?: psiElement)
|
override fun toString() = super<DeclarationLookupObject>.toString() + " " + (descriptor ?: psiElement)
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
|
|||||||
+1
-7
@@ -35,16 +35,10 @@ public class KotlinExcludeFromCompletionLookupActionProvider : LookupActionProvi
|
|||||||
|
|
||||||
val project = lookup.getPsiFile().getProject()
|
val project = lookup.getPsiFile().getProject()
|
||||||
|
|
||||||
lookupObject.descriptor?.importableFqName?.let {
|
lookupObject.importableFqName?.let {
|
||||||
addExcludes(consumer, project, it.asString())
|
addExcludes(consumer, project, it.asString())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val psiElement = lookupObject.psiElement
|
|
||||||
if (psiElement is PsiClass) {
|
|
||||||
val qualifiedName = psiElement.getQualifiedName() ?: return
|
|
||||||
addExcludes(consumer, project, qualifiedName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addExcludes(consumer: Consumer<LookupElementAction>, project: Project, fqName: String) {
|
private fun addExcludes(consumer: Consumer<LookupElementAction>, project: Project, fqName: String) {
|
||||||
|
|||||||
@@ -21,15 +21,18 @@ import com.intellij.codeInsight.lookup.*
|
|||||||
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer
|
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.util.PlatformIcons
|
||||||
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.completion.handlers.*
|
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.TypeNullability
|
||||||
import org.jetbrains.kotlin.types.typeUtil.nullability
|
import org.jetbrains.kotlin.types.typeUtil.nullability
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
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.synthetic.SyntheticJavaBeansPropertyDescriptor
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
public class LookupElementFactory(
|
public class LookupElementFactory(
|
||||||
private val resolutionFacade: ResolutionFacade,
|
private val resolutionFacade: ResolutionFacade,
|
||||||
@@ -137,6 +141,24 @@ public class LookupElementFactory(
|
|||||||
return element.withIconFromLookupObject()
|
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(
|
private fun createLookupElement(
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
declaration: PsiElement?,
|
declaration: PsiElement?,
|
||||||
@@ -152,6 +174,10 @@ public class LookupElementFactory(
|
|||||||
return createLookupElementForJavaClass(declaration, qualifyNestedClasses, includeClassTypeArguments)
|
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
|
// for constructor use name and icon of containing class
|
||||||
val nameAndIconDescriptor: DeclarationDescriptor
|
val nameAndIconDescriptor: DeclarationDescriptor
|
||||||
val iconDeclaration: PsiElement?
|
val iconDeclaration: PsiElement?
|
||||||
|
|||||||
+2
-3
@@ -26,9 +26,8 @@ import org.jetbrains.kotlin.renderer.render
|
|||||||
|
|
||||||
open class BaseDeclarationInsertHandler : InsertHandler<LookupElement> {
|
open class BaseDeclarationInsertHandler : InsertHandler<LookupElement> {
|
||||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||||
val descriptor = (item.getObject() as? DeclarationLookupObject)?.descriptor
|
val name = (item.getObject() as? DeclarationLookupObject)?.name
|
||||||
if (descriptor != null) {
|
if (name != null) {
|
||||||
val name = descriptor.getName()
|
|
||||||
val nameInCode = name.render()
|
val nameInCode = name.render()
|
||||||
val document = context.getDocument()
|
val document = context.getDocument()
|
||||||
val needEscaping = nameInCode != name.asString()
|
val needEscaping = nameInCode != name.asString()
|
||||||
|
|||||||
+4
@@ -19,9 +19,13 @@ package org.jetbrains.kotlin.idea.core.completion
|
|||||||
import com.intellij.openapi.util.Iconable
|
import com.intellij.openapi.util.Iconable
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
public interface DeclarationLookupObject : Iconable {
|
public interface DeclarationLookupObject : Iconable {
|
||||||
public val psiElement: PsiElement?
|
public val psiElement: PsiElement?
|
||||||
public val descriptor: DeclarationDescriptor?
|
public val descriptor: DeclarationDescriptor?
|
||||||
|
public val name: Name?
|
||||||
|
public val importableFqName: FqName?
|
||||||
public val isDeprecated: Boolean
|
public val isDeprecated: Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user