diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantNullableReturnTypeInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantNullableReturnTypeInspection.kt index 47083e37281..0f62c4f8232 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantNullableReturnTypeInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantNullableReturnTypeInspection.kt @@ -22,8 +22,8 @@ import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory import org.jetbrains.kotlin.idea.util.textRangeIn import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType -import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypes import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.isNullable @@ -47,12 +47,24 @@ class RedundantNullableReturnTypeInspection : AbstractKotlinInspection() { if (declaration.isOverridable()) return - val body = when (declaration) { - is KtNamedFunction -> declaration.bodyExpression - is KtProperty -> declaration.initializer ?: declaration.accessors.singleOrNull { it.isGetter }?.bodyExpression + val (body, targetDeclaration) = when (declaration) { + is KtNamedFunction -> { + val body = declaration.bodyExpression + if (body != null) body to declaration else null + } + is KtProperty -> { + val initializer = declaration.initializer + val getter = declaration.accessors.singleOrNull { it.isGetter } + val getterBody = getter?.bodyExpression + when { + initializer != null -> initializer to declaration + getterBody != null -> getterBody to getter + else -> null + } + } else -> null } ?: return - val actualReturnTypes = body.actualReturnTypes(declaration) + val actualReturnTypes = body.actualReturnTypes(targetDeclaration) if (actualReturnTypes.isEmpty() || actualReturnTypes.any { it.isNullable() }) return val declarationName = declaration.nameAsSafeName.asString() @@ -72,11 +84,12 @@ class RedundantNullableReturnTypeInspection : AbstractKotlinInspection() { private fun KtExpression.actualReturnTypes(declaration: KtDeclaration): List { val context = analyze() + val declarationDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] ?: return emptyList() val dataFlowValueFactory = getResolutionFacade().getDataFlowValueFactory() val moduleDescriptor = findModuleDescriptor() val languageVersionSettings = languageVersionSettings val returnTypes = collectDescendantsOfType { - it.labelQualifier == null && it.getParentOfTypes(true, KtNamedFunction::class.java, KtProperty::class.java) == declaration + it.labelQualifier == null && it.getTargetFunctionDescriptor(context) == declarationDescriptor }.flatMap { it.returnedExpression.types(context, dataFlowValueFactory, moduleDescriptor, languageVersionSettings) } diff --git a/idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableInElvis.kt b/idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableInElvis.kt new file mode 100644 index 00000000000..b37213d27f3 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableInElvis.kt @@ -0,0 +1,5 @@ +// PROBLEM: none +fun elvisFun(str: String?): String? { + val v = str?.length ?: return null + return v.toString() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantNullableReturnType/property/returnNullableInElvis.kt b/idea/testData/inspectionsLocal/redundantNullableReturnType/property/returnNullableInElvis.kt new file mode 100644 index 00000000000..0c68a451666 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantNullableReturnType/property/returnNullableInElvis.kt @@ -0,0 +1,8 @@ +// PROBLEM: none +val foo: String? + get() { + val s = bar() ?: return null + return s + } + +fun bar(): String? = null \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 679a47e4731..f9408c2aae6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -8269,6 +8269,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableFromLambdaInSingleExpressionBody.kt"); } + @TestMetadata("returnNullableInElvis.kt") + public void testReturnNullableInElvis() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableInElvis.kt"); + } + @TestMetadata("singleExpressionBody.kt") public void testSingleExpressionBody() throws Exception { runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/singleExpressionBody.kt"); @@ -8312,6 +8317,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/property/returnNullableFromLambdaInGetter.kt"); } + @TestMetadata("returnNullableInElvis.kt") + public void testReturnNullableInElvis() throws Exception { + runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/property/returnNullableInElvis.kt"); + } + @TestMetadata("var.kt") public void testVar() throws Exception { runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/property/var.kt");