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 98845d525d5..0900c966c36 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 @@ -21,6 +21,7 @@ import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.completion.CompletionSorter import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.template.TemplateManager import com.intellij.patterns.PatternCondition 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.parents 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.scopes.DescriptorKindExclude import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -63,6 +65,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, PARAMETER_NAME(descriptorKindFilter = null), + TOP_LEVEL_CLASS_NAME(descriptorKindFilter = null), + SUPER_QUALIFIER(descriptorKindFilter = DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS) } @@ -94,11 +98,16 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, private fun detectCompletionKind(): CompletionKind { if (nameExpression == null) { - val parameter = position.getParent() as? KtParameter - return if (parameter != null && position == parameter.getNameIdentifier()) - CompletionKind.PARAMETER_NAME - else - CompletionKind.KEYWORDS_ONLY + return when { + (position.parent as? KtParameter)?.nameIdentifier == position -> + CompletionKind.PARAMETER_NAME + + (position.parent as? KtClassOrObject)?.nameIdentifier == position && position.parent.parent is KtFile -> + CompletionKind.TOP_LEVEL_CLASS_NAME + + else -> + CompletionKind.KEYWORDS_ONLY + } } if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(nameExpression)) { @@ -155,6 +164,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, 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 (parameterNameAndTypeCompletion != null) { val prefixPattern = StandardPatterns.string().with(object : PatternCondition("Prefix ends with uppercase letter") { @@ -344,6 +358,16 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, .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 { var sorter = super.createSorter() diff --git a/idea/idea-completion/testData/basic/common/TopLevelClassName-3.kt b/idea/idea-completion/testData/basic/common/TopLevelClassName-3.kt new file mode 100644 index 00000000000..65d8be12730 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/TopLevelClassName-3.kt @@ -0,0 +1,3 @@ +class + +// NUMBER: 0 \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/TopLevelClassName1.kt b/idea/idea-completion/testData/basic/common/TopLevelClassName1.kt new file mode 100644 index 00000000000..4f82c0af068 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/TopLevelClassName1.kt @@ -0,0 +1,3 @@ +class + +// EXIST: { lookupString: "TopLevelClassName1", itemText: "TopLevelClassName1" } \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/TopLevelClassName4.kt b/idea/idea-completion/testData/basic/common/TopLevelClassName4.kt new file mode 100644 index 00000000000..53ddef5c1d0 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/TopLevelClassName4.kt @@ -0,0 +1,5 @@ +class A { + class +} + +// NUMBER: 0 diff --git a/idea/idea-completion/testData/basic/common/TopLevelClassName5.kt b/idea/idea-completion/testData/basic/common/TopLevelClassName5.kt new file mode 100644 index 00000000000..4a1b9a32b66 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/TopLevelClassName5.kt @@ -0,0 +1,6 @@ +class + +class TopLevelClassName5 { +} + +// NUMBER: 0 diff --git a/idea/idea-completion/testData/basic/common/topLevelClassName2.kt b/idea/idea-completion/testData/basic/common/topLevelClassName2.kt new file mode 100644 index 00000000000..65d8be12730 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/topLevelClassName2.kt @@ -0,0 +1,3 @@ +class + +// NUMBER: 0 \ No newline at end of file diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 5d8ad56b2a7..f803d86c9f3 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -691,6 +691,36 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes 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") public void testTypeArgCompletionBug() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeArgCompletionBug.kt"); diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index ac94fef0750..1a0070f53bc 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -691,6 +691,36 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT 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") public void testTypeArgCompletionBug() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/TypeArgCompletionBug.kt");