diff --git a/idea/idea-completion/testData/smart/ImplicitlyTypedOverrideFunBody.kt b/idea/idea-completion/testData/smart/ImplicitlyTypedOverrideFunBody.kt new file mode 100644 index 00000000000..efa0752e659 --- /dev/null +++ b/idea/idea-completion/testData/smart/ImplicitlyTypedOverrideFunBody.kt @@ -0,0 +1,13 @@ +abstract class Base { + abstract fun foo(): Int +} + +class Derived : Base() { + override fun foo() = +} + +fun getInt(): Int = 0 +fun getString(): String = "" + +// EXIST: getInt +// ABSENT: getString \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/ImplicitlyTypedOverrideValInitializer.kt b/idea/idea-completion/testData/smart/ImplicitlyTypedOverrideValInitializer.kt new file mode 100644 index 00000000000..8d91b1ec9f4 --- /dev/null +++ b/idea/idea-completion/testData/smart/ImplicitlyTypedOverrideValInitializer.kt @@ -0,0 +1,13 @@ +abstract class Base { + abstract val foo: Int +} + +class Derived : Base() { + override val foo = +} + +fun getInt(): Int = 0 +fun getString(): String = "" + +// EXIST: getInt +// ABSENT: getString \ No newline at end of file diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java index 4b6a35ebe1b..92a332d5317 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java @@ -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"); diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt index 3a5c933087a..33c6891f0c1 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.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? { 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? { val forExpression = (expressionWithType.parent as? KtContainerNode) ?.parent as? KtForExpression ?: return null