Basic completion shows items from smart completion after "as" + do not insert any tail in basic completion
This commit is contained in:
+20
-15
@@ -30,8 +30,9 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SMART_COMPLETION_ITEM_PRIORITY_KEY
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletion
|
||||
import org.jetbrains.kotlin.idea.completion.smart.toExpressionWithType
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletionItemPriority
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -95,13 +96,9 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
else
|
||||
null
|
||||
|
||||
private val expectedInfos = if (expression != null)
|
||||
ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor).calculate(expression.toExpressionWithType())
|
||||
else
|
||||
null
|
||||
|
||||
private val smartCompletion = expression?.let {
|
||||
SmartCompletion(it, resolutionFacade, moduleDescriptor, bindingContext, isVisibleFilter, inDescriptor, prefixMatcher, GlobalSearchScope.EMPTY_SCOPE, toFromOriginalFileMapper, lookupElementFactory)
|
||||
SmartCompletion(it, resolutionFacade, moduleDescriptor, bindingContext, isVisibleFilter, inDescriptor, prefixMatcher,
|
||||
GlobalSearchScope.EMPTY_SCOPE, toFromOriginalFileMapper, lookupElementFactory, forBasicCompletion = true)
|
||||
}
|
||||
|
||||
private fun calcCompletionKind(): CompletionKind {
|
||||
@@ -198,6 +195,20 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
}
|
||||
|
||||
if (completionKind != CompletionKind.NAMED_ARGUMENTS_ONLY) {
|
||||
if (smartCompletion != null) {
|
||||
@suppress("UNUSED_VARIABLE") // we don't use InheritanceSearcher
|
||||
val (additionalItems, inheritanceSearcher) = smartCompletion.additionalItems()
|
||||
|
||||
// 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.addDescriptorElements(referenceVariants, suppressAutoInsertion = false)
|
||||
|
||||
val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc
|
||||
@@ -251,12 +262,6 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
}
|
||||
|
||||
if (completionKind != CompletionKind.KEYWORDS_ONLY) {
|
||||
if (smartCompletion != null && expectedInfos != null && expectedInfos.isNotEmpty()) {
|
||||
@suppress("UNUSED_VARIABLE") // we don't use InheritanceSearcher
|
||||
val (additionalItems, inheritanceSearcher) = smartCompletion.additionalItems(expectedInfos, forOrdinaryCompletion = true)
|
||||
collector.addElements(additionalItems)
|
||||
}
|
||||
|
||||
flushToResultSet()
|
||||
|
||||
if (!configuration.completeNonImportedDeclarations && isNoQualifierContext()) {
|
||||
@@ -300,8 +305,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
sorter = sorter.weighBefore(DeprecatedWeigher.toString(), ParameterNameAndTypeCompletion.Weigher)
|
||||
}
|
||||
|
||||
if (smartCompletion != null && expectedInfos != null && expectedInfos.isNotEmpty()) {
|
||||
sorter = sorter.weighBefore(KindWeigher.toString(), ExpectedInfoMatchWeigher(expectedInfos, smartCompletion), SmartCompletionPriorityWeigher)
|
||||
if (smartCompletion != null) {
|
||||
sorter = sorter.weighBefore(KindWeigher.toString(), SmartCompletionInBasicWeigher(smartCompletion), SmartCompletionPriorityWeigher)
|
||||
}
|
||||
|
||||
return sorter
|
||||
|
||||
@@ -315,17 +315,23 @@ fun LookupElementFactory.createLookupElementForType(type: JetType): LookupElemen
|
||||
|
||||
val itemText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type)
|
||||
|
||||
return object : BaseTypeLookupElement(type, baseLookupElement) {
|
||||
val typeLookupElement = object : BaseTypeLookupElement(type, baseLookupElement) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.setItemText(itemText)
|
||||
}
|
||||
}
|
||||
|
||||
// if type is simply classifier without anything else, use classifier's lookup element to avoid duplicates (works after "as" in basic completion)
|
||||
return if (typeLookupElement.fullText == IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classifier))
|
||||
baseLookupElement
|
||||
else
|
||||
typeLookupElement
|
||||
}
|
||||
}
|
||||
|
||||
private open class BaseTypeLookupElement(type: JetType, baseLookupElement: LookupElement) : LookupElementDecorator<LookupElement>(baseLookupElement) {
|
||||
private val fullText = IdeDescriptorRenderers.SOURCE_CODE.renderType(type)
|
||||
val fullText = IdeDescriptorRenderers.SOURCE_CODE.renderType(type)
|
||||
|
||||
override fun equals(other: Any?) = other is BaseTypeLookupElement && fullText == other.fullText
|
||||
override fun hashCode() = fullText.hashCode()
|
||||
|
||||
@@ -86,16 +86,36 @@ class ByExpectedTypeFilter(val fuzzyType: FuzzyType) : ByTypeFilter {
|
||||
override fun hashCode() = fuzzyType.hashCode()
|
||||
}
|
||||
|
||||
open data class ExpectedInfo(val filter: ByTypeFilter, val expectedName: String?, val tail: Tail?, val itemOptions: ItemOptions = ItemOptions.DEFAULT) {
|
||||
constructor(fuzzyType: FuzzyType, expectedName: String?, tail: Tail?, itemOptions: ItemOptions = ItemOptions.DEFAULT)
|
||||
: this(ByExpectedTypeFilter(fuzzyType), expectedName, tail, itemOptions)
|
||||
data class ExpectedInfo(
|
||||
val filter: ByTypeFilter,
|
||||
val expectedName: String?,
|
||||
val tail: Tail?,
|
||||
val itemOptions: ItemOptions = ItemOptions.DEFAULT,
|
||||
val additionalData: ExpectedInfo.AdditionalData? = null
|
||||
) {
|
||||
// just a marker interface
|
||||
interface AdditionalData {}
|
||||
|
||||
constructor(type: JetType, expectedName: String?, tail: Tail?, itemOptions: ItemOptions = ItemOptions.DEFAULT)
|
||||
: this(FuzzyType(type, emptyList()), expectedName, tail, itemOptions)
|
||||
constructor(fuzzyType: FuzzyType, expectedName: String?, tail: Tail?, itemOptions: ItemOptions = ItemOptions.DEFAULT, additionalData: ExpectedInfo.AdditionalData? = null)
|
||||
: this(ByExpectedTypeFilter(fuzzyType), expectedName, tail, itemOptions, additionalData)
|
||||
|
||||
constructor(type: JetType, expectedName: String?, tail: Tail?, itemOptions: ItemOptions = ItemOptions.DEFAULT, additionalData: ExpectedInfo.AdditionalData? = null)
|
||||
: this(FuzzyType(type, emptyList()), expectedName, tail, itemOptions, additionalData)
|
||||
|
||||
fun matchingSubstitutor(descriptorType: FuzzyType): TypeSubstitutor? = filter.matchingSubstitutor(descriptorType)
|
||||
|
||||
fun matchingSubstitutor(descriptorType: JetType): TypeSubstitutor? = matchingSubstitutor(FuzzyType(descriptorType, emptyList()))
|
||||
|
||||
companion object {
|
||||
fun createForArgument(type: JetType, name: String?, tail: Tail?, function: FunctionDescriptor, position: ArgumentPosition, itemOptions: ItemOptions = ItemOptions.DEFAULT): ExpectedInfo {
|
||||
return ExpectedInfo(FuzzyType(type, function.typeParameters), name, tail, itemOptions, ArgumentAdditionalData(function, position))
|
||||
}
|
||||
|
||||
fun createForReturnValue(type: JetType?, callable: CallableDescriptor): ExpectedInfo {
|
||||
val filter = if (type != null) ByExpectedTypeFilter(FuzzyType(type, emptyList())) else ByTypeFilter.All
|
||||
return ExpectedInfo(filter, callable.name.asString(), null, additionalData = ReturnValueAdditionalData(callable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ExpectedInfo.fuzzyType: FuzzyType?
|
||||
@@ -106,26 +126,17 @@ data class ArgumentPosition(val argumentIndex: Int, val argumentName: Name?, val
|
||||
constructor(argumentIndex: Int, argumentName: Name?) : this(argumentIndex, argumentName, false)
|
||||
}
|
||||
|
||||
class ArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?, val function: FunctionDescriptor, val position: ArgumentPosition, itemOptions: ItemOptions = ItemOptions.DEFAULT)
|
||||
: ExpectedInfo(FuzzyType(type, function.typeParameters), name, tail, itemOptions) {
|
||||
|
||||
class ArgumentAdditionalData(val function: FunctionDescriptor, val position: ArgumentPosition) : ExpectedInfo.AdditionalData {
|
||||
override fun equals(other: Any?)
|
||||
= other is ArgumentExpectedInfo && super.equals(other) && function == other.function && position == other.position
|
||||
= other is ArgumentAdditionalData && function == other.function && position == other.position
|
||||
|
||||
override fun hashCode()
|
||||
= function.hashCode()
|
||||
}
|
||||
|
||||
class ReturnValueExpectedInfo(
|
||||
type: JetType?,
|
||||
val callable: CallableDescriptor
|
||||
) : ExpectedInfo(
|
||||
if (type != null) ByExpectedTypeFilter(FuzzyType(type, emptyList())) else ByTypeFilter.All,
|
||||
callable.name.asString(),
|
||||
null
|
||||
) {
|
||||
class ReturnValueAdditionalData(val callable: CallableDescriptor) : ExpectedInfo.AdditionalData {
|
||||
override fun equals(other: Any?)
|
||||
= other is ReturnValueExpectedInfo && super.equals(other) && callable == other.callable
|
||||
= other is ReturnValueAdditionalData && callable == other.callable
|
||||
|
||||
override fun hashCode()
|
||||
= callable.hashCode()
|
||||
@@ -180,7 +191,14 @@ class ExpectedInfos(
|
||||
public fun calculateForArgument(call: Call, argument: ValueArgument): Collection<ExpectedInfo>? {
|
||||
val results = calculateForArgument(call, TypeUtils.NO_EXPECTED_TYPE, argument) ?: return null
|
||||
|
||||
if (useOuterCallsExpectedTypeCount > 0 && results.any { it.fuzzyType != null && it.fuzzyType!!.freeParameters.isNotEmpty() && it.function.fuzzyReturnType()?.freeParameters?.isNotEmpty() ?: false }) {
|
||||
fun makesSenseToUseOuterCallExpectedType(info: ExpectedInfo): Boolean {
|
||||
val data = info.additionalData as ArgumentAdditionalData
|
||||
return info.fuzzyType != null
|
||||
&& info.fuzzyType!!.freeParameters.isNotEmpty()
|
||||
&& data.function.fuzzyReturnType()?.freeParameters?.isNotEmpty() ?: false
|
||||
}
|
||||
|
||||
if (useOuterCallsExpectedTypeCount > 0 && results.any(::makesSenseToUseOuterCallExpectedType)) {
|
||||
val callExpression = (call.callElement as? JetExpression)?.getQualifiedExpressionForSelectorOrThis() ?: return results
|
||||
val expectedFuzzyTypes = ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, useHeuristicSignatures, useOuterCallsExpectedTypeCount - 1)
|
||||
.calculate(callExpression)
|
||||
@@ -198,7 +216,7 @@ class ExpectedInfos(
|
||||
return results
|
||||
}
|
||||
|
||||
private fun calculateForArgument(call: Call, callExpectedType: JetType, argument: ValueArgument): Collection<ArgumentExpectedInfo>? {
|
||||
private fun calculateForArgument(call: Call, callExpectedType: JetType, argument: ValueArgument): Collection<ExpectedInfo>? {
|
||||
val argumentIndex = call.getValueArguments().indexOf(argument)
|
||||
assert(argumentIndex >= 0) {
|
||||
"Could not find argument '$argument' among arguments of call: $call"
|
||||
@@ -229,7 +247,7 @@ class ExpectedInfos(
|
||||
val callResolver = createContainerForMacros(project, moduleDescriptor).callResolver
|
||||
val results: OverloadResolutionResults<FunctionDescriptor> = callResolver.resolveFunctionCall(callResolutionContext)
|
||||
|
||||
val expectedInfos = LinkedHashSet<ArgumentExpectedInfo>()
|
||||
val expectedInfos = LinkedHashSet<ExpectedInfo>()
|
||||
for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) {
|
||||
val status = candidate.getStatus()
|
||||
if (status == ResolutionStatus.RECEIVER_TYPE_ERROR || status == ResolutionStatus.RECEIVER_PRESENCE_ERROR) continue
|
||||
@@ -289,11 +307,11 @@ class ExpectedInfos(
|
||||
tail
|
||||
|
||||
if (!alreadyHasStar) {
|
||||
expectedInfos.add(ArgumentExpectedInfo(varargElementType, expectedName?.unpluralize(), varargTail, descriptor, argumentPosition))
|
||||
expectedInfos.add(ExpectedInfo.createForArgument(varargElementType, expectedName?.unpluralize(), varargTail, descriptor, argumentPosition))
|
||||
}
|
||||
|
||||
val starOptions = if (!alreadyHasStar) ItemOptions.STAR_PREFIX else ItemOptions.DEFAULT
|
||||
expectedInfos.add(ArgumentExpectedInfo(parameter.getType(), expectedName, varargTail, descriptor, argumentPosition, starOptions))
|
||||
expectedInfos.add(ExpectedInfo.createForArgument(parameter.getType(), expectedName, varargTail, descriptor, argumentPosition, starOptions))
|
||||
}
|
||||
else {
|
||||
if (alreadyHasStar) continue
|
||||
@@ -305,11 +323,11 @@ class ExpectedInfos(
|
||||
|
||||
if (isFunctionLiteralArgument) {
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
||||
expectedInfos.add(ArgumentExpectedInfo(parameterType, expectedName, null, descriptor, argumentPosition))
|
||||
expectedInfos.add(ExpectedInfo.createForArgument(parameterType, expectedName, null, descriptor, argumentPosition))
|
||||
}
|
||||
}
|
||||
else {
|
||||
expectedInfos.add(ArgumentExpectedInfo(parameterType, expectedName, tail, descriptor, argumentPosition))
|
||||
expectedInfos.add(ExpectedInfo.createForArgument(parameterType, expectedName, tail, descriptor, argumentPosition))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,18 +475,18 @@ class ExpectedInfos(
|
||||
return functionReturnValueExpectedInfo(descriptor, expectType = true).singletonOrEmptyList()
|
||||
}
|
||||
|
||||
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor, expectType: Boolean): ReturnValueExpectedInfo? {
|
||||
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor, expectType: Boolean): ExpectedInfo? {
|
||||
return when (descriptor) {
|
||||
is SimpleFunctionDescriptor -> {
|
||||
val expectedType = if (expectType) descriptor.returnType else null
|
||||
ReturnValueExpectedInfo(expectedType, descriptor)
|
||||
ExpectedInfo.createForReturnValue(expectedType, descriptor)
|
||||
}
|
||||
|
||||
is PropertyGetterDescriptor -> {
|
||||
if (descriptor !is PropertyGetterDescriptor) return null
|
||||
val property = descriptor.getCorrespondingProperty()
|
||||
val expectedType = if (expectType) property.type else null
|
||||
ReturnValueExpectedInfo(expectedType, property)
|
||||
ExpectedInfo.createForReturnValue(expectedType, property)
|
||||
}
|
||||
|
||||
else -> null
|
||||
|
||||
@@ -186,13 +186,9 @@ class DeclarationRemotenessWeigher(private val file: JetFile) : LookupElementWei
|
||||
}
|
||||
}
|
||||
|
||||
class ExpectedInfoMatchWeigher(
|
||||
private val expectedInfos: Collection<ExpectedInfo>,
|
||||
private val smartCompletion: SmartCompletion
|
||||
) : LookupElementWeigher("kotlin.expectedInfoMatch") {
|
||||
|
||||
private val smartCastCalculator = smartCompletion.smartCastCalculator
|
||||
class SmartCompletionInBasicWeigher(private val smartCompletion: SmartCompletion) : LookupElementWeigher("kotlin.smartInBasic") {
|
||||
private val descriptorsToSkip = smartCompletion.descriptorsToSkip
|
||||
private val expectedInfos = smartCompletion.expectedInfos
|
||||
|
||||
private fun fullMatchWeight(nameSimilarity: Int): Long {
|
||||
return -((3L shl 32) + nameSimilarity)
|
||||
@@ -218,10 +214,16 @@ class ExpectedInfoMatchWeigher(
|
||||
|
||||
// TODO: keywords with type
|
||||
val o = element.`object`
|
||||
|
||||
if ((o as? DeclarationLookupObject)?.descriptor in descriptorsToSkip) return DESCRIPTOR_TO_SKIP_WEIGHT
|
||||
|
||||
if (expectedInfos == null || expectedInfos.isEmpty()) return NO_MATCH_WEIGHT
|
||||
|
||||
val smartCastCalculator = smartCompletion.smartCastCalculator
|
||||
|
||||
val (fuzzyTypes, name) = when (o) {
|
||||
is DeclarationLookupObject -> {
|
||||
val descriptor = o.descriptor ?: return NO_MATCH_WEIGHT
|
||||
if (descriptor in descriptorsToSkip) return DESCRIPTOR_TO_SKIP_WEIGHT
|
||||
descriptor.fuzzyTypesForSmartCompletion(smartCastCalculator) to descriptor.name
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -43,8 +43,8 @@ class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
||||
|
||||
val added = HashSet<String>()
|
||||
for (expectedInfo in expectedInfos) {
|
||||
if (expectedInfo is ArgumentExpectedInfo && expectedInfo.position == ArgumentPosition(0)) {
|
||||
val parameters = expectedInfo.function.getValueParameters()
|
||||
if (expectedInfo.additionalData is ArgumentAdditionalData && expectedInfo.additionalData.position == ArgumentPosition(0)) {
|
||||
val parameters = expectedInfo.additionalData.function.valueParameters
|
||||
if (parameters.size() > 1) {
|
||||
val variables = ArrayList<VariableDescriptor>()
|
||||
for ((i, parameter) in parameters.withIndex()) {
|
||||
|
||||
+37
-26
@@ -48,18 +48,22 @@ interface InheritanceItemsSearcher {
|
||||
}
|
||||
|
||||
class SmartCompletion(
|
||||
val expression: JetExpression,
|
||||
val resolutionFacade: ResolutionFacade,
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val bindingContext: BindingContext,
|
||||
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
val inDescriptor: DeclarationDescriptor,
|
||||
val prefixMatcher: PrefixMatcher,
|
||||
val inheritorSearchScope: GlobalSearchScope,
|
||||
val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
val lookupElementFactory: LookupElementFactory
|
||||
private val expression: JetExpression,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val bindingContext: BindingContext,
|
||||
private val visibilityFilter: (DeclarationDescriptor) -> Boolean,
|
||||
private val inDescriptor: DeclarationDescriptor,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val inheritorSearchScope: GlobalSearchScope,
|
||||
private val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
private val lookupElementFactory: LookupElementFactory,
|
||||
private val forBasicCompletion: Boolean = false
|
||||
) {
|
||||
private val receiver = if (expression is JetSimpleNameExpression) expression.getReceiverExpression() else null
|
||||
private val expressionWithType = receiver?.parent as? JetExpression ?: expression
|
||||
|
||||
public val expectedInfos: Collection<ExpectedInfo>? = calcExpectedInfos(expressionWithType)
|
||||
|
||||
public val smartCastCalculator: SmartCastCalculator = SmartCastCalculator(bindingContext, moduleDescriptor, expression)
|
||||
|
||||
@@ -107,11 +111,11 @@ class SmartCompletion(
|
||||
}
|
||||
|
||||
private fun executeInternal(): Result? {
|
||||
val asTypePositionResult = buildForAsTypePosition()
|
||||
if (asTypePositionResult != null) return asTypePositionResult
|
||||
val (additionalItems, inheritanceSearcher) = additionalItems()
|
||||
|
||||
val expectedInfos = calcExpectedInfos(expression.toExpressionWithType())
|
||||
if (expectedInfos == null || expectedInfos.isEmpty()) return null
|
||||
if (expectedInfos == null || expectedInfos.isEmpty()) {
|
||||
return Result(null, additionalItems, inheritanceSearcher)
|
||||
}
|
||||
|
||||
fun filterDeclaration(descriptor: DeclarationDescriptor): Collection<LookupElement> {
|
||||
if (descriptor in descriptorsToSkip) return emptyList()
|
||||
@@ -137,26 +141,28 @@ class SmartCompletion(
|
||||
return result
|
||||
}
|
||||
|
||||
val (additionalItems, inheritanceSearcher) = additionalItems(expectedInfos)
|
||||
|
||||
return Result(::filterDeclaration, additionalItems, inheritanceSearcher)
|
||||
}
|
||||
|
||||
public fun additionalItems(
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
forOrdinaryCompletion: Boolean = false
|
||||
): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
|
||||
public fun additionalItems(): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
|
||||
val asTypePositionItems = buildForAsTypePosition()
|
||||
if (asTypePositionItems != null) {
|
||||
assert(expectedInfos == null)
|
||||
return Pair(asTypePositionItems, null)
|
||||
}
|
||||
|
||||
val items = ArrayList<LookupElement>()
|
||||
val inheritanceSearchers = ArrayList<InheritanceItemsSearcher>()
|
||||
if (receiver == null) {
|
||||
TypeInstantiationItems(resolutionFacade, moduleDescriptor, bindingContext, visibilityFilter, toFromOriginalFileMapper, inheritorSearchScope, lookupElementFactory, forOrdinaryCompletion)
|
||||
|
||||
if (expectedInfos != null && expectedInfos.isNotEmpty() && receiver == null) {
|
||||
TypeInstantiationItems(resolutionFacade, moduleDescriptor, bindingContext, visibilityFilter, toFromOriginalFileMapper, inheritorSearchScope, lookupElementFactory, forBasicCompletion)
|
||||
.addTo(items, inheritanceSearchers, expectedInfos)
|
||||
|
||||
if (expression is JetSimpleNameExpression) {
|
||||
StaticMembers(bindingContext, lookupElementFactory).addToCollection(items, expectedInfos, expression, descriptorsToSkip)
|
||||
}
|
||||
|
||||
if (!forOrdinaryCompletion) {
|
||||
if (!forBasicCompletion) {
|
||||
items.addThisItems(expression, expectedInfos, smartCastCalculator)
|
||||
|
||||
LambdaItems.addToCollection(items, expectedInfos)
|
||||
@@ -193,6 +199,12 @@ class SmartCompletion(
|
||||
}
|
||||
|
||||
private fun calcExpectedInfos(expression: JetExpression): Collection<ExpectedInfo>? {
|
||||
if (forBasicCompletion) {
|
||||
return ExpectedInfos(bindingContext, resolutionFacade, moduleDescriptor, useOuterCallsExpectedTypeCount = 0)
|
||||
.calculate(expression)
|
||||
?.map { it.copy(tail = null) }
|
||||
}
|
||||
|
||||
// if our expression is initializer of implicitly typed variable - take type of variable from original file (+ the same for function)
|
||||
val declaration = implicitlyTypedDeclarationFromInitializer(expression)
|
||||
if (declaration != null) {
|
||||
@@ -227,7 +239,6 @@ class SmartCompletion(
|
||||
}
|
||||
|
||||
public val descriptorsToSkip: Set<DeclarationDescriptor> by lazy<Set<DeclarationDescriptor>> {
|
||||
val expressionWithType = expression.toExpressionWithType()
|
||||
val parent = expressionWithType.getParent()
|
||||
when (parent) {
|
||||
is JetBinaryExpression -> {
|
||||
@@ -324,7 +335,7 @@ class SmartCompletion(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun buildForAsTypePosition(): Result? {
|
||||
private fun buildForAsTypePosition(): Collection<LookupElement>? {
|
||||
val binaryExpression = ((expression.getParent() as? JetUserType)
|
||||
?.getParent() as? JetTypeReference)
|
||||
?.getParent() as? JetBinaryExpressionWithTypeRHS
|
||||
@@ -341,7 +352,7 @@ class SmartCompletion(
|
||||
val lookupElement = lookupElementFactory.createLookupElementForType(type) ?: continue
|
||||
items.add(lookupElement.addTailAndNameSimilarity(infos))
|
||||
}
|
||||
return Result(null, items, null)
|
||||
return items
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -29,9 +29,6 @@ import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithExpressionPrefixInsertHandler
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
@@ -41,7 +38,6 @@ import org.jetbrains.kotlin.types.typeUtil.isNothing
|
||||
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import java.util.HashSet
|
||||
|
||||
class ArtificialElementInsertHandler(
|
||||
val textBeforeCaret: String, val textAfterCaret: String, val shortenRefs: Boolean) : InsertHandler<LookupElement>{
|
||||
@@ -59,8 +55,7 @@ class ArtificialElementInsertHandler(
|
||||
}
|
||||
|
||||
fun mergeTails(tails: Collection<Tail?>): Tail? {
|
||||
if (tails.size() == 1) return tails.single()
|
||||
return if (HashSet(tails).size() == 1) tails.first() else null
|
||||
return tails.singleOrNull() ?: tails.toSet().singleOrNull()
|
||||
}
|
||||
|
||||
fun LookupElement.addTail(tail: Tail?): LookupElement {
|
||||
@@ -187,7 +182,7 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
val lookupElement = itemData.createLookupElement()
|
||||
if (lookupElement != null) {
|
||||
val nameSimilarityInfos = if (noNameSimilarityForReturnItself && descriptor is CallableDescriptor) {
|
||||
infos.filter { (it as? ReturnValueExpectedInfo)?.callable != descriptor } // do not calculate name similarity with function itself in its return
|
||||
infos.filter { (it.additionalData as? ReturnValueAdditionalData)?.callable != descriptor } // do not calculate name similarity with function itself in its return
|
||||
}
|
||||
else
|
||||
infos
|
||||
@@ -343,10 +338,6 @@ fun DeclarationDescriptor.fuzzyTypesForSmartCompletion(smartCastCalculator: Smar
|
||||
}
|
||||
}
|
||||
|
||||
fun JetExpression.toExpressionWithType(): JetExpression {
|
||||
return (this as? JetSimpleNameExpression)?.getReceiverExpression()?.parent as? JetExpression ?: this
|
||||
}
|
||||
|
||||
fun Collection<ExpectedInfo>.filterFunctionExpected()
|
||||
= filter { it.fuzzyType != null && KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(it.fuzzyType!!.type) }
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(list: List<String>){}
|
||||
|
||||
fun bar(o: Any) {
|
||||
foo(o as <caret>)
|
||||
}
|
||||
|
||||
// EXIST: { itemText: "List<String>" }
|
||||
@@ -0,0 +1,10 @@
|
||||
class Xyz
|
||||
|
||||
fun foo(xyz: Xyz){}
|
||||
|
||||
fun bar(o: Any) {
|
||||
foo(o as Xy<caret>)
|
||||
}
|
||||
|
||||
// EXIST: Xyz
|
||||
// NOTHING_ELSE
|
||||
@@ -0,0 +1,13 @@
|
||||
class CCC {
|
||||
companion object {
|
||||
fun create(): CCC = CCC()
|
||||
}
|
||||
}
|
||||
|
||||
fun f(ccc: CCC, p: Int){}
|
||||
|
||||
fun g() {
|
||||
f(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: create
|
||||
@@ -0,0 +1,13 @@
|
||||
class CCC {
|
||||
companion object {
|
||||
fun create(): CCC = CCC()
|
||||
}
|
||||
}
|
||||
|
||||
fun f(ccc: CCC, p: Int){}
|
||||
|
||||
fun g() {
|
||||
f(CCC.create()<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: create
|
||||
@@ -0,0 +1,13 @@
|
||||
class Xx1
|
||||
class Xx2
|
||||
class Xx3
|
||||
|
||||
fun foo(xx: Xx2){}
|
||||
|
||||
fun bar(o: Any) {
|
||||
foo(o as Xx<caret>)
|
||||
}
|
||||
|
||||
// ORDER: Xx2
|
||||
// ORDER: Xx1
|
||||
// ORDER: Xx3
|
||||
+12
@@ -1310,6 +1310,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FromSmart extends AbstractJSBasicCompletionTest {
|
||||
@TestMetadata("AfterAs.kt")
|
||||
public void testAfterAs() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/AfterAs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("AfterAsNoDuplicates.kt")
|
||||
public void testAfterAsNoDuplicates() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/AfterAsNoDuplicates.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFromSmart() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/fromSmart"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
+12
@@ -1310,6 +1310,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class FromSmart extends AbstractJvmBasicCompletionTest {
|
||||
@TestMetadata("AfterAs.kt")
|
||||
public void testAfterAs() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/AfterAs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("AfterAsNoDuplicates.kt")
|
||||
public void testAfterAsNoDuplicates() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/fromSmart/AfterAsNoDuplicates.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInFromSmart() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/fromSmart"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
+6
@@ -77,6 +77,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NoTailFromSmart.kt")
|
||||
public void testNoTailFromSmart() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/NoTailFromSmart.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PlatformStaticInClass.kt")
|
||||
public void testPlatformStaticInClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/PlatformStaticInClass.kt");
|
||||
|
||||
+6
@@ -147,6 +147,12 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ExpectedInfo extends AbstractBasicCompletionWeigherTest {
|
||||
@TestMetadata("AfterAs.kt")
|
||||
public void testAfterAs() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/expectedInfo/AfterAs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInExpectedInfo() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/weighers/basic/expectedInfo"), Pattern.compile("^([^\\.]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user