@@ -36,9 +36,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
3636import org.jetbrains.kotlin.lexer.KtKeywordToken
3737import org.jetbrains.kotlin.resolve.BindingContext
3838import org.jetbrains.kotlin.resolve.DescriptorUtils
39- import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
40- import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
41- import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
39+ import org.jetbrains.kotlin.resolve.descriptorUtil.*
4240import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
4341import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion
4442import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope
@@ -63,12 +61,17 @@ fun completions(file: CompiledFile, cursor: Int, index: SymbolIndex, config: Com
6361 val partial = findPartialIdentifier(file, cursor)
6462 LOG .debug(" Looking for completions that match '{}'" , partial)
6563
66- val (elementItems, isExhaustive, receiver ) = elementCompletionItems(file, cursor, config, partial)
64+ val (elementItems, element ) = elementCompletionItems(file, cursor, config, partial)
6765 val elementItemList = elementItems.toList()
6866 val elementItemLabels = elementItemList.mapNotNull { it.label }.toSet()
67+
68+ val isExhaustive = element !is KtNameReferenceExpression
69+ && element !is KtTypeElement
70+ && element !is KtQualifiedExpression
71+
6972 val items = (
7073 elementItemList.asSequence()
71- + (if (! isExhaustive) indexCompletionItems(file, cursor, receiver , index, partial).filter { it.label !in elementItemLabels } else emptySequence())
74+ + (if (! isExhaustive) indexCompletionItems(file, cursor, element , index, partial).filter { it.label !in elementItemLabels } else emptySequence())
7275 + (if (elementItemList.isEmpty()) keywordCompletionItems(partial) else emptySequence())
7376 )
7477 val itemList = items
@@ -80,8 +83,13 @@ fun completions(file: CompiledFile, cursor: Int, index: SymbolIndex, config: Com
8083 return CompletionList (isIncomplete, itemList)
8184}
8285
86+ private fun getQueryNameFromExpression (receiver : KtExpression ? , cursor : Int , file : CompiledFile ): FqName ? {
87+ val receiverType = receiver?.let { expr -> file.scopeAtPoint(cursor)?.let { file.typeOfExpression(expr, it) } }
88+ return receiverType?.constructor ?.declarationDescriptor?.fqNameSafe
89+ }
90+
8391/* * Finds completions in the global symbol index, for potentially unimported symbols. */
84- private fun indexCompletionItems (file : CompiledFile , cursor : Int , receiver : KtExpression ? , index : SymbolIndex , partial : String ): Sequence <CompletionItem > {
92+ private fun indexCompletionItems (file : CompiledFile , cursor : Int , element : KtElement ? , index : SymbolIndex , partial : String ): Sequence <CompletionItem > {
8593 val parsedFile = file.parse
8694 val imports = parsedFile.importDirectives
8795 // TODO: Deal with alias imports
@@ -93,11 +101,23 @@ private fun indexCompletionItems(file: CompiledFile, cursor: Int, receiver: KtEx
93101 val importedNames = imports
94102 .mapNotNull { it.importedFqName?.shortName() }
95103 .toSet()
96- val receiverType = receiver?.let { expr -> file.scopeAtPoint(cursor)?.let { file.typeOfExpression(expr, it) } }
97- val receiverTypeFqName = receiverType?.constructor ?.declarationDescriptor?.fqNameSafe
104+
105+ val queryName = when (element) {
106+ is KtQualifiedExpression -> getQueryNameFromExpression(element.receiverExpression, element.receiverExpression.startOffset, file)
107+ is KtSimpleNameExpression -> {
108+ val receiver = element.getReceiverExpression()
109+ when {
110+ receiver != null -> getQueryNameFromExpression(receiver, receiver.startOffset, file)
111+ else -> null
112+ }
113+ }
114+ is KtUserType -> file.referenceAtPoint(element.qualifier?.startOffset ? : cursor)?.second?.fqNameSafe
115+ is KtTypeElement -> file.referenceAtPoint(element.startOffsetInParent)?.second?.fqNameOrNull()
116+ else -> null
117+ }
98118
99119 return index
100- .query(partial, receiverTypeFqName , limit = MAX_COMPLETION_ITEMS )
120+ .query(partial, queryName , limit = MAX_COMPLETION_ITEMS )
101121 .asSequence()
102122 .filter { it.kind != Symbol .Kind .MODULE } // Ignore global module/package name completions for now, since they cannot be 'imported'
103123 .filter { it.fqName.shortName() !in importedNames && it.fqName.parent() !in wildcardPackages }
@@ -157,24 +177,19 @@ private fun keywordCompletionItems(partial: String): Sequence<CompletionItem> =
157177 kind = CompletionItemKind .Keyword
158178 } }
159179
160- data class ElementCompletionItems (val items : Sequence <CompletionItem >, val isExhaustive : Boolean , val receiver : KtExpression ? = null )
180+ data class ElementCompletionItems (val items : Sequence <CompletionItem >, val element : KtElement ? = null )
161181
162182/* * Finds completions based on the element around the user's cursor. */
163183private fun elementCompletionItems (file : CompiledFile , cursor : Int , config : CompletionConfiguration , partial : String ): ElementCompletionItems {
164- val surroundingElement = completableElement(file, cursor) ? : return ElementCompletionItems (emptySequence(), isExhaustive = true )
184+ val surroundingElement = completableElement(file, cursor) ? : return ElementCompletionItems (emptySequence())
165185 val completions = elementCompletions(file, cursor, surroundingElement)
166186
167187 val matchesName = completions.filter { containsCharactersInOrder(name(it), partial, caseSensitive = false ) }
168188 val sorted = matchesName.takeIf { partial.length >= MIN_SORT_LENGTH }?.sortedBy { stringDistance(name(it), partial) }
169189 ? : matchesName.sortedBy { if (name(it).startsWith(partial)) 0 else 1 }
170190 val visible = sorted.filter(isVisible(file, cursor))
171191
172- val isExhaustive = surroundingElement !is KtNameReferenceExpression
173- && surroundingElement !is KtTypeElement
174- && surroundingElement !is KtQualifiedExpression
175- val receiver = (surroundingElement as ? KtQualifiedExpression )?.receiverExpression
176-
177- return ElementCompletionItems (visible.map { completionItem(it, surroundingElement, file, config) }, isExhaustive, receiver)
192+ return ElementCompletionItems (visible.map { completionItem(it, surroundingElement, file, config) }, surroundingElement)
178193}
179194
180195private val callPattern = Regex (" (.*)\\ ((?:\\ $\\ d+)?\\ )(?:\\ $0)?" )
0 commit comments