Redundant nullable return type: false negative with return expression in local function or lambda

#KT-41817 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-09-11 10:22:32 +09:00
committed by Vladimir Dolzhenko
parent de3907e8cc
commit 370622087b
6 changed files with 42 additions and 3 deletions
@@ -22,6 +22,7 @@ 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.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.types.KotlinType
@@ -51,7 +52,7 @@ class RedundantNullableReturnTypeInspection : AbstractKotlinInspection() {
is KtProperty -> declaration.initializer ?: declaration.accessors.singleOrNull { it.isGetter }?.bodyExpression
else -> null
} ?: return
val actualReturnTypes = body.actualReturnTypes()
val actualReturnTypes = body.actualReturnTypes(declaration)
if (actualReturnTypes.isEmpty() || actualReturnTypes.any { it.isNullable() }) return
val declarationName = declaration.nameAsSafeName.asString()
@@ -69,12 +70,14 @@ class RedundantNullableReturnTypeInspection : AbstractKotlinInspection() {
}
}
private fun KtExpression.actualReturnTypes(): List<KotlinType> {
private fun KtExpression.actualReturnTypes(declaration: KtDeclaration): List<KotlinType> {
val context = analyze()
val dataFlowValueFactory = getResolutionFacade().getDataFlowValueFactory()
val moduleDescriptor = findModuleDescriptor()
val languageVersionSettings = languageVersionSettings
val returnTypes = collectDescendantsOfType<KtReturnExpression>().flatMap {
val returnTypes = collectDescendantsOfType<KtReturnExpression> {
it.labelQualifier == null && it.getParentOfTypes(true, KtNamedFunction::class.java, KtProperty::class.java) == declaration
}.flatMap {
it.returnedExpression.types(context, dataFlowValueFactory, moduleDescriptor, languageVersionSettings)
}
return if (this is KtBlockExpression) {
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test(list: List<Int>): Int?<caret> {
val x = list.mapNotNull {
return@mapNotNull null
}
return 1
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test(list: List<Int>): Int {
val x = list.mapNotNull {
return@mapNotNull null
}
return 1
}
@@ -0,0 +1,6 @@
fun test(): Int?<caret> {
fun f(): Int? {
return null
}
return 1
}
@@ -0,0 +1,6 @@
fun test(): Int {
fun f(): Int? {
return null
}
return 1
}
@@ -8249,6 +8249,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/overridable.kt");
}
@TestMetadata("returnNullableForLambda.kt")
public void testReturnNullableForLambda() throws Exception {
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableForLambda.kt");
}
@TestMetadata("returnNullableForLocalFunction.kt")
public void testReturnNullableForLocalFunction() throws Exception {
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableForLocalFunction.kt");
}
@TestMetadata("returnNullableFromLambdaInBlockBody.kt")
public void testReturnNullableFromLambdaInBlockBody() throws Exception {
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableFromLambdaInBlockBody.kt");