KT-13266 Non-imported type aliases do not appear in completion
#KT-13266 Fixed
This commit is contained in:
+11
-3
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiLiteral
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
|
||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
||||
import org.jetbrains.kotlin.idea.core.isJavaClassNotToBeUsedInKotlin
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
@@ -41,23 +42,30 @@ class AllClassesCompletion(private val parameters: CompletionParameters,
|
||||
private val prefixMatcher: PrefixMatcher,
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val kindFilter: (ClassKind) -> Boolean,
|
||||
private val includeTypeAliases: Boolean,
|
||||
private val includeJavaClassesNotToBeUsed: Boolean
|
||||
) {
|
||||
fun collect(classDescriptorCollector: (ClassDescriptor) -> Unit, javaClassCollector: (PsiClass) -> Unit) {
|
||||
fun collect(classifierDescriptorCollector: (ClassifierDescriptorWithTypeParameters) -> Unit, javaClassCollector: (PsiClass) -> Unit) {
|
||||
|
||||
//TODO: this is a temporary solution until we have built-ins in indices
|
||||
// we need only nested classes because top-level built-ins are all added through default imports
|
||||
for (builtinPackage in resolutionFacade.moduleDescriptor.builtIns.builtInsPackageFragments) {
|
||||
collectClassesFromScope(builtinPackage.getMemberScope()) {
|
||||
if (it.containingDeclaration is ClassDescriptor) {
|
||||
classDescriptorCollector(it)
|
||||
classifierDescriptorCollector(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlinIndicesHelper
|
||||
.getKotlinClasses({ prefixMatcher.prefixMatches(it) }, kindFilter)
|
||||
.forEach { classDescriptorCollector(it) }
|
||||
.forEach { classifierDescriptorCollector(it) }
|
||||
|
||||
if (includeTypeAliases) {
|
||||
kotlinIndicesHelper
|
||||
.getTopLevelTypeAliases(prefixMatcher.asStringNameFilter())
|
||||
.forEach { classifierDescriptorCollector(it) }
|
||||
}
|
||||
|
||||
if (!ProjectStructureUtil.isJsKotlinModule(parameters.originalFile as KtFile)) {
|
||||
addAdaptedJavaCompletion(javaClassCollector)
|
||||
|
||||
+23
-8
@@ -28,6 +28,7 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.ProcessingContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.createKeywordConstructLookupElement
|
||||
import org.jetbrains.kotlin.idea.completion.smart.ExpectedInfoMatch
|
||||
import org.jetbrains.kotlin.idea.completion.smart.SMART_COMPLETION_ITEM_PRIORITY_KEY
|
||||
@@ -291,17 +292,30 @@ class BasicCompletionSession(
|
||||
|
||||
if (callTypeAndReceiver.receiver == null && prefix.isNotEmpty()) {
|
||||
val classKindFilter: ((ClassKind) -> Boolean)?
|
||||
val includeTypeAliases: Boolean
|
||||
when (callTypeAndReceiver) {
|
||||
is CallTypeAndReceiver.ANNOTATION -> classKindFilter = { it == ClassKind.ANNOTATION_CLASS }
|
||||
is CallTypeAndReceiver.DEFAULT, is CallTypeAndReceiver.TYPE -> classKindFilter = { it != ClassKind.ENUM_ENTRY }
|
||||
else -> classKindFilter = null
|
||||
is CallTypeAndReceiver.ANNOTATION -> {
|
||||
classKindFilter = { it == ClassKind.ANNOTATION_CLASS }
|
||||
includeTypeAliases = false
|
||||
}
|
||||
|
||||
is CallTypeAndReceiver.DEFAULT, is CallTypeAndReceiver.TYPE -> {
|
||||
classKindFilter = { it != ClassKind.ENUM_ENTRY }
|
||||
includeTypeAliases = true
|
||||
}
|
||||
|
||||
else -> {
|
||||
classKindFilter = null
|
||||
includeTypeAliases = false
|
||||
}
|
||||
}
|
||||
|
||||
if (classKindFilter != null) {
|
||||
val prefixMatcher = if (configuration.useBetterPrefixMatcherForNonImportedClasses)
|
||||
BetterPrefixMatcher(prefixMatcher, collector.bestMatchingDegree)
|
||||
else
|
||||
prefixMatcher
|
||||
addClassesFromIndex(classKindFilter, prefixMatcher)
|
||||
addClassesFromIndex(classKindFilter, includeTypeAliases, prefixMatcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,15 +586,16 @@ class BasicCompletionSession(
|
||||
}
|
||||
}
|
||||
|
||||
private fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean, prefixMatcher: PrefixMatcher) {
|
||||
val classDescriptorCollector = { descriptor: ClassDescriptor ->
|
||||
private fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean, includeTypeAliases: Boolean, prefixMatcher: PrefixMatcher) {
|
||||
val classifierDescriptorCollector = { descriptor: ClassifierDescriptorWithTypeParameters ->
|
||||
collector.addElement(basicLookupElementFactory.createLookupElement(descriptor), notImported = true)
|
||||
}
|
||||
val javaClassCollector = { javaClass: PsiClass ->
|
||||
collector.addElement(basicLookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true)
|
||||
}
|
||||
AllClassesCompletion(parameters, indicesHelper(true), prefixMatcher, resolutionFacade, kindFilter, configuration.completeJavaClassesNotToBeUsed)
|
||||
.collect(classDescriptorCollector, javaClassCollector)
|
||||
AllClassesCompletion(parameters, indicesHelper(true), prefixMatcher, resolutionFacade,
|
||||
kindFilter, includeTypeAliases, configuration.completeJavaClassesNotToBeUsed
|
||||
).collect(classifierDescriptorCollector, javaClassCollector)
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -89,7 +89,8 @@ class ParameterNameAndTypeCompletion(
|
||||
fun addFromAllClasses(parameters: CompletionParameters, indicesHelper: KotlinIndicesHelper) {
|
||||
for ((classNameMatcher, userPrefix) in classNamePrefixMatchers.zip(userPrefixes)) {
|
||||
AllClassesCompletion(
|
||||
parameters, indicesHelper, classNameMatcher, resolutionFacade, { !it.isSingleton }, includeJavaClassesNotToBeUsed = false
|
||||
parameters, indicesHelper, classNameMatcher, resolutionFacade, { !it.isSingleton },
|
||||
includeTypeAliases = true, includeJavaClassesNotToBeUsed = false
|
||||
).collect(
|
||||
{ addSuggestionsForClassifier(it, userPrefix, notImported = true) },
|
||||
{ addSuggestionsForJavaClass(it, userPrefix, notImported = true) }
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package test
|
||||
|
||||
class MyClass
|
||||
typealias MyAlias = MyClass
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package test2
|
||||
|
||||
fun foo(ali<caret>)
|
||||
|
||||
// EXIST: { lookupString: "alias : MyAlias", itemText: "alias: MyAlias", typeText: "public typealias MyAlias = MyClass defined in test", attributes: "" }
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package dependency
|
||||
|
||||
class MyClass
|
||||
typealias MyAlias = MyClass
|
||||
@@ -0,0 +1,10 @@
|
||||
package test
|
||||
|
||||
typealias MySameFileAlias = (String) -> Int
|
||||
private typealias MyPrivateAlias = (String, Char) -> Unit
|
||||
|
||||
val test: My<caret>
|
||||
|
||||
// EXIST: { lookupString: "MySameFileAlias", itemText: "MySameFileAlias", tailText: null, typeText: "public typealias MySameFileAlias = (String) -> Int defined in test", attributes: "" }
|
||||
// EXIST: { lookupString: "MyPrivateAlias", itemText: "MyPrivateAlias", tailText: null, typeText: "private typealias MyPrivateAlias = (String, Char) -> Unit defined in test", attributes: "" }
|
||||
// EXIST: { lookupString: "MyAlias", itemText: "MyAlias", tailText: null, typeText: "public typealias MyAlias = MyClass defined in dependency", attributes: "" }
|
||||
@@ -0,0 +1 @@
|
||||
fun foo(): MyAl<caret>
|
||||
@@ -0,0 +1,5 @@
|
||||
package test
|
||||
|
||||
class MyClass
|
||||
|
||||
typealias MyAlias = MyClass
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import test.MyAlias
|
||||
|
||||
fun foo(): MyAlias<caret>
|
||||
+12
@@ -323,6 +323,12 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterNameAndTypeForNotImportedAlias")
|
||||
public void testParameterNameAndTypeForNotImportedAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/ParameterNameAndTypeForNotImportedAlias/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterNameAndTypeNestedClasses")
|
||||
public void testParameterNameAndTypeNestedClasses() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/ParameterNameAndTypeNestedClasses/");
|
||||
@@ -400,4 +406,10 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/TopLevelFunction/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeAliases")
|
||||
public void testTypeAliases() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/TypeAliases/");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -101,6 +101,10 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun testNotImportedTypeAlias() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
fun doTest(completionChar: Char = '\n', vararg extraFileNames: String) {
|
||||
val fileName = getTestName(false)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user