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 class DescriptorKindExclude {
abstract fun excludes(descriptor: DeclarationDescriptor): Boolean 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 abstract val fullyExcludedDescriptorKinds: Int
override fun toString() = this.javaClass.simpleName override fun toString() = this.javaClass.simpleName
@@ -190,8 +194,8 @@ abstract class DescriptorKindExclude {
override fun excludes(descriptor: DeclarationDescriptor) override fun excludes(descriptor: DeclarationDescriptor)
= descriptor !is CallableDescriptor || descriptor.extensionReceiverParameter == null = descriptor !is CallableDescriptor || descriptor.extensionReceiverParameter == null
override val fullyExcludedDescriptorKinds: Int override val fullyExcludedDescriptorKinds
get() = DescriptorKindFilter.ALL_KINDS_MASK and (DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK).inv() = DescriptorKindFilter.ALL_KINDS_MASK and (DescriptorKindFilter.FUNCTIONS_MASK or DescriptorKindFilter.VARIABLES_MASK).inv()
} }
object EnumEntry : DescriptorKindExclude() { object EnumEntry : DescriptorKindExclude() {
@@ -26,9 +26,7 @@ import com.intellij.patterns.StandardPatterns
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.ProcessingContext import com.intellij.util.ProcessingContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.idea.completion.handlers.createKeywordConstructLookupElement import org.jetbrains.kotlin.idea.completion.handlers.createKeywordConstructLookupElement
import org.jetbrains.kotlin.idea.completion.smart.ExpectedInfoMatch import org.jetbrains.kotlin.idea.completion.smart.ExpectedInfoMatch
import org.jetbrains.kotlin.idea.completion.smart.SMART_COMPLETION_ITEM_PRIORITY_KEY 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.stubindex.PackageIndexUtil
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.lexer.KtTokens 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.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -158,7 +158,7 @@ class BasicCompletionSession(
} }
private val ALL = object : CompletionKind { private val ALL = object : CompletionKind {
override val descriptorKindFilter: DescriptorKindFilter? by lazy { override val descriptorKindFilter: DescriptorKindFilter by lazy {
var filter = callTypeAndReceiver.callType.descriptorKindFilter var filter = callTypeAndReceiver.callType.descriptorKindFilter
if (filter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0) { if (filter.kindMask.and(DescriptorKindFilter.PACKAGES_MASK) != 0) {
@@ -201,9 +201,20 @@ class BasicCompletionSession(
val contextVariableTypesForSmartCompletion = withCollectRequiredContextVariableTypes(::completeWithSmartCompletion) val contextVariableTypesForSmartCompletion = withCollectRequiredContextVariableTypes(::completeWithSmartCompletion)
val contextVariableTypesForReferenceVariants = withCollectRequiredContextVariableTypes { lookupElementFactory -> val contextVariableTypesForReferenceVariants = withCollectRequiredContextVariableTypes { lookupElementFactory ->
val (imported, notImported) = referenceVariantsWithNonInitializedVarExcluded!! if (prefix.isEmpty() || callTypeAndReceiver.receiver != null) {
collector.addDescriptorElements(imported, lookupElementFactory) addReferenceVariantElements(lookupElementFactory, descriptorKindFilter)
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true) }
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() KEYWORDS_ONLY.doComplete()
@@ -253,7 +264,11 @@ class BasicCompletionSession(
} }
val staticMembersCompletion = StaticMembersCompletion( val staticMembersCompletion = StaticMembersCompletion(
prefixMatcher, resolutionFacade, lookupElementFactory, referenceVariants!!.imported, isJvmModule) prefixMatcher,
resolutionFacade,
lookupElementFactory,
referenceVariantsCollector!!.allCollected.imported,
isJvmModule)
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
staticMembersCompletion.completeFromImports(file, collector) staticMembersCompletion.completeFromImports(file, collector)
} }
@@ -526,7 +541,7 @@ class BasicCompletionSession(
} }
private val SUPER_QUALIFIER = object : CompletionKind { private val SUPER_QUALIFIER = object : CompletionKind {
override val descriptorKindFilter: DescriptorKindFilter? override val descriptorKindFilter: DescriptorKindFilter
get() = DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS get() = DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS
override fun doComplete() { override fun doComplete() {
@@ -536,7 +551,7 @@ class BasicCompletionSession(
.mapNotNull { it.constructor.declarationDescriptor as? ClassDescriptor } .mapNotNull { it.constructor.declarationDescriptor as? ClassDescriptor }
if (callTypeAndReceiver.receiver != null) { if (callTypeAndReceiver.receiver != null) {
val referenceVariantsSet = referenceVariants!!.imported.toSet() val referenceVariantsSet = referenceVariantsCollector!!.collectReferenceVariants(descriptorKindFilter).imported.toSet()
superClasses = superClasses.filter { it in referenceVariantsSet } superClasses = superClasses.filter { it in referenceVariantsSet }
} }
@@ -594,4 +609,20 @@ class BasicCompletionSession(
).collect(classifierDescriptorCollector, javaClassCollector) ).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 return context
} }
protected val referenceVariants: ReferenceVariants? by lazy { protected val referenceVariantsCollector = if (nameExpression != null) {
if (nameExpression != null && descriptorKindFilter != null) ReferenceVariantsCollector(referenceVariantsHelper, indicesHelper(true), prefixMatcher,
ReferenceVariantsCollector(referenceVariantsHelper, indicesHelper(true), prefixMatcher, nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext,
nameExpression, callTypeAndReceiver, resolutionFacade, bindingContext, importableFqNameClassifier, configuration)
importableFqNameClassifier, configuration }
).collectReferenceVariants(descriptorKindFilter!!) else {
else null
null
} }
protected val referenceVariantsWithNonInitializedVarExcluded: ReferenceVariants? by lazy { protected fun ReferenceVariants.excludeNonInitializedVariable(): ReferenceVariants {
referenceVariants?.let { ReferenceVariants(referenceVariantsHelper.excludeNonInitializedVariable(it.imported, position), it.notImportedExtensions) } return ReferenceVariants(referenceVariantsHelper.excludeNonInitializedVariable(imported, position), notImportedExtensions)
} }
protected fun referenceVariantsWithSingleFunctionTypeParameter(): ReferenceVariants? { protected fun referenceVariantsWithSingleFunctionTypeParameter(): ReferenceVariants? {
val variants = referenceVariants ?: return null val variants = referenceVariantsCollector?.allCollected ?: return null
val filter: (DeclarationDescriptor) -> Boolean = { it is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(it) } val filter = { descriptor: DeclarationDescriptor -> descriptor is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(descriptor) }
return ReferenceVariants(variants.imported.filter(filter), variants.notImportedExtensions.filter(filter)) return ReferenceVariants(variants.imported.filter(filter), variants.notImportedExtensions.filter(filter))
} }
protected fun getRuntimeReceiverTypeReferenceVariants(lookupElementFactory: LookupElementFactory): Pair<ReferenceVariants, LookupElementFactory>? { protected fun getRuntimeReceiverTypeReferenceVariants(lookupElementFactory: LookupElementFactory): Pair<ReferenceVariants, LookupElementFactory>? {
val evaluator = file.getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) ?: return null 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 explicitReceiver = callTypeAndReceiver.receiver as? KtExpression ?: return null
val type = bindingContext.getType(explicitReceiver) ?: return null val type = bindingContext.getType(explicitReceiver) ?: return null
@@ -337,7 +336,7 @@ abstract class CompletionSession(
protected fun processTopLevelCallables(processor: (CallableDescriptor) -> Unit) { protected fun processTopLevelCallables(processor: (CallableDescriptor) -> Unit) {
val shadowedFilter = ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression!!, callTypeAndReceiver) val shadowedFilter = ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression!!, callTypeAndReceiver)
?.createNonImportedDeclarationsFilter<CallableDescriptor>(referenceVariants!!.imported) ?.createNonImportedDeclarationsFilter<CallableDescriptor>(referenceVariantsCollector!!.allCollected.imported)
indicesHelper(true).processTopLevelCallables({ prefixMatcher.prefixMatches(it) }) { indicesHelper(true).processTopLevelCallables({ prefixMatcher.prefixMatches(it) }) {
if (shadowedFilter != null) { if (shadowedFilter != null) {
shadowedFilter(listOf(it)).singleOrNull()?.let(processor) 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.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
import java.util.*
data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>) data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>)
internal class ReferenceVariantsCollector( class ReferenceVariantsCollector(
private val referenceVariantsHelper: ReferenceVariantsHelper, private val referenceVariantsHelper: ReferenceVariantsHelper,
private val indicesHelper: KotlinIndicesHelper, private val indicesHelper: KotlinIndicesHelper,
private val prefixMatcher: PrefixMatcher, private val prefixMatcher: PrefixMatcher,
@@ -50,8 +51,32 @@ internal class ReferenceVariantsCollector(
private val prefix = prefixMatcher.prefix private val prefix = prefixMatcher.prefix
private val descriptorNameFilter = prefixMatcher.asStringNameFilter() 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 { 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 val completeExtensionsFromIndices = descriptorKindFilter.kindMask.and(DescriptorKindFilter.CALLABLES_MASK) != 0
&& DescriptorKindExclude.Extensions !in descriptorKindFilter.excludes
&& callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE && callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
val descriptorKindFilter = if (completeExtensionsFromIndices) val descriptorKindFilter = if (completeExtensionsFromIndices)
@@ -131,8 +156,7 @@ internal class ReferenceVariantsCollector(
return true return true
} }
override val fullyExcludedDescriptorKinds: Int override val fullyExcludedDescriptorKinds: Int get() = 0
get() = 0
} }
private fun isDataClassComponentFunction(descriptor: DeclarationDescriptor): Boolean { private fun isDataClassComponentFunction(descriptor: DeclarationDescriptor): Boolean {
@@ -86,9 +86,12 @@ class SmartCompletionSession(
val filter = smartCompletion!!.descriptorFilter val filter = smartCompletion!!.descriptorFilter
val contextVariableTypesForReferenceVariants = filter?.let { val contextVariableTypesForReferenceVariants = filter?.let {
withCollectRequiredContextVariableTypes { lookupElementFactory -> withCollectRequiredContextVariableTypes { lookupElementFactory ->
val (imported, notImported) = referenceVariantsWithNonInitializedVarExcluded ?: return@withCollectRequiredContextVariableTypes if (referenceVariantsCollector != null) {
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) } val (imported, notImported) = referenceVariantsCollector.collectReferenceVariants(descriptorKindFilter).excludeNonInitializedVariable()
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) } 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) { if (filter != null) {
val staticMembersCompletion: StaticMembersCompletion? val staticMembersCompletion: StaticMembersCompletion?
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) { 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) val decoratedFactory = staticMembersCompletion.decoratedLookupElementFactory(ItemPriority.STATIC_MEMBER_FROM_IMPORTS)
staticMembersCompletion.membersFromImports(file) staticMembersCompletion.membersFromImports(file)
.flatMap { filter(it, decoratedFactory) } .flatMap { filter(it, decoratedFactory) }