Optimization: look for callables at first when prefix starts uppercase and the opposite otherwise

This commit is contained in:
Valentin Kipyatkov
2016-10-27 19:48:33 +03:00
parent dbaaee7d0b
commit 23c22984e8
5 changed files with 97 additions and 35 deletions
@@ -175,6 +175,10 @@ class DescriptorKindFilter(
abstract class DescriptorKindExclude {
abstract fun excludes(descriptor: DeclarationDescriptor): Boolean
/**
* Bit-mask of descriptor kind's that are fully excluded by this [DescriptorKindExclude].
* That is, [excludes] returns true for all descriptor of these kinds.
*/
abstract val fullyExcludedDescriptorKinds: Int
override fun toString() = this.javaClass.simpleName
@@ -190,8 +194,8 @@ abstract class DescriptorKindExclude {
override fun excludes(descriptor: DeclarationDescriptor)
= descriptor !is CallableDescriptor || descriptor.extensionReceiverParameter == null
override val fullyExcludedDescriptorKinds: Int
get() = DescriptorKindFilter.ALL_KINDS_MASK and (DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK).inv()
override val fullyExcludedDescriptorKinds
= DescriptorKindFilter.ALL_KINDS_MASK and (DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK).inv()
}
object EnumEntry : DescriptorKindExclude() {
@@ -26,9 +26,7 @@ import com.intellij.patterns.StandardPatterns
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.ProcessingContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.completion.handlers.createKeywordConstructLookupElement
import org.jetbrains.kotlin.idea.completion.smart.ExpectedInfoMatch
import org.jetbrains.kotlin.idea.completion.smart.SMART_COMPLETION_ITEM_PRIORITY_KEY
@@ -39,6 +37,8 @@ import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptorKindExclude
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
@@ -158,7 +158,7 @@ class BasicCompletionSession(
}
private val ALL = object : CompletionKind {
override val descriptorKindFilter: DescriptorKindFilter? by lazy {
override val descriptorKindFilter: DescriptorKindFilter by lazy {
var filter = callTypeAndReceiver.callType.descriptorKindFilter
if (filter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0) {
@@ -201,9 +201,20 @@ class BasicCompletionSession(
val contextVariableTypesForSmartCompletion = withCollectRequiredContextVariableTypes(::completeWithSmartCompletion)
val contextVariableTypesForReferenceVariants = withCollectRequiredContextVariableTypes { lookupElementFactory ->
val (imported, notImported) = referenceVariantsWithNonInitializedVarExcluded!!
collector.addDescriptorElements(imported, lookupElementFactory)
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true)
if (prefix.isEmpty() || callTypeAndReceiver.receiver != null) {
addReferenceVariantElements(lookupElementFactory, descriptorKindFilter)
}
else if (prefix[0].isLowerCase()) {
addReferenceVariantElements(lookupElementFactory, USUALLY_START_LOWER_CASE.intersect(descriptorKindFilter))
flushToResultSet()
addReferenceVariantElements(lookupElementFactory, USUALLY_START_UPPER_CASE.intersect(descriptorKindFilter))
}
else {
addReferenceVariantElements(lookupElementFactory, USUALLY_START_UPPER_CASE.intersect(descriptorKindFilter))
flushToResultSet()
addReferenceVariantElements(lookupElementFactory, USUALLY_START_LOWER_CASE.intersect(descriptorKindFilter))
}
referenceVariantsCollector!!.collectingFinished()
}
KEYWORDS_ONLY.doComplete()
@@ -253,7 +264,11 @@ class BasicCompletionSession(
}
val staticMembersCompletion = StaticMembersCompletion(
prefixMatcher, resolutionFacade, lookupElementFactory, referenceVariants!!.imported, isJvmModule)
prefixMatcher,
resolutionFacade,
lookupElementFactory,
referenceVariantsCollector!!.allCollected.imported,
isJvmModule)
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
staticMembersCompletion.completeFromImports(file, collector)
}
@@ -526,7 +541,7 @@ class BasicCompletionSession(
}
private val SUPER_QUALIFIER = object : CompletionKind {
override val descriptorKindFilter: DescriptorKindFilter?
override val descriptorKindFilter: DescriptorKindFilter
get() = DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS
override fun doComplete() {
@@ -536,7 +551,7 @@ class BasicCompletionSession(
.mapNotNull { it.constructor.declarationDescriptor as? ClassDescriptor }
if (callTypeAndReceiver.receiver != null) {
val referenceVariantsSet = referenceVariants!!.imported.toSet()
val referenceVariantsSet = referenceVariantsCollector!!.collectReferenceVariants(descriptorKindFilter).imported.toSet()
superClasses = superClasses.filter { it in referenceVariantsSet }
}
@@ -594,4 +609,20 @@ class BasicCompletionSession(
).collect(classifierDescriptorCollector, javaClassCollector)
}
}
private fun addReferenceVariantElements(lookupElementFactory: LookupElementFactory, descriptorKindFilter: DescriptorKindFilter) {
val (imported, notImported) = referenceVariantsCollector!!.collectReferenceVariants(descriptorKindFilter).excludeNonInitializedVariable()
collector.addDescriptorElements(imported, lookupElementFactory)
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true)
}
}
private val USUALLY_START_UPPER_CASE = DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.FUNCTIONS_MASK,
listOf(NonSamConstructorFunctionExclude, DescriptorKindExclude.Extensions /* needed for faster getReferenceVariants */))
private val USUALLY_START_LOWER_CASE = DescriptorKindFilter(DescriptorKindFilter.CALLABLES_MASK or DescriptorKindFilter.PACKAGES_MASK,
listOf(SamConstructorDescriptorKindExclude))
private object NonSamConstructorFunctionExclude : DescriptorKindExclude() {
override fun excludes(descriptor: DeclarationDescriptor) = descriptor is FunctionDescriptor && descriptor !is SamConstructorDescriptor
override val fullyExcludedDescriptorKinds: Int get() = 0
}
@@ -269,29 +269,28 @@ abstract class CompletionSession(
return context
}
protected val referenceVariants: ReferenceVariants? by lazy {
if (nameExpression != null && descriptorKindFilter != null)
ReferenceVariantsCollector(referenceVariantsHelper, indicesHelper(true), prefixMatcher,
nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext,
importableFqNameClassifier, configuration
).collectReferenceVariants(descriptorKindFilter!!)
else
null
protected val referenceVariantsCollector = if (nameExpression != null) {
ReferenceVariantsCollector(referenceVariantsHelper, indicesHelper(true), prefixMatcher,
nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext,
importableFqNameClassifier, configuration)
}
else {
null
}
protected val referenceVariantsWithNonInitializedVarExcluded: ReferenceVariants? by lazy {
referenceVariants?.let { ReferenceVariants(referenceVariantsHelper.excludeNonInitializedVariable(it.imported, position), it.notImportedExtensions) }
protected fun ReferenceVariants.excludeNonInitializedVariable(): ReferenceVariants {
return ReferenceVariants(referenceVariantsHelper.excludeNonInitializedVariable(imported, position), notImportedExtensions)
}
protected fun referenceVariantsWithSingleFunctionTypeParameter(): ReferenceVariants? {
val variants = referenceVariants ?: return null
val filter: (DeclarationDescriptor) -> Boolean = { it is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(it) }
val variants = referenceVariantsCollector?.allCollected ?: return null
val filter = { descriptor: DeclarationDescriptor -> descriptor is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(descriptor) }
return ReferenceVariants(variants.imported.filter(filter), variants.notImportedExtensions.filter(filter))
}
protected fun getRuntimeReceiverTypeReferenceVariants(lookupElementFactory: LookupElementFactory): Pair<ReferenceVariants, LookupElementFactory>? {
val evaluator = file.getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) ?: return null
val referenceVariants = referenceVariants ?: return null
val referenceVariants = referenceVariantsCollector?.allCollected ?: return null
val explicitReceiver = callTypeAndReceiver.receiver as? KtExpression ?: return null
val type = bindingContext.getType(explicitReceiver) ?: return null
@@ -337,7 +336,7 @@ abstract class CompletionSession(
protected fun processTopLevelCallables(processor: (CallableDescriptor) -> Unit) {
val shadowedFilter = ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression!!, callTypeAndReceiver)
?.createNonImportedDeclarationsFilter<CallableDescriptor>(referenceVariants!!.imported)
?.createNonImportedDeclarationsFilter<CallableDescriptor>(referenceVariantsCollector!!.allCollected.imported)
indicesHelper(true).processTopLevelCallables({ prefixMatcher.prefixMatches(it) }) {
if (shadowedFilter != null) {
shadowedFilter(listOf(it)).singleOrNull()?.let(processor)
@@ -32,10 +32,11 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
import java.util.*
data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>)
internal class ReferenceVariantsCollector(
class ReferenceVariantsCollector(
private val referenceVariantsHelper: ReferenceVariantsHelper,
private val indicesHelper: KotlinIndicesHelper,
private val prefixMatcher: PrefixMatcher,
@@ -50,8 +51,32 @@ internal class ReferenceVariantsCollector(
private val prefix = prefixMatcher.prefix
private val descriptorNameFilter = prefixMatcher.asStringNameFilter()
private val collectedImported = LinkedHashSet<DeclarationDescriptor>()
private val collectedNotImportedExtensions = LinkedHashSet<CallableDescriptor>()
private var isCollectingFinished = false
val allCollected: ReferenceVariants
get() {
assert(isCollectingFinished)
return ReferenceVariants(collectedImported, collectedNotImportedExtensions)
}
fun collectingFinished() {
assert(!isCollectingFinished)
isCollectingFinished = true
}
fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter): ReferenceVariants {
assert(!isCollectingFinished)
val variants = doCollectReferenceVariants(descriptorKindFilter)
collectedImported.addAll(variants.imported)
collectedNotImportedExtensions.addAll(variants.notImportedExtensions)
return variants
}
private fun doCollectReferenceVariants(descriptorKindFilter: DescriptorKindFilter): ReferenceVariants {
val completeExtensionsFromIndices = descriptorKindFilter.kindMask.and(DescriptorKindFilter.CALLABLES_MASK) != 0
&& DescriptorKindExclude.Extensions !in descriptorKindFilter.excludes
&& callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE
@Suppress("NAME_SHADOWING")
val descriptorKindFilter = if (completeExtensionsFromIndices)
@@ -131,8 +156,7 @@ internal class ReferenceVariantsCollector(
return true
}
override val fullyExcludedDescriptorKinds: Int
get() = 0
override val fullyExcludedDescriptorKinds: Int get() = 0
}
private fun isDataClassComponentFunction(descriptor: DeclarationDescriptor): Boolean {
@@ -141,4 +165,4 @@ internal class ReferenceVariantsCollector(
DataClassDescriptorResolver.isComponentLike(descriptor.name) &&
descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
}
}
}
@@ -86,9 +86,12 @@ class SmartCompletionSession(
val filter = smartCompletion!!.descriptorFilter
val contextVariableTypesForReferenceVariants = filter?.let {
withCollectRequiredContextVariableTypes { lookupElementFactory ->
val (imported, notImported) = referenceVariantsWithNonInitializedVarExcluded ?: return@withCollectRequiredContextVariableTypes
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
if (referenceVariantsCollector != null) {
val (imported, notImported) = referenceVariantsCollector.collectReferenceVariants(descriptorKindFilter).excludeNonInitializedVariable()
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
referenceVariantsCollector.collectingFinished()
}
}
}
@@ -120,7 +123,8 @@ class SmartCompletionSession(
if (filter != null) {
val staticMembersCompletion: StaticMembersCompletion?
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
staticMembersCompletion = StaticMembersCompletion(prefixMatcher, resolutionFacade, lookupElementFactory, referenceVariants!!.imported, isJvmModule)
val alreadyCollected = referenceVariantsCollector!!.allCollected.imported
staticMembersCompletion = StaticMembersCompletion(prefixMatcher, resolutionFacade, lookupElementFactory, alreadyCollected, isJvmModule)
val decoratedFactory = staticMembersCompletion.decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER_FROM_IMPORTS)
staticMembersCompletion.membersFromImports(file)
.flatMap { filter(it, decoratedFactory) }