Skip to content

Commit aabf0a4

Browse files
committed
Narrow the amount of indexed completions returned
In the last commit, enabling completions for when statements, I noticed a bunch of junk indexed completions coming through. This should narrow the amount we're receiving
1 parent 8c58e70 commit aabf0a4

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

server/src/main/kotlin/org/javacs/kt/completion/Completions.kt

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
3636
import org.jetbrains.kotlin.lexer.KtKeywordToken
3737
import org.jetbrains.kotlin.resolve.BindingContext
3838
import 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.*
4240
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
4341
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion
4442
import 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. */
163183
private 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

180195
private val callPattern = Regex("(.*)\\((?:\\$\\d+)?\\)(?:\\$0)?")

0 commit comments

Comments
 (0)