From 5c4ba53f4244fd60c8a48a94b425ba4e888231ef Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Mon, 6 Mar 2017 20:19:47 +0300 Subject: [PATCH] Optimization of Basic Code Completion Now we first search for simple reference variants, then for extensions Because extension search is slow #KT-16856 --- .../codeInsight/ReferenceVariantsHelper.kt | 2 +- .../idea/completion/BasicCompletionSession.kt | 13 +- .../completion/ReferenceVariantsCollector.kt | 129 +++++++++++++----- 3 files changed, 103 insertions(+), 41 deletions(-) diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index d5548e6a4be..7921eb5db3b 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -95,7 +95,7 @@ class ReferenceVariantsHelper( return variants } - fun filterOutJavaGettersAndSetters(variants: Collection): Collection { + fun filterOutJavaGettersAndSetters(variants: Collection): Collection { val accessorMethodsToRemove = HashSet() val filteredVariants = variants.filter { it !is SyntheticJavaPropertyDescriptor || !it.suppressedByNotPropertyList(notProperties) } 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 f348626327f..5fea1cd7861 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 @@ -618,9 +618,16 @@ class BasicCompletionSession( } private fun addReferenceVariantElements(lookupElementFactory: LookupElementFactory, descriptorKindFilter: DescriptorKindFilter) { - val (imported, notImported) = referenceVariantsCollector!!.collectReferenceVariants(descriptorKindFilter).excludeNonInitializedVariable() - collector.addDescriptorElements(imported, lookupElementFactory) - collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true) + fun addReferenceVariants(referenceVariants: ReferenceVariants) { + collector.addDescriptorElements(referenceVariantsHelper.excludeNonInitializedVariable(referenceVariants.imported, position), lookupElementFactory) + collector.addDescriptorElements(referenceVariants.notImportedExtensions, lookupElementFactory, notImported = true) + } + + val referenceVariantsCollector = referenceVariantsCollector!! + referenceVariantsCollector.collectReferenceVariants(descriptorKindFilter) { referenceVariants -> + addReferenceVariants(referenceVariants) + flushToResultSet() + } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt index cae5181df4e..ff877d6a571 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ReferenceVariantsCollector.kt @@ -36,6 +36,10 @@ import java.util.* data class ReferenceVariants(val imported: Collection, val notImportedExtensions: Collection) +private operator fun ReferenceVariants.plus(other: ReferenceVariants): ReferenceVariants { + return ReferenceVariants(imported.union(other.imported), notImportedExtensions.union(other.notImportedExtensions)) +} + class ReferenceVariantsCollector( private val referenceVariantsHelper: ReferenceVariantsHelper, private val indicesHelper: KotlinIndicesHelper, @@ -48,6 +52,12 @@ class ReferenceVariantsCollector( private val configuration: CompletionSessionConfiguration, private val runtimeReceiver: ExpressionReceiver? = null ) { + + data class FilterConfiguration internal constructor(val descriptorKindFilter: DescriptorKindFilter, + val additionalPropertyNameFilter: ((String) -> Boolean)?, + val shadowedDeclarationsFilter: ShadowedDeclarationsFilter?, + val completeExtensionsFromIndices: Boolean) + private val prefix = prefixMatcher.prefix private val descriptorNameFilter = prefixMatcher.asStringNameFilter() @@ -68,15 +78,37 @@ class ReferenceVariantsCollector( fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter): ReferenceVariants { assert(!isCollectingFinished) - val variants = doCollectReferenceVariants(descriptorKindFilter) - collectedImported.addAll(variants.imported) - collectedNotImportedExtensions.addAll(variants.notImportedExtensions) + val config = configure(descriptorKindFilter) + + val basic = collectBasicVariants(config) + return basic + collectExtensionVariants(config, basic) + } + + fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter, consumer: (ReferenceVariants) -> Unit) { + assert(!isCollectingFinished) + val config = configure(descriptorKindFilter) + + val basic = collectBasicVariants(config) + consumer(basic) + val extensions = collectExtensionVariants(config, basic) + consumer(extensions) + } + + private fun collectBasicVariants(filterConfiguration: FilterConfiguration): ReferenceVariants { + val variants = doCollectBasicVariants(filterConfiguration) + collectedImported += variants.imported return variants } - private val GET_SET_PREFIXES = listOf("get", "set", "ge", "se", "g", "s") + private fun collectExtensionVariants(filterConfiguration: FilterConfiguration, basicVariants: ReferenceVariants): ReferenceVariants { + val variants = doCollectExtensionVariants(filterConfiguration, basicVariants) + collectedImported += variants.imported + collectedNotImportedExtensions += variants.notImportedExtensions + return variants + } - private fun doCollectReferenceVariants(descriptorKindFilter: DescriptorKindFilter): ReferenceVariants { + + fun configure(descriptorKindFilter: DescriptorKindFilter): FilterConfiguration { val completeExtensionsFromIndices = descriptorKindFilter.kindMask.and(DescriptorKindFilter.CALLABLES_MASK) != 0 && DescriptorKindExclude.Extensions !in descriptorKindFilter.excludes && callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE @@ -86,6 +118,20 @@ class ReferenceVariantsCollector( else descriptorKindFilter + val getOrSetPrefix = GET_SET_PREFIXES.firstOrNull { prefix.startsWith(it) } + val additionalPropertyNameFilter: ((String) -> Boolean)? = getOrSetPrefix + ?.let { prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmart()).asStringNameFilter() } + + val shadowedDeclarationsFilter = if (runtimeReceiver != null) + ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, runtimeReceiver) + else + ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression, callTypeAndReceiver) + + return ReferenceVariantsCollector.FilterConfiguration(descriptorKindFilter, additionalPropertyNameFilter, shadowedDeclarationsFilter, completeExtensionsFromIndices) + } + + + private fun doCollectBasicVariants(filterConfiguration: FilterConfiguration): ReferenceVariants { fun getReferenceVariants(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection { return referenceVariantsHelper.getReferenceVariants( nameExpression, @@ -97,18 +143,19 @@ class ReferenceVariantsCollector( useReceiverType = runtimeReceiver?.type) } - var variants = getReferenceVariants(descriptorKindFilter, descriptorNameFilter.toNameFilter()) + val (descriptorKindFilter, additionalPropertyNameFilter) = filterConfiguration - val getOrSetPrefix = GET_SET_PREFIXES.firstOrNull { prefix.startsWith(it) } - val additionalPropertyNameFilter: ((String) -> Boolean)? = getOrSetPrefix - ?.let { prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmart()).asStringNameFilter() } + var basicVariants = getReferenceVariants(descriptorKindFilter, descriptorNameFilter.toNameFilter()) if (additionalPropertyNameFilter != null) { - variants += getReferenceVariants(descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES), - additionalPropertyNameFilter.toNameFilter()) - variants = variants.distinct() + basicVariants += getReferenceVariants(descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES), additionalPropertyNameFilter.toNameFilter()) + basicVariants = basicVariants.distinct() } + return ReferenceVariants(filterConfiguration.filterVariants(basicVariants).toHashSet(), emptyList()) + } + + fun doCollectExtensionVariants(filterConfiguration: FilterConfiguration, basicVariants: ReferenceVariants): ReferenceVariants { + val (_, additionalPropertyNameFilter, shadowedDeclarationsFilter, completeExtensionsFromIndices) = filterConfiguration - var notImportedExtensions: Collection = emptyList() if (completeExtensionsFromIndices) { val nameFilter = if (additionalPropertyNameFilter != null) descriptorNameFilter or additionalPropertyNameFilter @@ -119,34 +166,42 @@ class ReferenceVariantsCollector( else indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, nameExpression, bindingContext, nameFilter) - val pair = extensions.partition { importableFqNameClassifier.isImportableDescriptorImported(it) } - variants += pair.first - notImportedExtensions = pair.second + val (extensionsVariants, notImportedExtensions) = extensions.partition { importableFqNameClassifier.isImportableDescriptorImported(it) } + + val notImportedDeclarationsFilter = + shadowedDeclarationsFilter?.createNonImportedDeclarationsFilter(importedDeclarations = basicVariants.imported + extensionsVariants) + + val filteredImported = filterConfiguration.filterVariants(extensionsVariants + basicVariants.imported) + + val importedExtensionsVariants = filteredImported.filter { it !in basicVariants.imported } + + return ReferenceVariants( + importedExtensionsVariants, + notImportedExtensions.let { variants -> notImportedDeclarationsFilter?.invoke(variants) ?: variants } + ) } - val shadowedDeclarationsFilter = if (runtimeReceiver != null) - ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, runtimeReceiver) - else - ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression, callTypeAndReceiver) - - if (shadowedDeclarationsFilter != null) { - variants = shadowedDeclarationsFilter.filter(variants) - notImportedExtensions = shadowedDeclarationsFilter - .createNonImportedDeclarationsFilter(importedDeclarations = variants) - .invoke(notImportedExtensions) - } - - if (!configuration.javaGettersAndSetters) { - variants = referenceVariantsHelper.filterOutJavaGettersAndSetters(variants) - } - - if (!configuration.dataClassComponentFunctions) { - variants = variants.filter { !isDataClassComponentFunction(it) } - } - - return ReferenceVariants(variants, notImportedExtensions) + return ReferenceVariants(emptyList(), emptyList()) } + fun FilterConfiguration.filterVariants(_variants: Collection): Collection { + var variants = _variants + + if (shadowedDeclarationsFilter != null) + variants = shadowedDeclarationsFilter.filter(variants) + + if (!configuration.javaGettersAndSetters) + variants = referenceVariantsHelper.filterOutJavaGettersAndSetters(variants) + + if (!configuration.dataClassComponentFunctions) + variants = variants.filter { !isDataClassComponentFunction(it) } + + return variants + } + + + private val GET_SET_PREFIXES = listOf("get", "set", "ge", "se", "g", "s") + private object TopLevelExtensionsExclude : DescriptorKindExclude() { override fun excludes(descriptor: DeclarationDescriptor): Boolean { if (descriptor !is CallableMemberDescriptor) return false