Optimization of Basic Code Completion

Now we first search for simple reference variants, then for extensions
 Because extension search is slow
 #KT-16856
This commit is contained in:
Simon Ogorodnik
2017-03-06 20:19:47 +03:00
parent 4906ddfc29
commit 5c4ba53f42
3 changed files with 103 additions and 41 deletions
@@ -95,7 +95,7 @@ class ReferenceVariantsHelper(
return variants return variants
} }
fun filterOutJavaGettersAndSetters(variants: Collection<DeclarationDescriptor>): Collection<DeclarationDescriptor> { fun <TDescriptor: DeclarationDescriptor> filterOutJavaGettersAndSetters(variants: Collection<TDescriptor>): Collection<TDescriptor> {
val accessorMethodsToRemove = HashSet<FunctionDescriptor>() val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
val filteredVariants = variants.filter { it !is SyntheticJavaPropertyDescriptor || !it.suppressedByNotPropertyList(notProperties) } val filteredVariants = variants.filter { it !is SyntheticJavaPropertyDescriptor || !it.suppressedByNotPropertyList(notProperties) }
@@ -618,9 +618,16 @@ class BasicCompletionSession(
} }
private fun addReferenceVariantElements(lookupElementFactory: LookupElementFactory, descriptorKindFilter: DescriptorKindFilter) { private fun addReferenceVariantElements(lookupElementFactory: LookupElementFactory, descriptorKindFilter: DescriptorKindFilter) {
val (imported, notImported) = referenceVariantsCollector!!.collectReferenceVariants(descriptorKindFilter).excludeNonInitializedVariable() fun addReferenceVariants(referenceVariants: ReferenceVariants) {
collector.addDescriptorElements(imported, lookupElementFactory) collector.addDescriptorElements(referenceVariantsHelper.excludeNonInitializedVariable(referenceVariants.imported, position), lookupElementFactory)
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true) collector.addDescriptorElements(referenceVariants.notImportedExtensions, lookupElementFactory, notImported = true)
}
val referenceVariantsCollector = referenceVariantsCollector!!
referenceVariantsCollector.collectReferenceVariants(descriptorKindFilter) { referenceVariants ->
addReferenceVariants(referenceVariants)
flushToResultSet()
}
} }
} }
@@ -36,6 +36,10 @@ 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>)
private operator fun ReferenceVariants.plus(other: ReferenceVariants): ReferenceVariants {
return ReferenceVariants(imported.union(other.imported), notImportedExtensions.union(other.notImportedExtensions))
}
class ReferenceVariantsCollector( class ReferenceVariantsCollector(
private val referenceVariantsHelper: ReferenceVariantsHelper, private val referenceVariantsHelper: ReferenceVariantsHelper,
private val indicesHelper: KotlinIndicesHelper, private val indicesHelper: KotlinIndicesHelper,
@@ -48,6 +52,12 @@ class ReferenceVariantsCollector(
private val configuration: CompletionSessionConfiguration, private val configuration: CompletionSessionConfiguration,
private val runtimeReceiver: ExpressionReceiver? = null 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 prefix = prefixMatcher.prefix
private val descriptorNameFilter = prefixMatcher.asStringNameFilter() private val descriptorNameFilter = prefixMatcher.asStringNameFilter()
@@ -68,15 +78,37 @@ class ReferenceVariantsCollector(
fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter): ReferenceVariants { fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter): ReferenceVariants {
assert(!isCollectingFinished) assert(!isCollectingFinished)
val variants = doCollectReferenceVariants(descriptorKindFilter) val config = configure(descriptorKindFilter)
collectedImported.addAll(variants.imported)
collectedNotImportedExtensions.addAll(variants.notImportedExtensions) 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 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 val completeExtensionsFromIndices = descriptorKindFilter.kindMask.and(DescriptorKindFilter.CALLABLES_MASK) != 0
&& DescriptorKindExclude.Extensions !in descriptorKindFilter.excludes && DescriptorKindExclude.Extensions !in descriptorKindFilter.excludes
&& callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE && callTypeAndReceiver !is CallTypeAndReceiver.IMPORT_DIRECTIVE
@@ -86,6 +118,20 @@ class ReferenceVariantsCollector(
else else
descriptorKindFilter 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<DeclarationDescriptor> { fun getReferenceVariants(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
return referenceVariantsHelper.getReferenceVariants( return referenceVariantsHelper.getReferenceVariants(
nameExpression, nameExpression,
@@ -97,18 +143,19 @@ class ReferenceVariantsCollector(
useReceiverType = runtimeReceiver?.type) useReceiverType = runtimeReceiver?.type)
} }
var variants = getReferenceVariants(descriptorKindFilter, descriptorNameFilter.toNameFilter()) val (descriptorKindFilter, additionalPropertyNameFilter) = filterConfiguration
val getOrSetPrefix = GET_SET_PREFIXES.firstOrNull { prefix.startsWith(it) } var basicVariants = getReferenceVariants(descriptorKindFilter, descriptorNameFilter.toNameFilter())
val additionalPropertyNameFilter: ((String) -> Boolean)? = getOrSetPrefix
?.let { prefixMatcher.cloneWithPrefix(prefix.removePrefix(getOrSetPrefix).decapitalizeSmart()).asStringNameFilter() }
if (additionalPropertyNameFilter != null) { if (additionalPropertyNameFilter != null) {
variants += getReferenceVariants(descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES), basicVariants += getReferenceVariants(descriptorKindFilter.intersect(DescriptorKindFilter.VARIABLES), additionalPropertyNameFilter.toNameFilter())
additionalPropertyNameFilter.toNameFilter()) basicVariants = basicVariants.distinct()
variants = variants.distinct()
} }
return ReferenceVariants(filterConfiguration.filterVariants(basicVariants).toHashSet(), emptyList())
}
fun doCollectExtensionVariants(filterConfiguration: FilterConfiguration, basicVariants: ReferenceVariants): ReferenceVariants {
val (_, additionalPropertyNameFilter, shadowedDeclarationsFilter, completeExtensionsFromIndices) = filterConfiguration
var notImportedExtensions: Collection<CallableDescriptor> = emptyList()
if (completeExtensionsFromIndices) { if (completeExtensionsFromIndices) {
val nameFilter = if (additionalPropertyNameFilter != null) val nameFilter = if (additionalPropertyNameFilter != null)
descriptorNameFilter or additionalPropertyNameFilter descriptorNameFilter or additionalPropertyNameFilter
@@ -119,34 +166,42 @@ class ReferenceVariantsCollector(
else else
indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, nameExpression, bindingContext, nameFilter) indicesHelper.getCallableTopLevelExtensions(callTypeAndReceiver, nameExpression, bindingContext, nameFilter)
val pair = extensions.partition { importableFqNameClassifier.isImportableDescriptorImported(it) } val (extensionsVariants, notImportedExtensions) = extensions.partition { importableFqNameClassifier.isImportableDescriptorImported(it) }
variants += pair.first
notImportedExtensions = pair.second val notImportedDeclarationsFilter =
shadowedDeclarationsFilter?.createNonImportedDeclarationsFilter<CallableDescriptor>(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) return ReferenceVariants(emptyList(), emptyList())
ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, runtimeReceiver)
else
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, nameExpression, callTypeAndReceiver)
if (shadowedDeclarationsFilter != null) {
variants = shadowedDeclarationsFilter.filter(variants)
notImportedExtensions = shadowedDeclarationsFilter
.createNonImportedDeclarationsFilter<CallableDescriptor>(importedDeclarations = variants)
.invoke(notImportedExtensions)
}
if (!configuration.javaGettersAndSetters) {
variants = referenceVariantsHelper.filterOutJavaGettersAndSetters(variants)
}
if (!configuration.dataClassComponentFunctions) {
variants = variants.filter { !isDataClassComponentFunction(it) }
}
return ReferenceVariants(variants, notImportedExtensions)
} }
fun <TDescriptor : DeclarationDescriptor> FilterConfiguration.filterVariants(_variants: Collection<TDescriptor>): Collection<TDescriptor> {
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() { private object TopLevelExtensionsExclude : DescriptorKindExclude() {
override fun excludes(descriptor: DeclarationDescriptor): Boolean { override fun excludes(descriptor: DeclarationDescriptor): Boolean {
if (descriptor !is CallableMemberDescriptor) return false if (descriptor !is CallableMemberDescriptor) return false