Smart completion to use super type for override if no explicit type specified

This commit is contained in:
Valentin Kipyatkov
2016-04-01 17:02:00 +03:00
parent 7af67da4ac
commit 3aff4d4c17
4 changed files with 54 additions and 10 deletions
@@ -0,0 +1,13 @@
abstract class Base {
abstract fun foo(): Int
}
class Derived : Base() {
override fun foo() = <caret>
}
fun getInt(): Int = 0
fun getString(): String = ""
// EXIST: getInt
// ABSENT: getString
@@ -0,0 +1,13 @@
abstract class Base {
abstract val foo: Int
}
class Derived : Base() {
override val foo = <caret>
}
fun getInt(): Int = 0
fun getString(): String = ""
// EXIST: getInt
// ABSENT: getString
@@ -185,6 +185,18 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName);
}
@TestMetadata("ImplicitlyTypedOverrideFunBody.kt")
public void testImplicitlyTypedOverrideFunBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ImplicitlyTypedOverrideFunBody.kt");
doTest(fileName);
}
@TestMetadata("ImplicitlyTypedOverrideValInitializer.kt")
public void testImplicitlyTypedOverrideValInitializer() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ImplicitlyTypedOverrideValInitializer.kt");
doTest(fileName);
}
@TestMetadata("ImplicitlyTypedValInitializer1.kt")
public void testImplicitlyTypedValInitializer1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ImplicitlyTypedValInitializer1.kt");
@@ -527,10 +527,11 @@ class ExpectedInfos(
if (expressionWithType != property.initializer) return null
val propertyDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? VariableDescriptor ?: return null
val expectedName = propertyDescriptor.name.asString()
val expectedInfo = if (property.typeReference != null)
ExpectedInfo(propertyDescriptor.type, expectedName, null)
val returnTypeToUse = returnTypeToUse(propertyDescriptor, hasExplicitReturnType = property.typeReference != null)
val expectedInfo = if (returnTypeToUse != null)
ExpectedInfo(returnTypeToUse, expectedName, null)
else
ExpectedInfo(ByTypeFilter.All, expectedName, null) // no explicit type - only expected name known
ExpectedInfo(ByTypeFilter.All, expectedName, null) // no explicit type or type from base - only expected name known
return listOf(expectedInfo)
}
@@ -538,33 +539,38 @@ class ExpectedInfos(
val declaration = expressionWithType.parent as? KtDeclarationWithBody ?: return null
if (expressionWithType != declaration.bodyExpression || declaration.hasBlockBody()) return null
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] as? FunctionDescriptor ?: return null
return functionReturnValueExpectedInfo(descriptor, expectType = declaration.hasDeclaredReturnType()).singletonOrEmptyList()
return functionReturnValueExpectedInfo(descriptor, hasExplicitReturnType = declaration.hasDeclaredReturnType()).singletonOrEmptyList()
}
private fun calculateForReturn(expressionWithType: KtExpression): Collection<ExpectedInfo>? {
val returnExpression = expressionWithType.parent as? KtReturnExpression ?: return null
val descriptor = returnExpression.getTargetFunctionDescriptor(bindingContext) ?: return null
return functionReturnValueExpectedInfo(descriptor, expectType = true).singletonOrEmptyList()
return functionReturnValueExpectedInfo(descriptor, hasExplicitReturnType = true).singletonOrEmptyList()
}
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor, expectType: Boolean): ExpectedInfo? {
private fun functionReturnValueExpectedInfo(descriptor: FunctionDescriptor, hasExplicitReturnType: Boolean): ExpectedInfo? {
return when (descriptor) {
is SimpleFunctionDescriptor -> {
val expectedType = if (expectType) descriptor.returnType else null
ExpectedInfo.createForReturnValue(expectedType, descriptor)
ExpectedInfo.createForReturnValue(returnTypeToUse(descriptor, hasExplicitReturnType), descriptor)
}
is PropertyGetterDescriptor -> {
if (descriptor !is PropertyGetterDescriptor) return null
val property = descriptor.correspondingProperty
val expectedType = if (expectType) property.type else null
ExpectedInfo.createForReturnValue(expectedType, property)
ExpectedInfo.createForReturnValue(returnTypeToUse(property, hasExplicitReturnType), property)
}
else -> null
}
}
private fun returnTypeToUse(descriptor: CallableDescriptor, hasExplicitReturnType: Boolean): KotlinType? {
return if (hasExplicitReturnType)
descriptor.returnType
else
descriptor.overriddenDescriptors.singleOrNull()?.returnType
}
private fun calculateForLoopRange(expressionWithType: KtExpression): Collection<ExpectedInfo>? {
val forExpression = (expressionWithType.parent as? KtContainerNode)
?.parent as? KtForExpression ?: return null