Performance optimization in completion: search context variables of functional types later
This commit is contained in:
+47
-26
@@ -154,22 +154,30 @@ class BasicCompletionSession(
|
||||
}
|
||||
|
||||
override fun doComplete() {
|
||||
if (smartCompletion != null) {
|
||||
val (additionalItems, @Suppress("UNUSED_VARIABLE") inheritanceSearcher) = smartCompletion.additionalItems(lookupElementFactory)
|
||||
fun completeWithSmartCompletion(lookupElementFactory: LookupElementFactory) {
|
||||
if (smartCompletion != null) {
|
||||
val (additionalItems, @Suppress("UNUSED_VARIABLE") inheritanceSearcher) = smartCompletion.additionalItems(lookupElementFactory)
|
||||
|
||||
// all additional items should have SMART_COMPLETION_ITEM_PRIORITY_KEY to be recognized by SmartCompletionInBasicWeigher
|
||||
for (item in additionalItems) {
|
||||
if (item.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) == null) {
|
||||
item.putUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY, SmartCompletionItemPriority.DEFAULT)
|
||||
// all additional items should have SMART_COMPLETION_ITEM_PRIORITY_KEY to be recognized by SmartCompletionInBasicWeigher
|
||||
for (item in additionalItems) {
|
||||
if (item.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) == null) {
|
||||
item.putUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY, SmartCompletionItemPriority.DEFAULT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collector.addElements(additionalItems)
|
||||
collector.addElements(additionalItems)
|
||||
}
|
||||
}
|
||||
|
||||
val (imported, notImported) = referenceVariants!!
|
||||
collector.addDescriptorElements(imported, lookupElementFactory)
|
||||
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true)
|
||||
val contextVariableTypesForSmartCompletion = withCollectRequiredContextVariableTypes(::completeWithSmartCompletion)
|
||||
|
||||
fun completeReferenceVariants(lookupElementFactory: LookupElementFactory) {
|
||||
val (imported, notImported) = referenceVariants!!
|
||||
collector.addDescriptorElements(imported, lookupElementFactory)
|
||||
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true)
|
||||
}
|
||||
|
||||
val contextVariableTypesForReferenceVariants = withCollectRequiredContextVariableTypes(::completeReferenceVariants)
|
||||
|
||||
KEYWORDS_ONLY.doComplete()
|
||||
|
||||
@@ -188,7 +196,7 @@ class BasicCompletionSession(
|
||||
}
|
||||
}
|
||||
|
||||
packageNames.forEach { collector.addElement(lookupElementFactory.createLookupElementForPackage(it)) }
|
||||
packageNames.forEach { collector.addElement(basicLookupElementFactory.createLookupElementForPackage(it)) }
|
||||
}
|
||||
|
||||
flushToResultSet()
|
||||
@@ -196,22 +204,35 @@ class BasicCompletionSession(
|
||||
NamedArgumentCompletion.complete(collector, expectedInfos)
|
||||
flushToResultSet()
|
||||
|
||||
completeNonImported()
|
||||
flushToResultSet()
|
||||
val contextVariablesProvider = RealContextVariablesProvider(referenceVariantsHelper, position)
|
||||
withContextVariablesProvider(contextVariablesProvider) { lookupElementFactory ->
|
||||
if (contextVariableTypesForSmartCompletion.any { contextVariablesProvider.functionTypeVariables(it).isNotEmpty() }) {
|
||||
completeWithSmartCompletion(lookupElementFactory)
|
||||
}
|
||||
|
||||
if (position.containingFile is KtCodeFragment) {
|
||||
val variantsAndFactory = getRuntimeReceiverTypeReferenceVariants()
|
||||
if (variantsAndFactory != null) {
|
||||
val variants = variantsAndFactory.first
|
||||
val lookupElementFactory = variantsAndFactory.second
|
||||
collector.addDescriptorElements(variants.imported, lookupElementFactory, withReceiverCast = true)
|
||||
collector.addDescriptorElements(variants.notImportedExtensions, lookupElementFactory, withReceiverCast = true, notImported = true)
|
||||
flushToResultSet()
|
||||
if (contextVariableTypesForReferenceVariants.any { contextVariablesProvider.functionTypeVariables(it).isNotEmpty() }) {
|
||||
val (imported, notImported) = referenceVariantsWithSingleFunctionTypeParameter()!!
|
||||
collector.addDescriptorElements(imported, lookupElementFactory)
|
||||
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true)
|
||||
}
|
||||
|
||||
completeNonImported(lookupElementFactory)
|
||||
flushToResultSet()
|
||||
|
||||
if (position.containingFile is KtCodeFragment) {
|
||||
val variantsAndFactory = getRuntimeReceiverTypeReferenceVariants(lookupElementFactory)
|
||||
if (variantsAndFactory != null) {
|
||||
val variants = variantsAndFactory.first
|
||||
@Suppress("NAME_SHADOWING") val lookupElementFactory = variantsAndFactory.second
|
||||
collector.addDescriptorElements(variants.imported, lookupElementFactory, withReceiverCast = true)
|
||||
collector.addDescriptorElements(variants.notImportedExtensions, lookupElementFactory, withReceiverCast = true, notImported = true)
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun completeNonImported() {
|
||||
private fun completeNonImported(lookupElementFactory: LookupElementFactory) {
|
||||
if (shouldCompleteTopLevelCallablesFromIndex()) {
|
||||
collector.addDescriptorElements(getTopLevelCallables(), lookupElementFactory, notImported = true)
|
||||
}
|
||||
@@ -292,7 +313,7 @@ class BasicCompletionSession(
|
||||
"override" -> {
|
||||
collector.addElement(lookupElement)
|
||||
|
||||
OverridesCompletion(collector, lookupElementFactory).complete(position)
|
||||
OverridesCompletion(collector, basicLookupElementFactory).complete(position)
|
||||
}
|
||||
|
||||
"class" -> {
|
||||
@@ -377,7 +398,7 @@ class BasicCompletionSession(
|
||||
KEYWORDS_ONLY.doComplete()
|
||||
|
||||
if (shouldCompleteParameterNameAndType()) {
|
||||
val parameterNameAndTypeCompletion = ParameterNameAndTypeCompletion(collector, lookupElementFactory, prefixMatcher, resolutionFacade)
|
||||
val parameterNameAndTypeCompletion = ParameterNameAndTypeCompletion(collector, basicLookupElementFactory, prefixMatcher, resolutionFacade)
|
||||
|
||||
// if we are typing parameter name, restart completion each time we type an upper case letter because new suggestions will appear (previous words can be used as user prefix)
|
||||
val prefixPattern = StandardPatterns.string().with(object : PatternCondition<String>("Prefix ends with uppercase letter") {
|
||||
@@ -470,7 +491,7 @@ class BasicCompletionSession(
|
||||
}
|
||||
|
||||
superClasses
|
||||
.map { lookupElementFactory.createLookupElement(it, useReceiverTypes = false, qualifyNestedClasses = true, includeClassTypeArguments = false) }
|
||||
.map { basicLookupElementFactory.createLookupElement(it, qualifyNestedClasses = true, includeClassTypeArguments = false) }
|
||||
.forEach { collector.addElement(it) }
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
|
||||
class BasicLookupElementFactory(
|
||||
private val project: Project,
|
||||
private val insertHandlerProvider: InsertHandlerProvider
|
||||
val insertHandlerProvider: InsertHandlerProvider
|
||||
) {
|
||||
public fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor,
|
||||
|
||||
+37
-25
@@ -132,14 +132,16 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, resolutionFacade, isVisibleFilter)
|
||||
|
||||
protected val callTypeAndReceiver: CallTypeAndReceiver<*, *>
|
||||
protected val lookupElementFactory: LookupElementFactory
|
||||
protected val receiverTypes: Collection<KotlinType>?
|
||||
|
||||
init {
|
||||
val (callTypeAndReceiver, receiverTypes) = detectCallTypeAndReceiverTypes()
|
||||
this.callTypeAndReceiver = callTypeAndReceiver
|
||||
this.lookupElementFactory = createLookupElementFactory(callTypeAndReceiver.callType, receiverTypes)
|
||||
this.receiverTypes = receiverTypes
|
||||
}
|
||||
|
||||
protected val basicLookupElementFactory = BasicLookupElementFactory(project, InsertHandlerProvider(callTypeAndReceiver.callType) { expectedInfos })
|
||||
|
||||
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
||||
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
|
||||
LookupElementsCollector(prefixMatcher, parameters, resultSet, createSorter())
|
||||
@@ -273,12 +275,13 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
data class ReferenceVariants(val imported: Collection<DeclarationDescriptor>, val notImportedExtensions: Collection<CallableDescriptor>)
|
||||
|
||||
protected val referenceVariants: ReferenceVariants? by lazy {
|
||||
descriptorKindFilter?.let { collectReferenceVariants(it) }
|
||||
if (nameExpression != null && descriptorKindFilter != null) collectReferenceVariants(descriptorKindFilter!!, nameExpression) else null
|
||||
}
|
||||
|
||||
private fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter, runtimeReceiver: ExpressionReceiver? = null): ReferenceVariants {
|
||||
|
||||
private fun collectReferenceVariants(descriptorKindFilter: DescriptorKindFilter, nameExpression: KtSimpleNameExpression, runtimeReceiver: ExpressionReceiver? = null): ReferenceVariants {
|
||||
var variants = referenceVariantsHelper.getReferenceVariants(
|
||||
nameExpression!!,
|
||||
nameExpression,
|
||||
descriptorKindFilter,
|
||||
descriptorNameFilter,
|
||||
filterOutJavaGettersAndSetters = false,
|
||||
@@ -315,8 +318,15 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
return ReferenceVariants(variants, notImportedExtensions)
|
||||
}
|
||||
|
||||
protected fun getRuntimeReceiverTypeReferenceVariants(): Pair<ReferenceVariants, LookupElementFactory>? {
|
||||
protected fun referenceVariantsWithSingleFunctionTypeParameter(): ReferenceVariants? {
|
||||
val variants = referenceVariants ?: return null
|
||||
val filter: (DeclarationDescriptor) -> Boolean = { it is FunctionDescriptor && LookupElementFactory.hasSingleFunctionTypeParameter(it) }
|
||||
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 explicitReceiver = callTypeAndReceiver.receiver as? KtExpression ?: return null
|
||||
val type = bindingContext.getType(explicitReceiver) ?: return null
|
||||
@@ -325,12 +335,12 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
val runtimeType = evaluator(explicitReceiver)
|
||||
if (runtimeType == null || runtimeType == type) return null
|
||||
|
||||
val (variants, notImportedExtensions) = collectReferenceVariants(descriptorKindFilter!!, ExpressionReceiver(explicitReceiver, runtimeType))
|
||||
val filteredVariants = filterVariantsForRuntimeReceiverType(variants, referenceVariants!!.imported)
|
||||
val filteredNotImportedExtensions = filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants!!.notImportedExtensions)
|
||||
val (variants, notImportedExtensions) = collectReferenceVariants(descriptorKindFilter!!, nameExpression!!, ExpressionReceiver(explicitReceiver, runtimeType))
|
||||
val filteredVariants = filterVariantsForRuntimeReceiverType(variants, referenceVariants.imported)
|
||||
val filteredNotImportedExtensions = filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants.notImportedExtensions)
|
||||
|
||||
val referenceVariants = ReferenceVariants(filteredVariants, filteredNotImportedExtensions)
|
||||
return Pair(referenceVariants, lookupElementFactory.copy(receiverTypes = listOf(runtimeType)))
|
||||
val runtimeVariants = ReferenceVariants(filteredVariants, filteredNotImportedExtensions)
|
||||
return Pair(runtimeVariants, lookupElementFactory.copy(receiverTypes = listOf(runtimeType)))
|
||||
}
|
||||
|
||||
private fun <TDescriptor : DeclarationDescriptor> filterVariantsForRuntimeReceiverType(
|
||||
@@ -373,24 +383,26 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
protected fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean) {
|
||||
AllClassesCompletion(parameters, indicesHelper, prefixMatcher, resolutionFacade, kindFilter)
|
||||
.collect(
|
||||
{ descriptor -> collector.addDescriptorElements(descriptor, lookupElementFactory, notImported = true) },
|
||||
{ javaClass -> collector.addElement(lookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) }
|
||||
{ descriptor -> collector.addElement(basicLookupElementFactory.createLookupElement(descriptor), notImported = true) },
|
||||
{ javaClass -> collector.addElement(basicLookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun createLookupElementFactory(callType: CallType<*>?, receiverTypes: Collection<KotlinType>?): LookupElementFactory {
|
||||
val contextVariablesProvider = {
|
||||
nameExpression?.let {
|
||||
val descriptorFilter = DescriptorKindFilter.VARIABLES exclude DescriptorKindExclude.Extensions // we exclude extensions by performance reasons
|
||||
referenceVariantsHelper.getReferenceVariants(it, CallTypeAndReceiver.DEFAULT, descriptorFilter, nameFilter = { true })
|
||||
.map { it as VariableDescriptor }
|
||||
} ?: emptyList()
|
||||
}
|
||||
protected fun withCollectRequiredContextVariableTypes(action: (LookupElementFactory) -> Unit): Collection<FuzzyType> {
|
||||
val provider = CollectRequiredTypesContextVariablesProvider()
|
||||
val lookupElementFactory = createLookupElementFactory(provider)
|
||||
action(lookupElementFactory)
|
||||
return provider.requiredTypes
|
||||
}
|
||||
|
||||
val insertHandlerProvider = InsertHandlerProvider(callType) { expectedInfos }
|
||||
return LookupElementFactory(resolutionFacade, receiverTypes,
|
||||
callType, expression?.parent is KtSimpleNameStringTemplateEntry,
|
||||
insertHandlerProvider, contextVariablesProvider)
|
||||
protected fun withContextVariablesProvider(contextVariablesProvider: ContextVariablesProvider, action: (LookupElementFactory) -> Unit) {
|
||||
val lookupElementFactory = createLookupElementFactory(contextVariablesProvider)
|
||||
action(lookupElementFactory)
|
||||
}
|
||||
|
||||
protected fun createLookupElementFactory(contextVariablesProvider: ContextVariablesProvider): LookupElementFactory {
|
||||
return LookupElementFactory(basicLookupElementFactory, resolutionFacade, receiverTypes,
|
||||
callTypeAndReceiver.callType, contextVariablesProvider)
|
||||
}
|
||||
|
||||
private fun detectCallTypeAndReceiverTypes(): Pair<CallTypeAndReceiver<*, *>, Collection<KotlinType>?> {
|
||||
|
||||
@@ -29,12 +29,8 @@ import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.CastReceiverInsertHandler
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.util.findLabelAndCall
|
||||
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
@@ -94,22 +90,6 @@ fun LookupElement.withReceiverCast(): LookupElement {
|
||||
}
|
||||
}
|
||||
|
||||
fun LookupElement.withBracesSurrounding(): LookupElement {
|
||||
return object: LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
val startOffset = context.getStartOffset()
|
||||
context.getDocument().insertString(startOffset, "{")
|
||||
context.getOffsetMap().addOffset(CompletionInitializationContext.START_OFFSET, startOffset + 1)
|
||||
|
||||
val tailOffset = context.getTailOffset()
|
||||
context.getDocument().insertString(tailOffset, "}")
|
||||
context.setTailOffset(tailOffset)
|
||||
|
||||
super.handleInsert(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY = Key<Unit>("KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY")
|
||||
|
||||
fun LookupElement.keepOldArgumentListOnTab(): LookupElement {
|
||||
@@ -310,7 +290,7 @@ fun breakOrContinueExpressionItems(position: KtElement, breakOrContinue: String)
|
||||
return result
|
||||
}
|
||||
|
||||
fun LookupElementFactory.createLookupElementForType(type: KotlinType): LookupElement? {
|
||||
fun BasicLookupElementFactory.createLookupElementForType(type: KotlinType): LookupElement? {
|
||||
if (type.isError()) return null
|
||||
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(type)) {
|
||||
@@ -320,7 +300,7 @@ fun LookupElementFactory.createLookupElementForType(type: KotlinType): LookupEle
|
||||
}
|
||||
else {
|
||||
val classifier = type.getConstructor().getDeclarationDescriptor() ?: return null
|
||||
val baseLookupElement = createLookupElement(classifier, useReceiverTypes = false, qualifyNestedClasses = true, includeClassTypeArguments = false)
|
||||
val baseLookupElement = createLookupElement(classifier, qualifyNestedClasses = true, includeClassTypeArguments = false)
|
||||
|
||||
val itemText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type)
|
||||
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
|
||||
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import java.util.*
|
||||
|
||||
interface ContextVariablesProvider {
|
||||
fun functionTypeVariables(requiredType: FuzzyType): Collection<Pair<VariableDescriptor, TypeSubstitutor>>
|
||||
}
|
||||
|
||||
class RealContextVariablesProvider(
|
||||
private val referenceVariantsHelper: ReferenceVariantsHelper,
|
||||
private val contextElement: PsiElement
|
||||
) : ContextVariablesProvider {
|
||||
private val functionTypeVariables by lazy {
|
||||
collectVariables().filter { KotlinBuiltIns.isFunctionOrExtensionFunctionType(it.type) }
|
||||
}
|
||||
|
||||
private fun collectVariables(): Collection<VariableDescriptor> {
|
||||
val descriptorFilter = DescriptorKindFilter.VARIABLES exclude DescriptorKindExclude.Extensions // we exclude extensions by performance reasons
|
||||
return referenceVariantsHelper.getReferenceVariants(contextElement, CallTypeAndReceiver.DEFAULT, descriptorFilter, nameFilter = { true })
|
||||
.map { it as VariableDescriptor }
|
||||
}
|
||||
|
||||
override fun functionTypeVariables(requiredType: FuzzyType): Collection<Pair<VariableDescriptor, TypeSubstitutor>> {
|
||||
val result = SmartList<Pair<VariableDescriptor, TypeSubstitutor>>()
|
||||
for (variable in functionTypeVariables) {
|
||||
val substitutor = variable.fuzzyReturnType()?.checkIsSubtypeOf(requiredType) ?: continue
|
||||
result.add(variable to substitutor)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
class CollectRequiredTypesContextVariablesProvider : ContextVariablesProvider {
|
||||
private val _requiredTypes = HashSet<FuzzyType>()
|
||||
|
||||
public val requiredTypes: Set<FuzzyType>
|
||||
get() = _requiredTypes
|
||||
|
||||
override fun functionTypeVariables(requiredType: FuzzyType): Collection<Pair<VariableDescriptor, TypeSubstitutor>> {
|
||||
_requiredTypes.add(requiredType)
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -87,7 +87,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,
|
||||
.filter { it.getName().asString() !in documentedParameters }
|
||||
|
||||
descriptors.forEach {
|
||||
collector.addElement(lookupElementFactory.createLookupElement(it, useReceiverTypes = false, parametersAndTypeGrayed = true))
|
||||
collector.addElement(basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,
|
||||
}
|
||||
|
||||
scope.collectDescriptorsFiltered(nameFilter = descriptorNameFilter).filter(::isApplicable).forEach {
|
||||
val element = lookupElementFactory.createLookupElement(it, useReceiverTypes = false, parametersAndTypeGrayed = true)
|
||||
val element = basicLookupElementFactory.createLookupElement(it, parametersAndTypeGrayed = true)
|
||||
collector.addElement(object: LookupElementDecorator<LookupElement>(element) {
|
||||
override fun handleInsert(context: InsertionContext?) {
|
||||
// insert only plain name here, no qualifier/parentheses/etc.
|
||||
|
||||
+19
-42
@@ -21,7 +21,6 @@ import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -31,9 +30,8 @@ import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.CallType
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
|
||||
@@ -44,28 +42,27 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
|
||||
data /* we need copy() */
|
||||
class LookupElementFactory(
|
||||
val basicFactory: BasicLookupElementFactory,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val receiverTypes: Collection<KotlinType>?,
|
||||
private val callType: CallType<*>?,
|
||||
private val isInStringTemplateAfterDollar: Boolean,
|
||||
public val insertHandlerProvider: InsertHandlerProvider,
|
||||
private val contextVariablesProvider: () -> Collection<VariableDescriptor>
|
||||
private val contextVariablesProvider: ContextVariablesProvider
|
||||
) {
|
||||
private val basicFactory = BasicLookupElementFactory(resolutionFacade.project, insertHandlerProvider)
|
||||
|
||||
private val functionTypeContextVariables by lazy(LazyThreadSafetyMode.NONE) {
|
||||
contextVariablesProvider().filter { KotlinBuiltIns.isFunctionOrExtensionFunctionType(it.type) }
|
||||
companion object {
|
||||
fun hasSingleFunctionTypeParameter(descriptor: FunctionDescriptor): Boolean {
|
||||
val parameter = descriptor.original.valueParameters.singleOrNull() ?: return false
|
||||
return KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameter.type)
|
||||
}
|
||||
}
|
||||
|
||||
val insertHandlerProvider = basicFactory.insertHandlerProvider
|
||||
|
||||
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||
val result = SmartList<LookupElement>()
|
||||
|
||||
val isNormalCall = callType == CallType.DEFAULT || callType == CallType.DOT || callType == CallType.SAFE
|
||||
|
||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes, parametersAndTypeGrayed = !isNormalCall && callType != CallType.INFIX)
|
||||
if (isInStringTemplateAfterDollar && (descriptor is FunctionDescriptor || descriptor is ClassifierDescriptor)) {
|
||||
lookupElement = lookupElement.withBracesSurrounding()
|
||||
}
|
||||
result.add(lookupElement)
|
||||
|
||||
// add special item for function with one argument of function type with more than one parameter
|
||||
@@ -80,11 +77,12 @@ class LookupElementFactory(
|
||||
// check that all parameters except for the last one are optional
|
||||
val lastParameter = descriptor.valueParameters.lastOrNull() ?: return
|
||||
if (!descriptor.valueParameters.all { it == lastParameter || it.hasDefaultValue() }) return
|
||||
val parameterType = lastParameter.type
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
||||
val isSingleParameter = descriptor.valueParameters.size() == 1
|
||||
|
||||
val functionParameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(lastParameter.original.type)) {
|
||||
val isSingleParameter = descriptor.valueParameters.size == 1
|
||||
|
||||
val parameterType = lastParameter.type
|
||||
val functionParameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size
|
||||
// we don't need special item inserting lambda for single functional parameter that does not need multiple arguments because the default item will be special in this case
|
||||
if (!isSingleParameter || functionParameterCount > 1) {
|
||||
add(createFunctionCallElementWithLambda(descriptor, parameterType, functionParameterCount > 1, useReceiverTypes))
|
||||
@@ -94,12 +92,9 @@ class LookupElementFactory(
|
||||
//TODO: also ::function? at least for local functions
|
||||
//TODO: order for them
|
||||
val fuzzyParameterType = FuzzyType(parameterType, descriptor.typeParameters)
|
||||
for (variable in functionTypeContextVariables) {
|
||||
val substitutor = variable.fuzzyReturnType()?.checkIsSubtypeOf(fuzzyParameterType)
|
||||
if (substitutor != null) {
|
||||
val substitutedDescriptor = descriptor.substitute(substitutor) ?: continue
|
||||
add(createFunctionCallElementWithArgument(substitutedDescriptor, variable.name.asString(), useReceiverTypes))
|
||||
}
|
||||
for ((variable, substitutor) in contextVariablesProvider.functionTypeVariables(fuzzyParameterType)) {
|
||||
val substitutedDescriptor = descriptor.substitute(substitutor)
|
||||
add(createFunctionCallElementWithArgument(substitutedDescriptor, variable.name.render(), useReceiverTypes))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,10 +134,6 @@ class LookupElementFactory(
|
||||
}
|
||||
}
|
||||
|
||||
if (isInStringTemplateAfterDollar) {
|
||||
lookupElement = lookupElement.withBracesSurrounding()
|
||||
}
|
||||
|
||||
return lookupElement
|
||||
}
|
||||
|
||||
@@ -150,13 +141,7 @@ class LookupElementFactory(
|
||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||
|
||||
val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal).inputTypeArguments
|
||||
lookupElement = FunctionCallWithArgumentLookupElement(lookupElement, descriptor, argumentText, needTypeArguments)
|
||||
|
||||
if (isInStringTemplateAfterDollar) {
|
||||
lookupElement = lookupElement.withBracesSurrounding()
|
||||
}
|
||||
|
||||
return lookupElement
|
||||
return FunctionCallWithArgumentLookupElement(lookupElement, descriptor, argumentText, needTypeArguments)
|
||||
}
|
||||
|
||||
private inner class FunctionCallWithArgumentLookupElement(
|
||||
@@ -283,12 +268,4 @@ class LookupElementFactory(
|
||||
val typeParameter = receiverParameter.type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
|
||||
return typeParameter.containingDeclaration == original
|
||||
}
|
||||
|
||||
public fun createLookupElementForJavaClass(psiClass: PsiClass, qualifyNestedClasses: Boolean = false, includeClassTypeArguments: Boolean = true): LookupElement {
|
||||
return basicFactory.createLookupElementForJavaClass(psiClass, qualifyNestedClasses, includeClassTypeArguments)
|
||||
}
|
||||
|
||||
public fun createLookupElementForPackage(name: FqName): LookupElement {
|
||||
return basicFactory.createLookupElementForPackage(name)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -49,7 +49,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
|
||||
class OverridesCompletion(
|
||||
private val collector: LookupElementsCollector,
|
||||
private val lookupElementFactory: LookupElementFactory
|
||||
private val lookupElementFactory: BasicLookupElementFactory
|
||||
) {
|
||||
private val PRESENTATION_RENDERER = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.withOptions {
|
||||
modifiers = emptySet()
|
||||
@@ -66,7 +66,7 @@ class OverridesCompletion(
|
||||
if (isConstructorParameter && memberObject.descriptor !is PropertyDescriptor) continue
|
||||
|
||||
val descriptor = memberObject.descriptor
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false)
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor)
|
||||
|
||||
var text = "override " + PRESENTATION_RENDERER.render(descriptor)
|
||||
if (descriptor is FunctionDescriptor) {
|
||||
|
||||
+9
-9
@@ -48,7 +48,7 @@ import java.util.*
|
||||
|
||||
class ParameterNameAndTypeCompletion(
|
||||
private val collector: LookupElementsCollector,
|
||||
private val lookupElementFactory: LookupElementFactory,
|
||||
private val lookupElementFactory: BasicLookupElementFactory,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val resolutionFacade: ResolutionFacade
|
||||
) {
|
||||
@@ -112,9 +112,9 @@ class ParameterNameAndTypeCompletion(
|
||||
if (descriptor != null) {
|
||||
val parameterType = descriptor.getType()
|
||||
if (parameterType.isVisible(visibilityFilter)) {
|
||||
val lookupElement = MyLookupElement.create(name, ArbitraryType(parameterType), lookupElementFactory)
|
||||
val lookupElement = MyLookupElement.create(name, ArbitraryType(parameterType), lookupElementFactory)!!
|
||||
val count = lookupElementToCount[lookupElement] ?: 0
|
||||
lookupElementToCount[lookupElement!!] = count + 1
|
||||
lookupElementToCount[lookupElement] = count + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,24 +159,24 @@ class ParameterNameAndTypeCompletion(
|
||||
}
|
||||
|
||||
private abstract class Type(private val idString: String) {
|
||||
abstract fun createTypeLookupElement(lookupElementFactory: LookupElementFactory): LookupElement?
|
||||
abstract fun createTypeLookupElement(lookupElementFactory: BasicLookupElementFactory): LookupElement?
|
||||
|
||||
override fun equals(other: Any?) = other is Type && other.idString == idString
|
||||
override fun hashCode() = idString.hashCode()
|
||||
}
|
||||
|
||||
private class DescriptorType(private val classifier: ClassifierDescriptor) : Type(IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classifier)) {
|
||||
override fun createTypeLookupElement(lookupElementFactory: LookupElementFactory)
|
||||
= lookupElementFactory.createLookupElement(classifier, useReceiverTypes = false, qualifyNestedClasses = true)
|
||||
override fun createTypeLookupElement(lookupElementFactory: BasicLookupElementFactory)
|
||||
= lookupElementFactory.createLookupElement(classifier, qualifyNestedClasses = true)
|
||||
}
|
||||
|
||||
private class JavaClassType(private val psiClass: PsiClass) : Type(psiClass.getQualifiedName()!!) {
|
||||
override fun createTypeLookupElement(lookupElementFactory: LookupElementFactory)
|
||||
override fun createTypeLookupElement(lookupElementFactory: BasicLookupElementFactory)
|
||||
= lookupElementFactory.createLookupElementForJavaClass(psiClass, qualifyNestedClasses = true)
|
||||
}
|
||||
|
||||
private class ArbitraryType(private val type: KotlinType) : Type(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)) {
|
||||
override fun createTypeLookupElement(lookupElementFactory: LookupElementFactory)
|
||||
override fun createTypeLookupElement(lookupElementFactory: BasicLookupElementFactory)
|
||||
= lookupElementFactory.createLookupElementForType(type)
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ class ParameterNameAndTypeCompletion(
|
||||
) : LookupElementDecorator<LookupElement>(typeLookupElement) {
|
||||
|
||||
companion object {
|
||||
fun create(parameterName: String, type: Type, factory: LookupElementFactory): LookupElement? {
|
||||
fun create(parameterName: String, type: Type, factory: BasicLookupElementFactory): LookupElement? {
|
||||
val typeLookupElement = type.createTypeLookupElement(factory) ?: return null
|
||||
val lookupElement = MyLookupElement(parameterName, type, typeLookupElement)
|
||||
return lookupElement.suppressAutoInsertion()
|
||||
|
||||
+2
@@ -37,6 +37,8 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
object KotlinClassifierInsertHandler : BaseDeclarationInsertHandler() {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
surroundWithBracesIfInStringTemplate(context)
|
||||
|
||||
super.handleInsert(context, item)
|
||||
|
||||
val file = context.getFile()
|
||||
|
||||
+8
-4
@@ -58,16 +58,20 @@ sealed class KotlinFunctionInsertHandler : KotlinCallableInsertHandler() {
|
||||
) = Normal(inputTypeArguments, inputValueArguments, argumentText, lambdaInfo, argumentsOnly)
|
||||
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
|
||||
val document = context.document
|
||||
|
||||
if (!argumentsOnly) {
|
||||
surroundWithBracesIfInStringTemplate(context)
|
||||
|
||||
super.handleInsert(context, item)
|
||||
}
|
||||
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.document)
|
||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(document)
|
||||
|
||||
val startOffset = context.getStartOffset()
|
||||
val element = context.getFile().findElementAt(startOffset) ?: return
|
||||
val startOffset = context.startOffset
|
||||
val element = context.file.findElementAt(startOffset) ?: return
|
||||
|
||||
addArguments(context, element)
|
||||
}
|
||||
|
||||
+23
@@ -16,8 +16,31 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.handlers
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionInitializationContext
|
||||
import com.intellij.codeInsight.completion.InsertionContext
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
|
||||
fun surroundWithBracesIfInStringTemplate(context: InsertionContext) {
|
||||
val startOffset = context.startOffset
|
||||
val document = context.document
|
||||
if (startOffset > 0 && document.charsSequence[startOffset - 1] == '$') {
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(document)
|
||||
|
||||
if (context.file.findElementAt(startOffset - 1)?.node?.elementType == KtTokens.SHORT_TEMPLATE_ENTRY_START) {
|
||||
document.insertString(startOffset, "{")
|
||||
context.offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, startOffset + 1)
|
||||
|
||||
val tailOffset = context.tailOffset
|
||||
document.insertString(tailOffset, "}")
|
||||
context.tailOffset = tailOffset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun CharSequence.indexOfSkippingSpace(c: Char, startIndex: Int): Int? {
|
||||
for (i in startIndex..this.length() - 1) {
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.BasicLookupElementFactory
|
||||
import org.jetbrains.kotlin.idea.completion.ExpectedInfo
|
||||
import org.jetbrains.kotlin.idea.completion.LookupElementFactory
|
||||
import org.jetbrains.kotlin.idea.completion.createLookupElementForType
|
||||
import org.jetbrains.kotlin.idea.completion.fuzzyType
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
@@ -36,7 +36,7 @@ object ClassLiteralItems {
|
||||
public fun addToCollection(
|
||||
collection: MutableCollection<LookupElement>,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
lookupElementFactory: LookupElementFactory,
|
||||
lookupElementFactory: BasicLookupElementFactory,
|
||||
isJvmModule: Boolean
|
||||
) {
|
||||
val typeAndSuffixToExpectedInfos = LinkedHashMap<Pair<KotlinType, String>, MutableList<ExpectedInfo>>()
|
||||
|
||||
+3
-3
@@ -173,7 +173,7 @@ class SmartCompletion(
|
||||
}
|
||||
|
||||
private fun additionalItemsNoPostProcess(lookupElementFactory: LookupElementFactory): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
|
||||
val asTypePositionItems = buildForAsTypePosition(lookupElementFactory)
|
||||
val asTypePositionItems = buildForAsTypePosition(lookupElementFactory.basicFactory)
|
||||
if (asTypePositionItems != null) {
|
||||
assert(expectedInfos.isEmpty())
|
||||
return Pair(asTypePositionItems, null)
|
||||
@@ -209,7 +209,7 @@ class SmartCompletion(
|
||||
.addToCollection(items, expectedInfos, expression, descriptorsToSkip)
|
||||
}
|
||||
|
||||
ClassLiteralItems.addToCollection(items, expectedInfos, lookupElementFactory, isJvmModule)
|
||||
ClassLiteralItems.addToCollection(items, expectedInfos, lookupElementFactory.basicFactory, isJvmModule)
|
||||
|
||||
if (!forBasicCompletion) {
|
||||
LambdaItems.addToCollection(items, expectedInfos)
|
||||
@@ -368,7 +368,7 @@ class SmartCompletion(
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildForAsTypePosition(lookupElementFactory: LookupElementFactory): Collection<LookupElement>? {
|
||||
private fun buildForAsTypePosition(lookupElementFactory: BasicLookupElementFactory): Collection<LookupElement>? {
|
||||
val binaryExpression = ((expression.getParent() as? KtUserType)
|
||||
?.getParent() as? KtTypeReference)
|
||||
?.getParent() as? KtBinaryExpressionWithTypeRHS
|
||||
|
||||
+52
-29
@@ -64,45 +64,68 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
||||
return
|
||||
}
|
||||
|
||||
if (expression != null) {
|
||||
addFunctionLiteralArgumentCompletions()
|
||||
if (expression == null) return
|
||||
|
||||
val (additionalItems, inheritanceSearcher) = smartCompletion!!.additionalItems(lookupElementFactory)
|
||||
collector.addElements(additionalItems)
|
||||
addFunctionLiteralArgumentCompletions()
|
||||
|
||||
if (nameExpression != null) {
|
||||
val filter = smartCompletion!!.descriptorFilter
|
||||
if (filter != null) {
|
||||
val (imported, notImported) = referenceVariants!!
|
||||
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
|
||||
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
|
||||
var inheritanceSearcher: InheritanceItemsSearcher? = null
|
||||
val contextVariableTypesForAdditionalItems = withCollectRequiredContextVariableTypes { lookupElementFactory ->
|
||||
val pair = smartCompletion!!.additionalItems(lookupElementFactory)
|
||||
collector.addElements(pair.first)
|
||||
inheritanceSearcher = pair.second
|
||||
}
|
||||
|
||||
val filter = smartCompletion!!.descriptorFilter
|
||||
var contextVariableTypesForReferenceVariants = filter?.let {
|
||||
withCollectRequiredContextVariableTypes { lookupElementFactory ->
|
||||
val (imported, notImported) = referenceVariants ?: return@withCollectRequiredContextVariableTypes
|
||||
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
|
||||
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
|
||||
}
|
||||
}
|
||||
|
||||
flushToResultSet()
|
||||
|
||||
val contextVariablesProvider = RealContextVariablesProvider(referenceVariantsHelper, position)
|
||||
withContextVariablesProvider(contextVariablesProvider) { lookupElementFactory ->
|
||||
if (contextVariableTypesForAdditionalItems.any { contextVariablesProvider.functionTypeVariables(it).isNotEmpty() }) {
|
||||
val additionalItems = smartCompletion!!.additionalItems(lookupElementFactory).first
|
||||
collector.addElements(additionalItems)
|
||||
}
|
||||
|
||||
if (filter != null && contextVariableTypesForReferenceVariants!!.any { contextVariablesProvider.functionTypeVariables(it).isNotEmpty() }) {
|
||||
val (imported, notImported) = referenceVariantsWithSingleFunctionTypeParameter()!!
|
||||
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
|
||||
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
|
||||
}
|
||||
|
||||
flushToResultSet()
|
||||
|
||||
if (filter != null) {
|
||||
if (shouldCompleteTopLevelCallablesFromIndex()) {
|
||||
getTopLevelCallables().forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
|
||||
flushToResultSet()
|
||||
}
|
||||
|
||||
if (shouldCompleteTopLevelCallablesFromIndex()) {
|
||||
getTopLevelCallables().forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
|
||||
if (position.getContainingFile() is KtCodeFragment) {
|
||||
val variantsAndFactory = getRuntimeReceiverTypeReferenceVariants(lookupElementFactory)
|
||||
if (variantsAndFactory != null) {
|
||||
val variants = variantsAndFactory.first
|
||||
@Suppress("NAME_SHADOWING") val lookupElementFactory = variantsAndFactory.second
|
||||
variants.imported.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }) }
|
||||
variants.notImportedExtensions.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }, notImported = true) }
|
||||
flushToResultSet()
|
||||
}
|
||||
|
||||
if (position.getContainingFile() is KtCodeFragment) {
|
||||
val variantsAndFactory = getRuntimeReceiverTypeReferenceVariants()
|
||||
if (variantsAndFactory != null) {
|
||||
val variants = variantsAndFactory.first
|
||||
val lookupElementFactory = variantsAndFactory.second
|
||||
variants.imported.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }) }
|
||||
variants.notImportedExtensions.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }, notImported = true) }
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// it makes no sense to search inheritors if there is no reference because it means that we have prefix like "this@"
|
||||
inheritanceSearcher?.search({ prefixMatcher.prefixMatches(it) }) {
|
||||
collector.addElement(it)
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// it makes no sense to search inheritors if there is no reference because it means that we have prefix like "this@"
|
||||
inheritanceSearcher?.search({ prefixMatcher.prefixMatches(it) }) {
|
||||
collector.addElement(it)
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
|
||||
// special completion for outside parenthesis lambda argument
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class C {
|
||||
companion object {
|
||||
fun create(p: (Int) -> Unit) = C()
|
||||
}
|
||||
}
|
||||
|
||||
val handler: (Int) -> Unit = {}
|
||||
|
||||
fun v: C = cr<caret>
|
||||
|
||||
// EXIST: { allLookupStrings: "C, create", itemText: "C.create", tailText: " {...} (p: (Int) -> Unit) (<root>)", typeText:"C" }
|
||||
// EXIST: { allLookupStrings: "C, create", itemText: "C.create", tailText: "(handler) (<root>)", typeText:"C" }
|
||||
+16
-4
@@ -1,6 +1,18 @@
|
||||
fun foo(p: (String, Char) -> Unit): String {}
|
||||
class C {
|
||||
companion object {
|
||||
fun foo(p: (Int) -> Unit) = C()
|
||||
}
|
||||
}
|
||||
|
||||
fun v: String = fo<caret>
|
||||
fun foo(p: (String, Char) -> Unit): C {}
|
||||
|
||||
// EXIST: { lookupString:"foo", itemText: "foo", tailText: "(p: (String, Char) -> Unit) (<root>)", typeText:"String" }
|
||||
// EXIST: { lookupString:"foo", itemText: "foo", tailText: " { String, Char -> ... } (p: (String, Char) -> Unit) (<root>)", typeText:"String" }
|
||||
val handler1: (String, Char) -> Unit = {}
|
||||
val handler2: (Int) -> Unit = {}
|
||||
|
||||
fun v: C = fo<caret>
|
||||
|
||||
// EXIST: { lookupString:"foo", itemText: "foo", tailText: "(p: (String, Char) -> Unit) (<root>)", typeText:"C" }
|
||||
// EXIST: { lookupString:"foo", itemText: "foo", tailText: " { String, Char -> ... } (p: (String, Char) -> Unit) (<root>)", typeText:"C" }
|
||||
// EXIST: { lookupString:"foo", itemText: "foo", tailText: "(handler1) (<root>)", typeText:"C" }
|
||||
// EXIST: { allLookupStrings: "C, foo", itemText: "C.foo", tailText: " {...} (p: (Int) -> Unit) (<root>)", typeText:"C" }
|
||||
// EXIST: { allLookupStrings: "C, foo", itemText: "C.foo", tailText: "(handler2) (<root>)", typeText:"C" }
|
||||
|
||||
+6
@@ -1389,6 +1389,12 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ContextVariables3.kt")
|
||||
public void testContextVariables3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ContextVariablesFilter.kt")
|
||||
public void testContextVariablesFilter() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesFilter.kt");
|
||||
|
||||
+6
@@ -1389,6 +1389,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ContextVariables3.kt")
|
||||
public void testContextVariables3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ContextVariablesFilter.kt")
|
||||
public void testContextVariablesFilter() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesFilter.kt");
|
||||
|
||||
Reference in New Issue
Block a user