KT-7844 Completion for top level classes should propose the file name

#KT-7844 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-10-20 22:07:18 +03:00
parent eb8fb80325
commit b26a590614
8 changed files with 109 additions and 5 deletions
@@ -21,6 +21,7 @@ import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.completion.CompletionSorter import com.intellij.codeInsight.completion.CompletionSorter
import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.template.TemplateManager import com.intellij.codeInsight.template.TemplateManager
import com.intellij.patterns.PatternCondition import com.intellij.patterns.PatternCondition
import com.intellij.patterns.StandardPatterns import com.intellij.patterns.StandardPatterns
@@ -43,6 +44,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -63,6 +65,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
PARAMETER_NAME(descriptorKindFilter = null), PARAMETER_NAME(descriptorKindFilter = null),
TOP_LEVEL_CLASS_NAME(descriptorKindFilter = null),
SUPER_QUALIFIER(descriptorKindFilter = DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS) SUPER_QUALIFIER(descriptorKindFilter = DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS)
} }
@@ -94,11 +98,16 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
private fun detectCompletionKind(): CompletionKind { private fun detectCompletionKind(): CompletionKind {
if (nameExpression == null) { if (nameExpression == null) {
val parameter = position.getParent() as? KtParameter return when {
return if (parameter != null && position == parameter.getNameIdentifier()) (position.parent as? KtParameter)?.nameIdentifier == position ->
CompletionKind.PARAMETER_NAME CompletionKind.PARAMETER_NAME
else
CompletionKind.KEYWORDS_ONLY (position.parent as? KtClassOrObject)?.nameIdentifier == position && position.parent.parent is KtFile ->
CompletionKind.TOP_LEVEL_CLASS_NAME
else ->
CompletionKind.KEYWORDS_ONLY
}
} }
if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(nameExpression)) { if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(nameExpression)) {
@@ -155,6 +164,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
return return
} }
if (completionKind == CompletionKind.TOP_LEVEL_CLASS_NAME) {
completeTopLevelClassName()
return
}
// if we are typing parameter name, restart completion each time we type an upper case letter because new suggestions will appear (previous words can be used as user prefix) // if we are typing parameter name, restart completion each time we type an upper case letter because new suggestions will appear (previous words can be used as user prefix)
if (parameterNameAndTypeCompletion != null) { if (parameterNameAndTypeCompletion != null) {
val prefixPattern = StandardPatterns.string().with(object : PatternCondition<String>("Prefix ends with uppercase letter") { val prefixPattern = StandardPatterns.string().with(object : PatternCondition<String>("Prefix ends with uppercase letter") {
@@ -344,6 +358,16 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
.forEach { collector.addElement(it) } .forEach { collector.addElement(it) }
} }
private fun completeTopLevelClassName() {
val name = parameters.originalFile.virtualFile.nameWithoutExtension
if (!(Name.isValidIdentifier(name) && Name.identifier(name).render() == name && name[0].isUpperCase())) return
if ((parameters.originalFile as KtFile).declarations.any { it is KtClassOrObject && it.name == name }) return
val lookupElement = LookupElementBuilder.create(name)
lookupElement.putUserData(KotlinCompletionCharFilter.SUPPRESS_ITEM_SELECTION_BY_CHARS_ON_TYPING, Unit)
collector.addElement(lookupElement)
}
override fun createSorter(): CompletionSorter { override fun createSorter(): CompletionSorter {
var sorter = super.createSorter() var sorter = super.createSorter()
@@ -0,0 +1,3 @@
class <caret>
// NUMBER: 0
@@ -0,0 +1,3 @@
class <caret>
// EXIST: { lookupString: "TopLevelClassName1", itemText: "TopLevelClassName1" }
@@ -0,0 +1,5 @@
class A {
class <caret>
}
// NUMBER: 0
@@ -0,0 +1,6 @@
class <caret>
class TopLevelClassName5 {
}
// NUMBER: 0
@@ -0,0 +1,3 @@
class <caret>
// NUMBER: 0
@@ -691,6 +691,36 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("TopLevelClassName1.kt")
public void testTopLevelClassName1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName1.kt");
doTest(fileName);
}
@TestMetadata("topLevelClassName2.kt")
public void testTopLevelClassName2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/topLevelClassName2.kt");
doTest(fileName);
}
@TestMetadata("TopLevelClassName4.kt")
public void testTopLevelClassName4() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName4.kt");
doTest(fileName);
}
@TestMetadata("TopLevelClassName5.kt")
public void testTopLevelClassName5() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName5.kt");
doTest(fileName);
}
@TestMetadata("TopLevelClassName-3.kt")
public void testTopLevelClassName_3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName-3.kt");
doTest(fileName);
}
@TestMetadata("TypeArgCompletionBug.kt") @TestMetadata("TypeArgCompletionBug.kt")
public void testTypeArgCompletionBug() throws Exception { public void testTypeArgCompletionBug() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeArgCompletionBug.kt"); String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeArgCompletionBug.kt");
@@ -691,6 +691,36 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName); doTest(fileName);
} }
@TestMetadata("TopLevelClassName1.kt")
public void testTopLevelClassName1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName1.kt");
doTest(fileName);
}
@TestMetadata("topLevelClassName2.kt")
public void testTopLevelClassName2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/topLevelClassName2.kt");
doTest(fileName);
}
@TestMetadata("TopLevelClassName4.kt")
public void testTopLevelClassName4() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName4.kt");
doTest(fileName);
}
@TestMetadata("TopLevelClassName5.kt")
public void testTopLevelClassName5() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName5.kt");
doTest(fileName);
}
@TestMetadata("TopLevelClassName-3.kt")
public void testTopLevelClassName_3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TopLevelClassName-3.kt");
doTest(fileName);
}
@TestMetadata("TypeArgCompletionBug.kt") @TestMetadata("TypeArgCompletionBug.kt")
public void testTypeArgCompletionBug() throws Exception { public void testTypeArgCompletionBug() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeArgCompletionBug.kt"); String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeArgCompletionBug.kt");