Moved creation of additional items like special items for functions accepting lambda into LookupElementFactory to provide them in smart completion too
This commit is contained in:
+1
-1
@@ -334,7 +334,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
}
|
||||
|
||||
superClasses
|
||||
.map { lookupElementFactory.createLookupElement(it, boldImmediateMembers = false, qualifyNestedClasses = true, includeClassTypeArguments = false) }
|
||||
.map { lookupElementFactory.createLookupElement(it, useReceiverTypes = false, qualifyNestedClasses = true, includeClassTypeArguments = false) }
|
||||
.forEach { collector.addElement(it) }
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,13 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
|
||||
protected val receiversData: ReferenceVariantsHelper.ReceiversData? = nameExpression?.let { referenceVariantsHelper.getReferenceVariantsReceivers(it) }
|
||||
|
||||
private val factoryContext = if (expression?.getParent() is JetSimpleNameStringTemplateEntry)
|
||||
LookupElementFactory.Context.STRING_TEMPLATE_AFTER_DOLLAR
|
||||
else if (receiversData?.callType == CallType.INFIX)
|
||||
LookupElementFactory.Context.INFIX_CALL
|
||||
else
|
||||
LookupElementFactory.Context.NORMAL
|
||||
|
||||
protected val lookupElementFactory: LookupElementFactory = run {
|
||||
var receiverTypes = emptyList<JetType>()
|
||||
if (receiversData != null) {
|
||||
@@ -161,19 +168,12 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
}
|
||||
}
|
||||
|
||||
LookupElementFactory(resolutionFacade, receiverTypes, { expectedInfos })
|
||||
LookupElementFactory(resolutionFacade, receiverTypes, factoryContext, inDescriptor, { expectedInfos })
|
||||
}
|
||||
|
||||
private val collectorContext = if (expression?.getParent() is JetSimpleNameStringTemplateEntry)
|
||||
LookupElementsCollector.Context.STRING_TEMPLATE_AFTER_DOLLAR
|
||||
else if (receiversData?.callType == CallType.INFIX)
|
||||
LookupElementsCollector.Context.INFIX_CALL
|
||||
else
|
||||
LookupElementsCollector.Context.NORMAL
|
||||
|
||||
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
|
||||
protected val collector: LookupElementsCollector by lazy {
|
||||
LookupElementsCollector(prefixMatcher, parameters, resultSet, resolutionFacade, lookupElementFactory, createSorter(), inDescriptor, collectorContext)
|
||||
LookupElementsCollector(prefixMatcher, parameters, resultSet, lookupElementFactory, createSorter())
|
||||
}
|
||||
|
||||
protected val originalSearchScope: GlobalSearchScope = getResolveScope(parameters.getOriginalFile() as JetFile)
|
||||
|
||||
@@ -295,6 +295,7 @@ fun breakOrContinueExpressionItems(position: JetElement, breakOrContinue: String
|
||||
|
||||
fun LookupElementFactory.createBackingFieldLookupElement(
|
||||
property: PropertyDescriptor,
|
||||
useReceiverTypes: Boolean,
|
||||
inDescriptor: DeclarationDescriptor,
|
||||
resolutionFacade: ResolutionFacade
|
||||
): LookupElement? {
|
||||
@@ -312,7 +313,7 @@ fun LookupElementFactory.createBackingFieldLookupElement(
|
||||
val bindingContext = resolutionFacade.analyze(declaration)
|
||||
if (!bindingContext[BindingContext.BACKING_FIELD_REQUIRED, property]!!) return null
|
||||
|
||||
val lookupElement = createLookupElement(property, true)
|
||||
val lookupElement = createLookupElement(property, useReceiverTypes)
|
||||
return object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun getLookupString() = "$" + super.getLookupString()
|
||||
override fun getAllLookupStrings() = setOf(getLookupString())
|
||||
@@ -335,7 +336,7 @@ fun LookupElementFactory.createLookupElementForType(type: JetType): LookupElemen
|
||||
}
|
||||
else {
|
||||
val classifier = type.getConstructor().getDeclarationDescriptor() ?: return null
|
||||
val baseLookupElement = createLookupElement(classifier, false, qualifyNestedClasses = true, includeClassTypeArguments = false)
|
||||
val baseLookupElement = createLookupElement(classifier, useReceiverTypes = false, qualifyNestedClasses = true, includeClassTypeArguments = false)
|
||||
|
||||
val itemText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type)
|
||||
|
||||
|
||||
+2
-3
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
|
||||
@@ -87,7 +86,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,
|
||||
.filter { it.getName().asString() !in documentedParameters }
|
||||
|
||||
descriptors.forEach {
|
||||
collector.addElement(lookupElementFactory.createLookupElement(it, false))
|
||||
collector.addElement(lookupElementFactory.createLookupElement(it, useReceiverTypes = false))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +107,7 @@ class KDocNameCompletionSession(parameters: CompletionParameters,
|
||||
}
|
||||
|
||||
scope.getDescriptorsFiltered(nameFilter = descriptorNameFilter).filter(::isApplicable).forEach {
|
||||
val element = lookupElementFactory.createLookupElement(it, false)
|
||||
val element = lookupElementFactory.createLookupElement(it, useReceiverTypes = false)
|
||||
collector.addElement(object: LookupElementDecorator<LookupElement>(element) {
|
||||
override fun handleInsert(context: InsertionContext?) {
|
||||
// insert only plain name here, no qualifier/parentheses/etc.
|
||||
|
||||
+77
-2
@@ -17,11 +17,13 @@
|
||||
package org.jetbrains.kotlin.idea.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertHandler
|
||||
import com.intellij.codeInsight.completion.InsertionContext
|
||||
import com.intellij.codeInsight.lookup.*
|
||||
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.PlatformIcons
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -62,13 +64,86 @@ public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObj
|
||||
public class LookupElementFactory(
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val receiverTypes: Collection<JetType>,
|
||||
private val context: LookupElementFactory.Context,
|
||||
private val inDescriptor: DeclarationDescriptor?,
|
||||
expectedInfosCalculator: () -> Collection<ExpectedInfo>
|
||||
) {
|
||||
public enum class Context {
|
||||
NORMAL,
|
||||
STRING_TEMPLATE_AFTER_DOLLAR,
|
||||
INFIX_CALL
|
||||
}
|
||||
|
||||
private val expectedInfos by lazy { expectedInfosCalculator() }
|
||||
|
||||
public fun createStandardLookupElementsForDescriptor(descriptor: DeclarationDescriptor, useReceiverTypes: Boolean): Collection<LookupElement> {
|
||||
val result = SmartList<LookupElement>()
|
||||
|
||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||
if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR && (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
|
||||
if (context != Context.INFIX_CALL && descriptor is FunctionDescriptor) {
|
||||
result.addSpecialFunctionCallElements(descriptor, useReceiverTypes)
|
||||
}
|
||||
|
||||
if (descriptor is PropertyDescriptor && inDescriptor != null) {
|
||||
var backingFieldElement = createBackingFieldLookupElement(descriptor, useReceiverTypes, inDescriptor, resolutionFacade)
|
||||
if (backingFieldElement != null) {
|
||||
if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR) {
|
||||
backingFieldElement = backingFieldElement.withBracesSurrounding()
|
||||
}
|
||||
result.add(backingFieldElement)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun MutableCollection<LookupElement>.addSpecialFunctionCallElements(descriptor: FunctionDescriptor, useReceiverTypes: Boolean) {
|
||||
val singleParameter = descriptor.valueParameters.singleOrNull() ?: return
|
||||
val parameterType = singleParameter.type
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
||||
val functionParameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
||||
if (functionParameterCount > 1) {
|
||||
add(createFunctionCallElementWithExplicitLambdaParameters(descriptor, parameterType, useReceiverTypes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFunctionCallElementWithExplicitLambdaParameters(descriptor: FunctionDescriptor, parameterType: JetType, useReceiverTypes: Boolean): LookupElement {
|
||||
var lookupElement = createLookupElement(descriptor, useReceiverTypes)
|
||||
val needTypeArguments = (getDefaultInsertHandler(descriptor) as KotlinFunctionInsertHandler).needTypeArguments
|
||||
val lambdaInfo = GenerateLambdaInfo(parameterType, true)
|
||||
|
||||
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
|
||||
val tails = presentation.getTailFragments()
|
||||
presentation.clearTail()
|
||||
presentation.appendTailText(" " + buildLambdaPresentation(parameterType) + " ", false)
|
||||
tails.forEach { presentation.appendTailText(it.text, true) }
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = lambdaInfo).handleInsert(context, this)
|
||||
}
|
||||
}
|
||||
|
||||
if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR) {
|
||||
lookupElement = lookupElement.withBracesSurrounding()
|
||||
}
|
||||
|
||||
return lookupElement
|
||||
}
|
||||
|
||||
public fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor,
|
||||
boldImmediateMembers: Boolean,
|
||||
useReceiverTypes: Boolean,
|
||||
qualifyNestedClasses: Boolean = false,
|
||||
includeClassTypeArguments: Boolean = true
|
||||
): LookupElement {
|
||||
@@ -84,7 +159,7 @@ public class LookupElementFactory(
|
||||
element.putUserData(CALLABLE_WEIGHT_KEY, weight) // store for use in lookup elements sorting
|
||||
}
|
||||
|
||||
if (boldImmediateMembers) {
|
||||
if (useReceiverTypes) {
|
||||
element = element.boldIfImmediate(weight)
|
||||
}
|
||||
return element
|
||||
|
||||
+6
-79
@@ -19,35 +19,21 @@ package org.jetbrains.kotlin.idea.completion
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.patterns.ElementPattern
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithExpressionPrefixInsertHandler
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import java.util.*
|
||||
|
||||
class LookupElementsCollector(
|
||||
private val defaultPrefixMatcher: PrefixMatcher,
|
||||
private val completionParameters: CompletionParameters,
|
||||
resultSet: CompletionResultSet,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val lookupElementFactory: LookupElementFactory,
|
||||
private val sorter: CompletionSorter,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val context: LookupElementsCollector.Context
|
||||
private val sorter: CompletionSorter
|
||||
) {
|
||||
public enum class Context {
|
||||
NORMAL,
|
||||
STRING_TEMPLATE_AFTER_DOLLAR,
|
||||
INFIX_CALL
|
||||
}
|
||||
|
||||
private val elements = LinkedHashMap<PrefixMatcher, ArrayList<LookupElement>>()
|
||||
|
||||
@@ -89,73 +75,14 @@ class LookupElementsCollector(
|
||||
|
||||
public fun addDescriptorElements(descriptor: DeclarationDescriptor, notImported: Boolean = false, withReceiverCast: Boolean = false) {
|
||||
run {
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor, true)
|
||||
var lookupElements = lookupElementFactory.createStandardLookupElementsForDescriptor(descriptor, useReceiverTypes = true)
|
||||
|
||||
if (withReceiverCast) {
|
||||
lookupElement = lookupElement.withReceiverCast()
|
||||
lookupElements = lookupElements.map { it.withReceiverCast() }
|
||||
}
|
||||
|
||||
if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR && (descriptor is FunctionDescriptor || descriptor is ClassifierDescriptor)) {
|
||||
lookupElement = lookupElement.withBracesSurrounding()
|
||||
}
|
||||
|
||||
addElement(lookupElement, notImported = notImported)
|
||||
addElements(lookupElements, notImported = notImported)
|
||||
}
|
||||
|
||||
// add special item for function with one argument of function type with more than one parameter
|
||||
if (context != Context.INFIX_CALL && descriptor is FunctionDescriptor) {
|
||||
addSpecialFunctionDescriptorElementIfNeeded(descriptor)
|
||||
}
|
||||
|
||||
if (descriptor is PropertyDescriptor) {
|
||||
var lookupElement = lookupElementFactory.createBackingFieldLookupElement(descriptor, inDescriptor, resolutionFacade)
|
||||
if (lookupElement != null) {
|
||||
if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR) {
|
||||
lookupElement = lookupElement.withBracesSurrounding()
|
||||
}
|
||||
addElement(lookupElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSpecialFunctionDescriptorElementIfNeeded(descriptor: FunctionDescriptor) {
|
||||
val parameters = descriptor.getValueParameters()
|
||||
if (parameters.size() == 1) {
|
||||
val parameterType = parameters.get(0).getType()
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
||||
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
||||
if (parameterCount > 1) {
|
||||
addSpecialFunctionDescriptorElement(descriptor, parameterType)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSpecialFunctionDescriptorElement(descriptor: FunctionDescriptor, parameterType: JetType) {
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor, true)
|
||||
val needTypeArguments = (lookupElementFactory.getDefaultInsertHandler(descriptor) as KotlinFunctionInsertHandler).needTypeArguments
|
||||
val lambdaInfo = GenerateLambdaInfo(parameterType, true)
|
||||
|
||||
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
|
||||
val tails = presentation.getTailFragments()
|
||||
presentation.clearTail()
|
||||
presentation.appendTailText(" " + buildLambdaPresentation(parameterType) + " ", false)
|
||||
tails.forEach { presentation.appendTailText(it.text, true) }
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = lambdaInfo).handleInsert(context, this)
|
||||
}
|
||||
}
|
||||
|
||||
if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR) {
|
||||
lookupElement = lookupElement.withBracesSurrounding()
|
||||
}
|
||||
|
||||
addElement(lookupElement)
|
||||
}
|
||||
|
||||
public fun addElement(element: LookupElement, prefixMatcher: PrefixMatcher = defaultPrefixMatcher, notImported: Boolean = false) {
|
||||
|
||||
+2
-1
@@ -53,8 +53,9 @@ object PackageDirectiveCompletion {
|
||||
val bindingContext = resolutionFacade.analyze(expression)
|
||||
|
||||
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter())
|
||||
val lookupElementFactory = LookupElementFactory(resolutionFacade, emptyList(), LookupElementFactory.Context.NORMAL, null, { emptyList() })
|
||||
for (variant in variants) {
|
||||
val lookupElement = LookupElementFactory(resolutionFacade, emptyList(), { emptyList() }).createLookupElement(variant, false)
|
||||
val lookupElement = lookupElementFactory.createLookupElement(variant, useReceiverTypes = false)
|
||||
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
|
||||
result.addElement(lookupElement)
|
||||
}
|
||||
|
||||
+1
-1
@@ -170,7 +170,7 @@ class ParameterNameAndTypeCompletion(
|
||||
|
||||
private class DescriptorType(private val classifier: ClassifierDescriptor) : Type(IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classifier)) {
|
||||
override fun createTypeLookupElement(lookupElementFactory: LookupElementFactory)
|
||||
= lookupElementFactory.createLookupElement(classifier, false, qualifyNestedClasses = true)
|
||||
= lookupElementFactory.createLookupElement(classifier, useReceiverTypes = false, qualifyNestedClasses = true)
|
||||
}
|
||||
|
||||
private class JavaClassType(private val psiClass: PsiClass) : Type(psiClass.getQualifiedName()!!) {
|
||||
|
||||
+4
-3
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.typeUtil.isBooleanOrNullableBoolean
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
object KeywordValues {
|
||||
public fun addToCollection(collection: MutableCollection<LookupElement>, expectedInfos: Collection<ExpectedInfo>, expressionWithType: JetExpression) {
|
||||
@@ -54,8 +55,8 @@ object KeywordValues {
|
||||
val booleanInfoClassifier = { info: ExpectedInfo ->
|
||||
if (info.fuzzyType?.type?.isBooleanOrNullableBoolean() ?: false) ExpectedInfoClassification.match(TypeSubstitutor.EMPTY) else ExpectedInfoClassification.noMatch
|
||||
}
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier) { LookupElementBuilder.create("true").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.TRUE) }
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier) { LookupElementBuilder.create("false").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.FALSE) }
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier) { LookupElementBuilder.create("true").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.TRUE).singletonList() }
|
||||
collection.addLookupElements(null, expectedInfos, booleanInfoClassifier) { LookupElementBuilder.create("false").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.FALSE).singletonList() }
|
||||
}
|
||||
|
||||
if (!shouldSkipNull(expressionWithType)) {
|
||||
@@ -66,7 +67,7 @@ object KeywordValues {
|
||||
ExpectedInfoClassification.noMatch
|
||||
}
|
||||
collection.addLookupElements(null, expectedInfos, classifier) {
|
||||
LookupElementBuilder.create("null").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.NULL)
|
||||
LookupElementBuilder.create("null").bold().assignSmartCompletionPriority(SmartCompletionItemPriority.NULL).singletonList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-11
@@ -40,9 +40,9 @@ import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptySet
|
||||
import java.util.ArrayList
|
||||
import java.util.HashSet
|
||||
import java.util.*
|
||||
|
||||
interface InheritanceItemsSearcher {
|
||||
fun search(nameFilter: (String) -> Boolean, consumer: (LookupElement) -> Unit)
|
||||
@@ -146,13 +146,7 @@ class SmartCompletion(
|
||||
val infoClassifier = { expectedInfo: ExpectedInfo -> types.classifyExpectedInfo(expectedInfo) }
|
||||
|
||||
result.addLookupElements(descriptor, expectedInfos, infoClassifier, noNameSimilarityForReturnItself = receiver == null) { descriptor ->
|
||||
lookupElementFactory.createLookupElement(descriptor, bindingContext, true)
|
||||
}
|
||||
|
||||
if (descriptor is PropertyDescriptor) {
|
||||
result.addLookupElements(descriptor, expectedInfos, infoClassifier) { descriptor ->
|
||||
lookupElementFactory.createBackingFieldLookupElement(descriptor, inDescriptor, resolutionFacade)
|
||||
}
|
||||
lookupElementFactory.createLookupElementsInSmartCompletion(descriptor, bindingContext, true)
|
||||
}
|
||||
|
||||
if (receiver == null) {
|
||||
@@ -232,7 +226,7 @@ class SmartCompletion(
|
||||
val types = smartCastCalculator.types(item.receiverParameter).map { FuzzyType(it, emptyList()) }
|
||||
val classifier = { expectedInfo: ExpectedInfo -> types.classifyExpectedInfo(expectedInfo) }
|
||||
addLookupElements(null, expectedInfos, classifier) {
|
||||
item.createLookupElement().assignSmartCompletionPriority(SmartCompletionItemPriority.THIS)
|
||||
item.createLookupElement().assignSmartCompletionPriority(SmartCompletionItemPriority.THIS).singletonList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,7 +281,7 @@ class SmartCompletion(
|
||||
val matchedExpectedInfos = functionExpectedInfos.filter { it.matchingSubstitutor(functionType) != null }
|
||||
if (matchedExpectedInfos.isEmpty()) return null
|
||||
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor, bindingContext, true)
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor, useReceiverTypes = false)
|
||||
val text = "::" + (if (descriptor is ConstructorDescriptor) descriptor.getContainingDeclaration().getName() else descriptor.getName())
|
||||
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun getLookupString() = text
|
||||
|
||||
+34
-32
@@ -82,7 +82,7 @@ class StaticMembers(
|
||||
}
|
||||
|
||||
collection.addLookupElements(descriptor, expectedInfos, classifier) {
|
||||
descriptor -> createLookupElement(descriptor, classDescriptor)
|
||||
descriptor -> createLookupElements(descriptor, classDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,46 +102,48 @@ class StaticMembers(
|
||||
members.forEach(::processMember)
|
||||
}
|
||||
|
||||
private fun createLookupElement(memberDescriptor: DeclarationDescriptor, classDescriptor: ClassDescriptor): LookupElement {
|
||||
val lookupElement = lookupElementFactory.createLookupElement(memberDescriptor, bindingContext, false)
|
||||
private fun createLookupElements(memberDescriptor: DeclarationDescriptor, classDescriptor: ClassDescriptor): Collection<LookupElement> {
|
||||
val lookupElements = lookupElementFactory.createLookupElementsInSmartCompletion(memberDescriptor, bindingContext, useReceiverTypes = false)
|
||||
val qualifierPresentation = classDescriptor.getName().asString()
|
||||
val qualifierText = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classDescriptor)
|
||||
|
||||
return object: LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun getAllLookupStrings(): Set<String> {
|
||||
return setOf(lookupElement.getLookupString(), qualifierPresentation)
|
||||
}
|
||||
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
getDelegate().renderElement(presentation)
|
||||
|
||||
presentation.setItemText(qualifierPresentation + "." + presentation.getItemText())
|
||||
|
||||
val tailText = " (" + DescriptorUtils.getFqName(classDescriptor.getContainingDeclaration()) + ")"
|
||||
if (memberDescriptor is FunctionDescriptor) {
|
||||
presentation.appendTailText(tailText, true)
|
||||
}
|
||||
else {
|
||||
presentation.setTailText(tailText, true)
|
||||
return lookupElements.map {
|
||||
object: LookupElementDecorator<LookupElement>(it) {
|
||||
override fun getAllLookupStrings(): Set<String> {
|
||||
return setOf(it.lookupString, qualifierPresentation)
|
||||
}
|
||||
|
||||
if (presentation.getTypeText().isNullOrEmpty()) {
|
||||
presentation.setTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(classDescriptor.getDefaultType()))
|
||||
}
|
||||
}
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
getDelegate().renderElement(presentation)
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
var text = qualifierText + "." + memberDescriptor.getName().render()
|
||||
presentation.setItemText(qualifierPresentation + "." + presentation.getItemText())
|
||||
|
||||
context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), text)
|
||||
context.setTailOffset(context.getStartOffset() + text.length())
|
||||
val tailText = " (" + DescriptorUtils.getFqName(classDescriptor.getContainingDeclaration()) + ")"
|
||||
if (memberDescriptor is FunctionDescriptor) {
|
||||
presentation.appendTailText(tailText, true)
|
||||
}
|
||||
else {
|
||||
presentation.setTailText(tailText, true)
|
||||
}
|
||||
|
||||
if (memberDescriptor is FunctionDescriptor) {
|
||||
getDelegate().handleInsert(context)
|
||||
if (presentation.getTypeText().isNullOrEmpty()) {
|
||||
presentation.setTypeText(DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(classDescriptor.getDefaultType()))
|
||||
}
|
||||
}
|
||||
|
||||
shortenReferences(context, context.getStartOffset(), context.getTailOffset())
|
||||
}
|
||||
}.assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER)
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
var text = qualifierText + "." + memberDescriptor.getName().render()
|
||||
|
||||
context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), text)
|
||||
context.setTailOffset(context.getStartOffset() + text.length())
|
||||
|
||||
if (memberDescriptor is FunctionDescriptor) {
|
||||
getDelegate().handleInsert(context)
|
||||
}
|
||||
|
||||
shortenReferences(context, context.getStartOffset(), context.getTailOffset())
|
||||
}
|
||||
}.assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -123,7 +123,7 @@ class TypeInstantiationItems(
|
||||
typeArgs: List<TypeProjection>,
|
||||
tail: Tail?
|
||||
): LookupElement? {
|
||||
var lookupElement = lookupElementFactory.createLookupElement(classifier, bindingContext, false)
|
||||
var lookupElement = lookupElementFactory.createLookupElement(classifier, useReceiverTypes = false)
|
||||
|
||||
if (DescriptorUtils.isNonCompanionObject(classifier)) {
|
||||
return lookupElement.addTail(tail)
|
||||
@@ -255,10 +255,10 @@ class TypeInstantiationItems(
|
||||
val samConstructor = scope.getFunctions(`class`.name, NoLookupLocation.FROM_IDE)
|
||||
.filterIsInstance<SamConstructorDescriptor>()
|
||||
.singleOrNull() ?: return
|
||||
val lookupElement = lookupElementFactory.createLookupElement(samConstructor, bindingContext, false)
|
||||
.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION)
|
||||
.addTail(tail)
|
||||
collection.add(lookupElement)
|
||||
lookupElementFactory.createLookupElementsInSmartCompletion(samConstructor, bindingContext, useReceiverTypes = false)
|
||||
.mapTo(collection) {
|
||||
it.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION).addTail(tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,7 @@ import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import java.util.*
|
||||
|
||||
class ArtificialElementInsertHandler(
|
||||
val textBeforeCaret: String, val textAfterCaret: String, val shortenRefs: Boolean) : InsertHandler<LookupElement>{
|
||||
@@ -155,7 +154,7 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
infoClassifier: (ExpectedInfo) -> ExpectedInfoClassification,
|
||||
noNameSimilarityForReturnItself: Boolean = false,
|
||||
lookupElementFactory: (TDescriptor) -> LookupElement?
|
||||
lookupElementFactory: (TDescriptor) -> Collection<LookupElement>
|
||||
) {
|
||||
class ItemData(val descriptor: TDescriptor, val itemOptions: ItemOptions) {
|
||||
override fun equals(other: Any?)
|
||||
@@ -163,7 +162,7 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
override fun hashCode() = if (this.descriptor != null) this.descriptor.getOriginal().hashCode() else 0
|
||||
}
|
||||
|
||||
fun ItemData.createLookupElement() = lookupElementFactory(this.descriptor)?.withOptions(this.itemOptions)
|
||||
fun ItemData.createLookupElements() = lookupElementFactory(this.descriptor).map { it.withOptions(this.itemOptions) }
|
||||
|
||||
val matchedInfos = HashMap<ItemData, MutableList<ExpectedInfo>>()
|
||||
val makeNullableInfos = HashMap<ItemData, MutableList<ExpectedInfo>>()
|
||||
@@ -179,20 +178,18 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
|
||||
if (!matchedInfos.isEmpty()) {
|
||||
for ((itemData, infos) in matchedInfos) {
|
||||
val lookupElement = itemData.createLookupElement()
|
||||
if (lookupElement != null) {
|
||||
val nameSimilarityInfos = if (noNameSimilarityForReturnItself && descriptor is CallableDescriptor) {
|
||||
infos.filter { (it.additionalData as? ReturnValueAdditionalData)?.callable != descriptor } // do not calculate name similarity with function itself in its return
|
||||
}
|
||||
else
|
||||
infos
|
||||
add(lookupElement.addTailAndNameSimilarity(infos, nameSimilarityInfos))
|
||||
val lookupElements = itemData.createLookupElements()
|
||||
val nameSimilarityInfos = if (noNameSimilarityForReturnItself && descriptor is CallableDescriptor) {
|
||||
infos.filter { (it.additionalData as? ReturnValueAdditionalData)?.callable != descriptor } // do not calculate name similarity with function itself in its return
|
||||
}
|
||||
else
|
||||
infos
|
||||
lookupElements.mapTo(this) { it.addTailAndNameSimilarity(infos, nameSimilarityInfos) }
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ((itemData, infos) in makeNullableInfos) {
|
||||
addLookupElementsForNullable({ itemData.createLookupElement() }, infos)
|
||||
addLookupElementsForNullable({ itemData.createLookupElements() }, infos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,18 +201,17 @@ private fun <T : DeclarationDescriptor?> T.substituteFixed(substitutor: TypeSubs
|
||||
return this?.substitute(substitutor) as T
|
||||
}
|
||||
|
||||
private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factory: () -> LookupElement?, matchedInfos: Collection<ExpectedInfo>) {
|
||||
for (element in lookupElementsForNullable(factory)) {
|
||||
add(element.addTailAndNameSimilarity(matchedInfos))
|
||||
private fun MutableCollection<LookupElement>.addLookupElementsForNullable(factory: () -> Collection<LookupElement>, matchedInfos: Collection<ExpectedInfo>) {
|
||||
fun LookupElement.postProcess(): LookupElement {
|
||||
var element = this
|
||||
element = element.suppressAutoInsertion()
|
||||
element = element.assignSmartCompletionPriority(SmartCompletionItemPriority.NULLABLE)
|
||||
element = element.addTailAndNameSimilarity(matchedInfos)
|
||||
return element
|
||||
}
|
||||
}
|
||||
|
||||
private fun lookupElementsForNullable(factory: () -> LookupElement?): Collection<LookupElement> {
|
||||
val result = ArrayList<LookupElement>(2)
|
||||
|
||||
var lookupElement = factory()
|
||||
if (lookupElement != null) {
|
||||
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
factory().mapTo(this) {
|
||||
object: LookupElementDecorator<LookupElement>(it) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.setItemText("!! " + presentation.getItemText())
|
||||
@@ -223,15 +219,11 @@ private fun lookupElementsForNullable(factory: () -> LookupElement?): Collection
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler("!!", spaceBefore = false, spaceAfter = false).handleInsert(context, getDelegate())
|
||||
}
|
||||
}
|
||||
lookupElement = lookupElement!!.suppressAutoInsertion()
|
||||
lookupElement = lookupElement!!.assignSmartCompletionPriority(SmartCompletionItemPriority.NULLABLE)
|
||||
result.add(lookupElement!!)
|
||||
}.postProcess()
|
||||
}
|
||||
|
||||
lookupElement = factory()
|
||||
if (lookupElement != null) {
|
||||
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement!!) {
|
||||
factory().mapTo(this) {
|
||||
object: LookupElementDecorator<LookupElement>(it) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.setItemText("?: " + presentation.getItemText())
|
||||
@@ -239,13 +231,8 @@ private fun lookupElementsForNullable(factory: () -> LookupElement?): Collection
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
WithTailInsertHandler("?:", spaceBefore = true, spaceAfter = true).handleInsert(context, getDelegate()) //TODO: code style
|
||||
}
|
||||
}
|
||||
lookupElement = lookupElement!!.suppressAutoInsertion()
|
||||
lookupElement = lookupElement!!.assignSmartCompletionPriority(SmartCompletionItemPriority.NULLABLE)
|
||||
result.add(lookupElement!!)
|
||||
}.postProcess()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun functionType(function: FunctionDescriptor): JetType? {
|
||||
@@ -274,22 +261,24 @@ fun functionType(function: FunctionDescriptor): JetType? {
|
||||
)
|
||||
}
|
||||
|
||||
fun LookupElementFactory.createLookupElement(
|
||||
fun LookupElementFactory.createLookupElementsInSmartCompletion(
|
||||
descriptor: DeclarationDescriptor,
|
||||
bindingContext: BindingContext,
|
||||
boldImmediateMembers: Boolean
|
||||
): LookupElement {
|
||||
var element = createLookupElement(descriptor, boldImmediateMembers)
|
||||
useReceiverTypes: Boolean
|
||||
): Collection<LookupElement> {
|
||||
return createStandardLookupElementsForDescriptor(descriptor, useReceiverTypes).map {
|
||||
var element = it
|
||||
|
||||
if (descriptor is FunctionDescriptor && descriptor.getValueParameters().isNotEmpty()) {
|
||||
element = element.keepOldArgumentListOnTab()
|
||||
if (descriptor is FunctionDescriptor && descriptor.valueParameters.isNotEmpty()) {
|
||||
element = element.keepOldArgumentListOnTab()
|
||||
}
|
||||
|
||||
if (descriptor is ValueParameterDescriptor && bindingContext[BindingContext.AUTO_CREATED_IT, descriptor]!!) {
|
||||
element = element.assignSmartCompletionPriority(SmartCompletionItemPriority.IT)
|
||||
}
|
||||
|
||||
element
|
||||
}
|
||||
|
||||
if (descriptor is ValueParameterDescriptor && bindingContext[BindingContext.AUTO_CREATED_IT, descriptor]!!) {
|
||||
element = element.assignSmartCompletionPriority(SmartCompletionItemPriority.IT)
|
||||
}
|
||||
|
||||
return element
|
||||
}
|
||||
|
||||
enum class SmartCompletionItemPriority {
|
||||
|
||||
@@ -11,3 +11,4 @@ fun foo(){
|
||||
}
|
||||
|
||||
// ELEMENT: bar
|
||||
// TAIL_TEXT: "(p: (Int, String) -> Unit) (sample)"
|
||||
|
||||
@@ -11,3 +11,4 @@ fun foo(){
|
||||
}
|
||||
|
||||
// ELEMENT: bar
|
||||
// TAIL_TEXT: "(p: (Int, String) -> Unit) (sample)"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
fun foo(p: (String, Char) -> Unit): String {}
|
||||
|
||||
fun v: String = fo<caret>
|
||||
|
||||
// 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" }
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.util.Comparator
|
||||
|
||||
var v: Comparator<String> = <caret>
|
||||
|
||||
// EXIST: { itemText: "object: Comparator<String>{...}" }
|
||||
// EXIST: { lookupString: "Comparator", itemText: "Comparator", tailText: "(function: (T!, T!) -> Int) (java.util)", typeText: "Comparator<T>" }
|
||||
// EXIST: { lookupString: "Comparator", itemText: "Comparator", tailText: " { T, T -> ... } (function: (T!, T!) -> Int) (java.util)", typeText: "Comparator<T>" }
|
||||
+12
@@ -143,6 +143,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("HighOrderFunction.kt")
|
||||
public void testHighOrderFunction() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/HighOrderFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("IfCondition.kt")
|
||||
public void testIfCondition() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/IfCondition.kt");
|
||||
@@ -425,6 +431,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SAMExpected2.kt")
|
||||
public void testSAMExpected2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SAMExpected2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SkipDeclarationsOfType.kt")
|
||||
public void testSkipDeclarationsOfType() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SkipDeclarationsOfType.kt");
|
||||
|
||||
Reference in New Issue
Block a user