Redundant nullable return type: fix false positive with elvis return

#KT-41878 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-09-14 23:06:17 +02:00
committed by Vladimir Dolzhenko
parent 51d405e950
commit 0e4bd70c29
4 changed files with 42 additions and 6 deletions
@@ -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<KotlinType> {
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<KtReturnExpression> {
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)
}
@@ -0,0 +1,5 @@
// PROBLEM: none
fun elvisFun(str: String?): String?<caret> {
val v = str?.length ?: return null
return v.toString()
}
@@ -0,0 +1,8 @@
// PROBLEM: none
val foo: String?<caret>
get() {
val s = bar() ?: return null
return s
}
fun bar(): String? = null
@@ -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");