KT-14252 Completion could suggest constructors available via typealiases
#KT-14252 fixed
This commit is contained in:
+1
-1
@@ -210,7 +210,7 @@ class SmartCompletion(
|
||||
}
|
||||
|
||||
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
|
||||
TypeInstantiationItems(resolutionFacade, bindingContext, visibilityFilter, toFromOriginalFileMapper, inheritorSearchScope, lookupElementFactory, forBasicCompletion)
|
||||
TypeInstantiationItems(resolutionFacade, bindingContext, visibilityFilter, toFromOriginalFileMapper, inheritorSearchScope, lookupElementFactory, forBasicCompletion, indicesHelper)
|
||||
.addTo(items, inheritanceSearchers, expectedInfos)
|
||||
|
||||
if (expression is KtSimpleNameExpression) {
|
||||
|
||||
+50
-27
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||
import org.jetbrains.kotlin.idea.core.ExpectedInfo
|
||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
||||
import org.jetbrains.kotlin.idea.core.Tail
|
||||
import org.jetbrains.kotlin.idea.core.multipleFuzzyTypes
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
|
||||
@@ -41,14 +42,17 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamTypeAliasConstructorDescriptor
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
import org.jetbrains.kotlin.synthetic.JavaSyntheticConstructorsProvider
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.util.constructors
|
||||
import org.jetbrains.kotlin.util.kind
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
@@ -59,7 +63,8 @@ class TypeInstantiationItems(
|
||||
val toFromOriginalFileMapper: ToFromOriginalFileMapper,
|
||||
val inheritorSearchScope: GlobalSearchScope,
|
||||
val lookupElementFactory: LookupElementFactory,
|
||||
val forOrdinaryCompletion: Boolean
|
||||
val forOrdinaryCompletion: Boolean,
|
||||
val indicesHelper: KotlinIndicesHelper
|
||||
) {
|
||||
fun addTo(
|
||||
items: MutableCollection<LookupElement>,
|
||||
@@ -87,22 +92,31 @@ class TypeInstantiationItems(
|
||||
) {
|
||||
if (fuzzyType.type.isFunctionType) return // do not show "object: ..." for function types
|
||||
|
||||
val classifier = fuzzyType.type.constructor.declarationDescriptor
|
||||
if (classifier !is ClassDescriptor) return
|
||||
val classifier = fuzzyType.type.constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters ?: return
|
||||
val classDescriptor = when (classifier) {
|
||||
is ClassDescriptor -> classifier
|
||||
is TypeAliasDescriptor -> classifier.classDescriptor
|
||||
else -> null
|
||||
}
|
||||
|
||||
addSamConstructorItem(items, classifier, tail)
|
||||
addSamConstructorItem(items, classifier, classDescriptor, tail)
|
||||
items.addIfNotNull(createTypeInstantiationItem(fuzzyType, classDescriptor, tail))
|
||||
|
||||
items.addIfNotNull(createTypeInstantiationItem(fuzzyType, tail))
|
||||
indicesHelper.resolveTypeAliasesUsingIndex(fuzzyType.type, classifier.name.asString()).forEach {
|
||||
addSamConstructorItem(items, it, classDescriptor, tail)
|
||||
val typeAliasFuzzyType = it.defaultType.toFuzzyType(fuzzyType.freeParameters)
|
||||
items.addIfNotNull(createTypeInstantiationItem(typeAliasFuzzyType, classDescriptor, tail))
|
||||
}
|
||||
|
||||
if (!forOrdinaryCompletion && !KotlinBuiltIns.isAny(classifier)) { // do not search inheritors of Any
|
||||
if (classDescriptor != null && !forOrdinaryCompletion && !KotlinBuiltIns.isAny(classDescriptor)) { // do not search inheritors of Any
|
||||
val typeArgs = fuzzyType.type.arguments
|
||||
inheritanceSearchers.addInheritorSearcher(classifier, classifier, typeArgs, fuzzyType.freeParameters, tail)
|
||||
inheritanceSearchers.addInheritorSearcher(classDescriptor, classDescriptor, typeArgs, fuzzyType.freeParameters, tail)
|
||||
|
||||
val javaClassId = JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(DescriptorUtils.getFqName(classifier))
|
||||
if (javaClassId != null) {
|
||||
val javaAnalog = resolutionFacade.moduleDescriptor.resolveTopLevelClass(javaClassId.asSingleFqName(), NoLookupLocation.FROM_IDE)
|
||||
if (javaAnalog != null) {
|
||||
inheritanceSearchers.addInheritorSearcher(javaAnalog, classifier, typeArgs, fuzzyType.freeParameters, tail)
|
||||
inheritanceSearchers.addInheritorSearcher(javaAnalog, classDescriptor, typeArgs, fuzzyType.freeParameters, tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,8 +139,8 @@ class TypeInstantiationItems(
|
||||
add(InheritanceSearcher(psiClass, kotlinClassDescriptor, typeArgs, freeParameters, tail))
|
||||
}
|
||||
|
||||
private fun createTypeInstantiationItem(fuzzyType: FuzzyType, tail: Tail?): LookupElement? {
|
||||
val classifier = fuzzyType.type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
private fun createTypeInstantiationItem(fuzzyType: FuzzyType, classDescriptor: ClassDescriptor?, tail: Tail?): LookupElement? {
|
||||
val classifier = fuzzyType.type.constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters ?: return null
|
||||
|
||||
var lookupElement = lookupElementFactory.createLookupElement(classifier, useReceiverTypes = false)
|
||||
|
||||
@@ -137,7 +151,7 @@ class TypeInstantiationItems(
|
||||
// not all inner classes can be instantiated and we handle them via constructors returned by ReferenceVariantsHelper
|
||||
if (classifier.isInner) return null
|
||||
|
||||
val isAbstract = classifier.modality == Modality.ABSTRACT
|
||||
val isAbstract = classDescriptor?.modality == Modality.ABSTRACT
|
||||
if (forOrdinaryCompletion && isAbstract) return null
|
||||
|
||||
val allConstructors = classifier.constructors
|
||||
@@ -286,21 +300,30 @@ class TypeInstantiationItems(
|
||||
return FuzzyType(this, freeParameters).freeParameters.isNotEmpty()
|
||||
}
|
||||
|
||||
private fun addSamConstructorItem(collection: MutableCollection<LookupElement>, `class`: ClassDescriptor, tail: Tail?) {
|
||||
if (`class`.kind == ClassKind.INTERFACE) {
|
||||
val container = `class`.containingDeclaration
|
||||
val scope = when (container) {
|
||||
is PackageFragmentDescriptor -> container.getMemberScope()
|
||||
is ClassDescriptor -> container.staticScope
|
||||
else -> return
|
||||
private fun addSamConstructorItem(collection: MutableCollection<LookupElement>,
|
||||
classifier: ClassifierDescriptorWithTypeParameters,
|
||||
classDescriptor: ClassDescriptor?,
|
||||
tail: Tail?) {
|
||||
if (classDescriptor?.kind == ClassKind.INTERFACE) {
|
||||
val samConstructor = if (classifier is TypeAliasDescriptor) {
|
||||
JavaSyntheticConstructorsProvider.getSyntheticConstructors(classifier, NoLookupLocation.FROM_IDE)
|
||||
.filterIsInstance<SamTypeAliasConstructorDescriptor>()
|
||||
.singleOrNull() ?: return
|
||||
}
|
||||
val samConstructor = scope.getContributedFunctions(`class`.name, NoLookupLocation.FROM_IDE)
|
||||
.filterIsInstance<SamConstructorDescriptor>()
|
||||
.singleOrNull() ?: return
|
||||
lookupElementFactory.createStandardLookupElementsForDescriptor(samConstructor, useReceiverTypes = false)
|
||||
.mapTo(collection) {
|
||||
it.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION).addTail(tail)
|
||||
}
|
||||
else {
|
||||
val container = classifier.containingDeclaration
|
||||
val scope = when (container) {
|
||||
is PackageFragmentDescriptor -> container.getMemberScope()
|
||||
is ClassDescriptor -> container.staticScope
|
||||
else -> return
|
||||
}
|
||||
scope.getContributedFunctions(classifier.name, NoLookupLocation.FROM_IDE)
|
||||
.filterIsInstance<SamConstructorDescriptor>()
|
||||
.singleOrNull() ?: return
|
||||
}
|
||||
lookupElementFactory
|
||||
.createStandardLookupElementsForDescriptor(samConstructor, useReceiverTypes = false)
|
||||
.mapTo(collection) { it.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION).addTail(tail) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +357,7 @@ class TypeInstantiationItems(
|
||||
}
|
||||
}
|
||||
|
||||
val lookupElement = createTypeInstantiationItem(inheritorFuzzyType, tail) ?: continue
|
||||
val lookupElement = createTypeInstantiationItem(inheritorFuzzyType, descriptor, tail) ?: continue
|
||||
consumer(lookupElement.assignSmartCompletionPriority(SmartCompletionItemPriority.INHERITOR_INSTANTIATION))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,4 @@ fun f(){
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
// TAIL_TEXT: (...) (kotlin.collections)
|
||||
|
||||
+3
-1
@@ -1,10 +1,12 @@
|
||||
import java.util.HashMap
|
||||
import java.util.List
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
fun foo(p: HashMap<String, List<Int>>){}
|
||||
|
||||
fun f(){
|
||||
foo(HashMap(<caret>))
|
||||
foo(HashMap())
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
// TAIL_TEXT: (...) (kotlin.collections)
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
typealias TaRunnable = Runnable
|
||||
|
||||
|
||||
fun usesRunnable(runnable: Runnable) {
|
||||
|
||||
}
|
||||
|
||||
fun usage() {
|
||||
usesRunnable(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"TaRunnable","tailText":" {...} (function: () -> Unit) (<root>)","typeText":"Runnable"}
|
||||
@@ -0,0 +1,13 @@
|
||||
class SomeClass
|
||||
typealias TaSomeClass = SomeClass
|
||||
|
||||
fun usesSomeClass(p: SomeClass) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun usage() {
|
||||
usesSomeClass(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"TaSomeClass","tailText":"() (<root>)"}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class SomeClass<K, V>
|
||||
typealias TaSomeClass<K, V> = SomeClass<K, V>
|
||||
|
||||
fun <T> usesSomeClass(p: SomeClass<T, *>) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun usage() {
|
||||
usesSomeClass<Any>(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"TaSomeClass","tailText":"() (<root>)","typeText":"SomeClass<K, V>"}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class SomeClass<K, V>
|
||||
typealias TaSomeClass<V> = SomeClass<Any, V>
|
||||
|
||||
fun usesSomeClass(p: SomeClass<*, *>) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun usage() {
|
||||
usesSomeClass(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"TaSomeClass","tailText":"() (<root>)","typeText":"SomeClass<Any, V>"}
|
||||
idea/idea-completion/testData/smart/constructor/ConstructorWithTypeParamsSubstitutionViaTypeAlias.kt
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
class SomeClass<K, V>
|
||||
typealias TaSomeClass = SomeClass<Any, Any>
|
||||
|
||||
fun usesSomeClass(p: SomeClass<*, *>) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun usage() {
|
||||
usesSomeClass(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"TaSomeClass","tailText":"() (<root>)","typeText":"SomeClass<Any, Any>"}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class SomeClass<K, V>
|
||||
typealias TaSomeClass<K, V> = SomeClass<K, V>
|
||||
|
||||
fun usesSomeClass(p: SomeClass<*, *>) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun usage() {
|
||||
usesSomeClass(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"TaSomeClass","tailText":"() (<root>)","typeText":"SomeClass<K, V>"}
|
||||
+36
@@ -498,6 +498,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SAMConstructorForTypeAlias.kt")
|
||||
public void testSAMConstructorForTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SAMConstructorForTypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SAMExpected1.kt")
|
||||
public void testSAMExpected1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/SAMExpected1.kt");
|
||||
@@ -827,6 +833,36 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/smart/constructor"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("ConstructorViaTypeAlias.kt")
|
||||
public void testConstructorViaTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/constructor/ConstructorViaTypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConstructorWithTypeParamsPartialSubstitution1ViaTypeAlias.kt")
|
||||
public void testConstructorWithTypeParamsPartialSubstitution1ViaTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/constructor/ConstructorWithTypeParamsPartialSubstitution1ViaTypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConstructorWithTypeParamsPartialSubstitution2ViaTypeAlias.kt")
|
||||
public void testConstructorWithTypeParamsPartialSubstitution2ViaTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/constructor/ConstructorWithTypeParamsPartialSubstitution2ViaTypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConstructorWithTypeParamsSubstitutionViaTypeAlias.kt")
|
||||
public void testConstructorWithTypeParamsSubstitutionViaTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/constructor/ConstructorWithTypeParamsSubstitutionViaTypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConstructorWithTypeParamsViaTypeAlias.kt")
|
||||
public void testConstructorWithTypeParamsViaTypeAlias() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/constructor/ConstructorWithTypeParamsViaTypeAlias.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("GenericJavaClass.kt")
|
||||
public void testGenericJavaClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/constructor/GenericJavaClass.kt");
|
||||
|
||||
Reference in New Issue
Block a user