Redundant nullable return type: fix false positive with elvis return
#KT-41878 Fixed
This commit is contained in:
committed by
Vladimir Dolzhenko
parent
51d405e950
commit
0e4bd70c29
+19
-6
@@ -22,8 +22,8 @@ import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory
|
|||||||
import org.jetbrains.kotlin.idea.util.textRangeIn
|
import org.jetbrains.kotlin.idea.util.textRangeIn
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
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.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.isNullable
|
import org.jetbrains.kotlin.types.isNullable
|
||||||
@@ -47,12 +47,24 @@ class RedundantNullableReturnTypeInspection : AbstractKotlinInspection() {
|
|||||||
|
|
||||||
if (declaration.isOverridable()) return
|
if (declaration.isOverridable()) return
|
||||||
|
|
||||||
val body = when (declaration) {
|
val (body, targetDeclaration) = when (declaration) {
|
||||||
is KtNamedFunction -> declaration.bodyExpression
|
is KtNamedFunction -> {
|
||||||
is KtProperty -> declaration.initializer ?: declaration.accessors.singleOrNull { it.isGetter }?.bodyExpression
|
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
|
else -> null
|
||||||
} ?: return
|
} ?: return
|
||||||
val actualReturnTypes = body.actualReturnTypes(declaration)
|
val actualReturnTypes = body.actualReturnTypes(targetDeclaration)
|
||||||
if (actualReturnTypes.isEmpty() || actualReturnTypes.any { it.isNullable() }) return
|
if (actualReturnTypes.isEmpty() || actualReturnTypes.any { it.isNullable() }) return
|
||||||
|
|
||||||
val declarationName = declaration.nameAsSafeName.asString()
|
val declarationName = declaration.nameAsSafeName.asString()
|
||||||
@@ -72,11 +84,12 @@ class RedundantNullableReturnTypeInspection : AbstractKotlinInspection() {
|
|||||||
|
|
||||||
private fun KtExpression.actualReturnTypes(declaration: KtDeclaration): List<KotlinType> {
|
private fun KtExpression.actualReturnTypes(declaration: KtDeclaration): List<KotlinType> {
|
||||||
val context = analyze()
|
val context = analyze()
|
||||||
|
val declarationDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] ?: return emptyList()
|
||||||
val dataFlowValueFactory = getResolutionFacade().getDataFlowValueFactory()
|
val dataFlowValueFactory = getResolutionFacade().getDataFlowValueFactory()
|
||||||
val moduleDescriptor = findModuleDescriptor()
|
val moduleDescriptor = findModuleDescriptor()
|
||||||
val languageVersionSettings = languageVersionSettings
|
val languageVersionSettings = languageVersionSettings
|
||||||
val returnTypes = collectDescendantsOfType<KtReturnExpression> {
|
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 {
|
}.flatMap {
|
||||||
it.returnedExpression.types(context, dataFlowValueFactory, moduleDescriptor, languageVersionSettings)
|
it.returnedExpression.types(context, dataFlowValueFactory, moduleDescriptor, languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
fun elvisFun(str: String?): String?<caret> {
|
||||||
|
val v = str?.length ?: return null
|
||||||
|
return v.toString()
|
||||||
|
}
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
val foo: String?<caret>
|
||||||
|
get() {
|
||||||
|
val s = bar() ?: return null
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(): String? = null
|
||||||
+10
@@ -8269,6 +8269,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/returnNullableFromLambdaInSingleExpressionBody.kt");
|
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")
|
@TestMetadata("singleExpressionBody.kt")
|
||||||
public void testSingleExpressionBody() throws Exception {
|
public void testSingleExpressionBody() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/function/singleExpressionBody.kt");
|
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");
|
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")
|
@TestMetadata("var.kt")
|
||||||
public void testVar() throws Exception {
|
public void testVar() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/property/var.kt");
|
runTest("idea/testData/inspectionsLocal/redundantNullableReturnType/property/var.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user