FoldInitializerAndIfToElvisInspection: don't report when 'var' variable has no explicit type and it's used as not nullable type

#KT-38349 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-04-18 14:20:16 +09:00
committed by Yan Zhulanow
parent db140b2815
commit 915dc6ce91
8 changed files with 80 additions and 0 deletions
@@ -29,14 +29,19 @@ import org.jetbrains.kotlin.idea.util.hasComments
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.PsiChildRange
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class FoldInitializerAndIfToElvisInspection : AbstractApplicabilityBasedInspection<KtIfExpression>(KtIfExpression::class.java) {
override fun inspectionText(element: KtIfExpression): String = KotlinBundle.message("if.null.return.break.foldable.to")
@@ -137,6 +142,15 @@ class FoldInitializerAndIfToElvisInspection : AbstractApplicabilityBasedInspecti
val checkedType = ifExpression.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference]
val variableType = (prevStatement.resolveToDescriptorIfAny() as? VariableDescriptor)?.type
if (checkedType != null && variableType != null && !checkedType.isSubtypeOf(variableType)) return null
} else if (prevStatement.isVar && operationExpression is KtBinaryExpression) {
val ifEndOffset = ifExpression.endOffset
val context = ifExpression.analyze()
val isUsedAsNotNullable = ReferencesSearch.search(prevStatement, LocalSearchScope(prevStatement.parent)).any {
if (it.element.startOffset <= ifEndOffset) return@any false
val type = it.element.safeAs<KtExpression>()?.getType(context) ?: return@any false
!type.isNullable()
}
if (isUsedAsNotNullable) return null
}
val statement = if (then is KtBlockExpression) then.statements.singleOrNull() else then
@@ -0,0 +1,8 @@
// PROBLEM: none
fun test(foo: Int?, bar: Int): Int {
var i = foo
<caret>if (i == null) {
return bar
}
return i
}
@@ -0,0 +1,12 @@
// PROBLEM: none
fun test(foo: Int?, bar: Int): Int {
var i = foo
<caret>if (i == null) {
return bar
}
baz(i)
val j = i + 1
return j
}
fun baz(i: Int?) {}
@@ -0,0 +1,7 @@
fun test(foo: Int?, bar: Int): Int? {
var i = foo
<caret>if (i == null) {
return bar
}
return i
}
@@ -0,0 +1,4 @@
fun test(foo: Int?, bar: Int): Int? {
var i: Int? = foo ?: return bar
return i
}
@@ -0,0 +1,9 @@
fun test(foo: Int?, bar: Int): Int {
var i = foo
<caret>if (i == null) {
return bar
}
return baz(i)
}
fun baz(i: Int?) = 1
@@ -0,0 +1,6 @@
fun test(foo: Int?, bar: Int): Int {
var i: Int? = foo ?: return bar
return baz(i)
}
fun baz(i: Int?) = 1
@@ -4923,6 +4923,26 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
public void testVar() throws Exception {
runTest("idea/testData/inspectionsLocal/foldInitializerAndIfToElvis/Var.kt");
}
@TestMetadata("VarUsedAsNotNullable.kt")
public void testVarUsedAsNotNullable() throws Exception {
runTest("idea/testData/inspectionsLocal/foldInitializerAndIfToElvis/VarUsedAsNotNullable.kt");
}
@TestMetadata("VarUsedAsNotNullable2.kt")
public void testVarUsedAsNotNullable2() throws Exception {
runTest("idea/testData/inspectionsLocal/foldInitializerAndIfToElvis/VarUsedAsNotNullable2.kt");
}
@TestMetadata("VarUsedAsNullable.kt")
public void testVarUsedAsNullable() throws Exception {
runTest("idea/testData/inspectionsLocal/foldInitializerAndIfToElvis/VarUsedAsNullable.kt");
}
@TestMetadata("VarUsedAsNullable2.kt")
public void testVarUsedAsNullable2() throws Exception {
runTest("idea/testData/inspectionsLocal/foldInitializerAndIfToElvis/VarUsedAsNullable2.kt");
}
}
@TestMetadata("idea/testData/inspectionsLocal/forEachParameterNotUsed")