diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt index 946111584cf..5b8a7233c51 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.CallHandle import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.typeUtil.* import java.util.* @@ -49,6 +50,26 @@ fun FuzzyType.isAlmostEverything(): Boolean { return typeParameter.upperBounds.singleOrNull()?.isAnyOrNullableAny() ?: false } +/** + * Replaces free parameters inside the type with corresponding type parameters of the class (when possible) + */ +fun FuzzyType.presentationType(): KotlinType { + if (freeParameters.isEmpty()) return type + + val map = HashMap() + for ((argument, typeParameter) in type.arguments.zip(type.constructor.parameters)) { + if (argument.projectionKind == Variance.INVARIANT) { + val equalToFreeParameter = freeParameters.firstOrNull { + KotlinTypeChecker.FLEXIBLE_UNEQUAL_TO_INFLEXIBLE.equalTypes(it.defaultType, argument.type) + } ?: continue + + map[equalToFreeParameter.typeConstructor] = createProjection(typeParameter.defaultType, Variance.INVARIANT, null) + } + } + val substitutor = TypeSubstitutor.create(map) + return substitutor.substitute(type, Variance.INVARIANT)!! +} + class FuzzyType( val type: KotlinType, freeParameters: Collection diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt index 57b28885fce..f09cf031962 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt @@ -41,6 +41,7 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.makeNotNullable +import org.jetbrains.kotlin.idea.util.presentationType import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor import org.jetbrains.kotlin.platform.JavaToKotlinClassMap @@ -208,7 +209,14 @@ class TypeInstantiationItems( //TODO: when constructor has one parameter of lambda type with more than one parameter, generate special additional item signatureText = when (visibleConstructors.size) { 0 -> "()" - 1 -> DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderFunctionParameters(visibleConstructors.single()) + + 1 -> { + val constructor = visibleConstructors.single() + val substitutor = TypeSubstitutor.create(fuzzyType.presentationType()) + val substitutedConstructor = constructor.substitute(substitutor) + DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderFunctionParameters(substitutedConstructor) + } + else -> "(...)" } diff --git a/idea/idea-completion/testData/smart/constructor/GenericType.kt b/idea/idea-completion/testData/smart/constructor/GenericType.kt index 5d601a106d9..53dcdf591a4 100644 --- a/idea/idea-completion/testData/smart/constructor/GenericType.kt +++ b/idea/idea-completion/testData/smart/constructor/GenericType.kt @@ -1,7 +1,7 @@ -class Foo +class Foo(t: T) fun foo(p : Any){ var a : Foo = } -// EXIST: { lookupString:"Foo", itemText:"Foo", tailText:"() ()" } +// EXIST: { lookupString:"Foo", itemText:"Foo", tailText:"(t: String) ()" } diff --git a/idea/idea-completion/testData/smart/inheritors/GenericClass1.kt b/idea/idea-completion/testData/smart/inheritors/GenericClass1.kt index c064e429ed6..68ae678ecd6 100644 --- a/idea/idea-completion/testData/smart/inheritors/GenericClass1.kt +++ b/idea/idea-completion/testData/smart/inheritors/GenericClass1.kt @@ -3,6 +3,8 @@ interface I abstract class C1 : I abstract class C2 : I abstract class C3 : I +class C4(t: T) : I +class C5(t1: T1, t2: T2) : I fun foo(i: I){} @@ -13,4 +15,6 @@ fun bar() { // EXIST: { itemText: "object: I{...}" } // EXIST: { itemText: "object: C1(){...}" } // EXIST: { itemText: "object: C3(){...}" } +// EXIST: { itemText: "C4", tailText: "(t: Int) ()" } +// EXIST: { itemText: "C5", tailText: "(t1: T1, t2: Int) ()" } // NOTHING_ELSE diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution1.kt b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution1.kt index 7b70b75fdcc..123d8639c33 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution1.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution1.kt @@ -13,4 +13,4 @@ class C { } // EXIST: { itemText: "createProperty", typeText: "Property" } -// EXIST: Property +// EXIST: { itemText: "Property", tailText: "(owner: C, value: TValue) ()" } diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution2.kt b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution2.kt index a14dacd9222..1b000a73a48 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution2.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution2.kt @@ -1,16 +1,16 @@ import kotlin.reflect.KProperty -class Property +class Property(owner: TOwner, value: TValue) operator fun Property.getValue(thisRef: TOwner, property: KProperty<*>): TValue { throw Exception() } -fun createProperty(): Property = Property() +fun createProperty(owner: TOwner, value: TValue): Property = Property(owner, value) class C { val v: Int by } // EXIST: { itemText: "createProperty", typeText: "Property" } -// EXIST: Property +// EXIST: { itemText: "Property", tailText: "(owner: C, value: Int) ()" } diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution3.kt b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution3.kt index bdc654f8e4e..169b9d3eee3 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution3.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution3.kt @@ -1,6 +1,6 @@ import kotlin.reflect.KProperty -class Property +class Property(owner: TOwner1, value: TValue1) operator fun Property.getValue(thisRef: TOwner2, property: KProperty<*>): TValue2 { throw Exception() @@ -10,11 +10,11 @@ operator fun Property.setValue(thisRef: TOw throw Exception() } -fun createProperty(): Property = Property() +fun createProperty(owner: TOwner4, value: TValue4): Property = Property(owner, value) class C { var v by } // EXIST: { itemText: "createProperty", typeText: "Property" } -// EXIST: Property +// EXIST: { itemText: "Property", tailText: "(owner: C, value: TValue1) ()" } diff --git a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution4.kt b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution4.kt index 0a22828cfe2..7e29bf96a2b 100644 --- a/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution4.kt +++ b/idea/idea-completion/testData/smart/propertyDelegate/ExtensionSubstitution4.kt @@ -1,6 +1,6 @@ import kotlin.reflect.KProperty -class Property +class Property(owner: TOwner1, value: TValue1) operator fun Property.getValue(thisRef: TOwner2, property: KProperty<*>): TValue2 { throw Exception() @@ -10,11 +10,11 @@ operator fun Property.setValue(thisRef: TOw throw Exception() } -fun createProperty(): Property = Property() +fun createProperty(owner: TOwner4, value: TValue4): Property = Property(owner, value) class C { var v: Int by } // EXIST: { itemText: "createProperty", typeText: "Property" } -// EXIST: Property +// EXIST: { itemText: "Property", tailText: "(owner: C, value: Int) ()" }