Smart completion after "by" works for generic properties too

This commit is contained in:
Valentin Kipyatkov
2016-03-31 20:47:06 +03:00
parent 20ac76fe3a
commit 4dde458e84
5 changed files with 39 additions and 10 deletions
@@ -0,0 +1,10 @@
import kotlin.reflect.KProperty
class X {
operator fun getValue(thisRef: List<String>, property: KProperty<*>): String = ""
}
val <T> List<T>.property: T by <caret>
// EXIST: lazy
// EXIST: X
@@ -0,0 +1,10 @@
import kotlin.reflect.KProperty
class X {
operator fun getValue(thisRef: List<String>, property: KProperty<*>): String = ""
operator fun setValue(thisRef: List<String>, property: KProperty<*>, value: String){}
}
var <T> List<T>.property: T by <caret>
// EXIST: X
@@ -1510,6 +1510,18 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName); doTest(fileName);
} }
@TestMetadata("GenericVal.kt")
public void testGenericVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/GenericVal.kt");
doTest(fileName);
}
@TestMetadata("GenericVar.kt")
public void testGenericVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/GenericVar.kt");
doTest(fileName);
}
@TestMetadata("Order.kt") @TestMetadata("Order.kt")
public void testOrder() throws Exception { public void testOrder() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/Order.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/propertyDelegate/Order.kt");
@@ -612,11 +612,11 @@ class ExpectedInfos(
val property = resolutionFacade.resolveToDescriptor(propertyDeclaration) as? PropertyDescriptor ?: return null val property = resolutionFacade.resolveToDescriptor(propertyDeclaration) as? PropertyDescriptor ?: return null
val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade) val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade)
val propertyOwnerType = property.extensionReceiverParameter?.type val propertyOwnerType = property.fuzzyExtensionReceiverType()
?: property.dispatchReceiverParameter?.type ?: property.dispatchReceiverParameter?.type?.let { FuzzyType(it, emptyList()) }
?: return null ?: return null
val explicitPropertyType = property.returnType?.check { propertyDeclaration.typeReference != null } val explicitPropertyType = property.fuzzyReturnType()?.check { propertyDeclaration.typeReference != null }
val typesWithGetDetector = TypesWithGetValueDetector(scope, indicesHelper, propertyOwnerType, explicitPropertyType) val typesWithGetDetector = TypesWithGetValueDetector(scope, indicesHelper, propertyOwnerType, explicitPropertyType)
val typesWithSetDetector = if (property.isVar) TypesWithSetValueDetector(scope, indicesHelper, propertyOwnerType) else null val typesWithSetDetector = if (property.isVar) TypesWithSetValueDetector(scope, indicesHelper, propertyOwnerType) else null
@@ -629,10 +629,7 @@ class ExpectedInfos(
val substitutedType = FuzzyType(getOperatorSubstitutor.substitute(descriptorType.type, Variance.INVARIANT)!!, descriptorType.freeParameters) val substitutedType = FuzzyType(getOperatorSubstitutor.substitute(descriptorType.type, Variance.INVARIANT)!!, descriptorType.freeParameters)
val (setValueOperator, setOperatorSubstitutor) = typesWithSetDetector.findOperator(substitutedType) ?: return null val (setValueOperator, setOperatorSubstitutor) = typesWithSetDetector.findOperator(substitutedType) ?: return null
val propertyType = if (explicitPropertyType != null) val propertyType = explicitPropertyType ?: getValueOperator.fuzzyReturnType()!!
FuzzyType(explicitPropertyType, emptyList())
else
getValueOperator.fuzzyReturnType()!!
val setParamType = FuzzyType(setValueOperator.valueParameters.last().type, setValueOperator.typeParameters) val setParamType = FuzzyType(setValueOperator.valueParameters.last().type, setValueOperator.typeParameters)
val setParamTypeSubstitutor = setParamType.checkIsSuperTypeOf(propertyType) ?: return null val setParamTypeSubstitutor = setParamType.checkIsSuperTypeOf(propertyType) ?: return null
return TypeSubstitutor.createChainedSubstitutor(getOperatorSubstitutor.substitution, return TypeSubstitutor.createChainedSubstitutor(getOperatorSubstitutor.substitution,
@@ -119,8 +119,8 @@ class TypesWithContainsDetector(
class TypesWithGetValueDetector( class TypesWithGetValueDetector(
scope: LexicalScope, scope: LexicalScope,
indicesHelper: KotlinIndicesHelper?, indicesHelper: KotlinIndicesHelper?,
private val propertyOwnerType: KotlinType, private val propertyOwnerType: FuzzyType,
private val propertyType: KotlinType? private val propertyType: FuzzyType?
) : TypesWithOperatorDetector(OperatorNameConventions.GET_VALUE, scope, indicesHelper) { ) : TypesWithOperatorDetector(OperatorNameConventions.GET_VALUE, scope, indicesHelper) {
override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? { override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? {
@@ -138,7 +138,7 @@ class TypesWithGetValueDetector(
class TypesWithSetValueDetector( class TypesWithSetValueDetector(
scope: LexicalScope, scope: LexicalScope,
indicesHelper: KotlinIndicesHelper?, indicesHelper: KotlinIndicesHelper?,
private val propertyOwnerType: KotlinType private val propertyOwnerType: FuzzyType
) : TypesWithOperatorDetector(OperatorNameConventions.SET_VALUE, scope, indicesHelper) { ) : TypesWithOperatorDetector(OperatorNameConventions.SET_VALUE, scope, indicesHelper) {
override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? { override fun checkIsSuitableByType(operator: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): TypeSubstitutor? {