From ec5d1d3a52121aa845cd173d9acc9ecbbc67dafa Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 30 Sep 2015 20:45:36 +0300 Subject: [PATCH] Support for A::class and A::class.java in basic completion (but not in smart) --- .../idea/completion/BasicCompletionSession.kt | 103 +++++++++++------- .../callableReference/EmptyQualifier.kt | 2 + .../callableReference/NonEmptyQualifier.kt | 4 +- 3 files changed, 68 insertions(+), 41 deletions(-) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index 23ba502cc52..337e9597904 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.completion.CompletionSorter import com.intellij.codeInsight.completion.CompletionType +import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.template.TemplateManager import com.intellij.patterns.PatternCondition import com.intellij.patterns.StandardPatterns @@ -37,6 +38,7 @@ import org.jetbrains.kotlin.idea.completion.smart.SmartCompletion 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.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* @@ -230,43 +232,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, collector.addDescriptorElements(referenceVariants) - val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc - KeywordCompletion.complete(expression ?: parameters.getPosition(), keywordsPrefix) { lookupElement -> - val keyword = lookupElement.getLookupString() - when (keyword) { - // if "this" is parsed correctly in the current context - insert it and all this@xxx items - "this" -> { - if (expression != null) { - collector.addElements(thisExpressionItems(bindingContext, expression, prefix, resolutionFacade).map { it.createLookupElement() }) - } - else { - // for completion in secondary constructor delegation call - collector.addElement(lookupElement) - } - } - - // if "return" is parsed correctly in the current context - insert it and all return@xxx items - "return" -> { - if (expression != null) { - collector.addElements(returnExpressionItems(bindingContext, expression)) - } - } - - "break", "continue" -> { - if (expression != null) { - collector.addElements(breakOrContinueExpressionItems(expression, keyword)) - } - } - - "override" -> { - collector.addElement(lookupElement) - - OverridesCompletion(collector, lookupElementFactory).complete(position) - } - - else -> collector.addElement(lookupElement) - } - } + completeKeywords() // getting root packages from scope is very slow so we do this in alternative way if (isNoQualifierContext() && (descriptorKindFilter?.kindMask ?: 0).and(DescriptorKindFilter.PACKAGES_MASK) != 0) { @@ -293,7 +259,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, collector.advertiseSecondCompletion() } - addNonImported(completionKind) + completeNonImported() if (position.getContainingFile() is JetCodeFragment) { flushToResultSet() @@ -305,7 +271,66 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, NamedArgumentCompletion.complete(collector, expectedInfos) } - private fun addNonImported(completionKind: CompletionKind) { + private fun completeKeywords() { + val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc + KeywordCompletion.complete(expression ?: parameters.getPosition(), keywordsPrefix) { lookupElement -> + val keyword = lookupElement.getLookupString() + when (keyword) { + // if "this" is parsed correctly in the current context - insert it and all this@xxx items + "this" -> { + if (expression != null) { + collector.addElements(thisExpressionItems(bindingContext, expression, prefix, resolutionFacade).map { it.createLookupElement() }) + } + else { + // for completion in secondary constructor delegation call + collector.addElement(lookupElement) + } + } + + // if "return" is parsed correctly in the current context - insert it and all return@xxx items + "return" -> { + if (expression != null) { + collector.addElements(returnExpressionItems(bindingContext, expression)) + } + } + + "break", "continue" -> { + if (expression != null) { + collector.addElements(breakOrContinueExpressionItems(expression, keyword)) + } + } + + "override" -> { + collector.addElement(lookupElement) + + OverridesCompletion(collector, lookupElementFactory).complete(position) + } + + "class" -> { + if (callTypeAndReceiver is CallTypeAndReceiver.CALLABLE_REFERENCE) { + if (callTypeAndReceiver.receiver != null) { + collector.addElement(lookupElement) + + if (!ProjectStructureUtil.isJsKotlinModule(parameters.originalFile as JetFile)) { + val element = LookupElementBuilder.create(KeywordLookupObject(), "class.java") + .withPresentableText("class") + .withTailText(".java") + .bold() + collector.addElement(element) + } + } + } + else { + collector.addElement(lookupElement) + } + } + + else -> collector.addElement(lookupElement) + } + } + } + + private fun completeNonImported() { if (completionKind == CompletionKind.ALL) { collector.addDescriptorElements(getTopLevelExtensions(), notImported = true) } diff --git a/idea/idea-completion/testData/basic/common/callableReference/EmptyQualifier.kt b/idea/idea-completion/testData/basic/common/callableReference/EmptyQualifier.kt index aa18ee8cecc..6af3f580377 100644 --- a/idea/idea-completion/testData/basic/common/callableReference/EmptyQualifier.kt +++ b/idea/idea-completion/testData/basic/common/callableReference/EmptyQualifier.kt @@ -46,3 +46,5 @@ abstract class AbstractClass // EXIST: { itemText: "InnerClass", attributes: "bold" } // ABSENT: WithPrivateConstructor // ABSENT: AbstractClass +// ABSENT: class +// ABSENT: class.java diff --git a/idea/idea-completion/testData/basic/common/callableReference/NonEmptyQualifier.kt b/idea/idea-completion/testData/basic/common/callableReference/NonEmptyQualifier.kt index 1649cfa09d7..3aaada59016 100644 --- a/idea/idea-completion/testData/basic/common/callableReference/NonEmptyQualifier.kt +++ b/idea/idea-completion/testData/basic/common/callableReference/NonEmptyQualifier.kt @@ -37,8 +37,8 @@ class C { } } -/* TODO // EXIST: class */ -/* TODO // EXIST: class.java */ +// EXIST: { lookupString: "class", itemText: "class", attributes: "bold" } +// EXIST_JAVA_ONLY: { lookupString: "class.java", itemText: "class", tailText: ".java", attributes: "bold" } // EXIST: { itemText: "memberFunInA", attributes: "bold" } // EXIST: { itemText: "memberValInA", attributes: "bold" } // EXIST: { itemText: "InnerInA", attributes: "bold" }