FIR IDE: Don't offer AddExclExclCallFix when expression is definitely

null.
This commit is contained in:
Mark Punzalan
2021-06-01 23:30:51 +00:00
committed by teamcityserver
parent 97ea901507
commit 2773506f4c
9 changed files with 55 additions and 8 deletions
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.unwrapParenthesesLabelsAndAnnotations
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object AddExclExclCallFixFactories {
val unsafeCallFactory = diagnosticFixFactory<KtFirDiagnostic.UnsafeCall> { diagnostic ->
@@ -79,6 +80,15 @@ object AddExclExclCallFixFactories {
else -> return emptyList()
}
// We don't want to offer AddExclExclCallFix if we know the expression is definitely null, e.g.:
//
// if (nullableInt == null) {
// val x = nullableInt.length // No AddExclExclCallFix here
// }
if (target?.safeAs<KtExpression>()?.isDefinitelyNull() == true) {
return emptyList()
}
return listOfNotNull(target.asAddExclExclCallFix(hasImplicitReceiver = hasImplicitReceiver))
}
@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.idea.frontend.api.types.KtTypeNullability
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object TypeMismatchFactories {
val argumentTypeMismatchFactory = diagnosticFixFactory<KtFirDiagnostic.ArgumentTypeMismatch> { diagnostic ->
@@ -37,6 +39,14 @@ object TypeMismatchFactories {
): List<IntentionAction> {
// TODO: Add more fixes than just AddExclExclCallFix when available.
if (!expectedType.canBeNull && actualType.canBeNull) {
// We don't want to offer AddExclExclCallFix if we know the expression is definitely null, e.g.:
//
// if (nullableInt == null) {
// val x: Int = nullableInt // No AddExclExclCallFix here
// }
if (psi.safeAs<KtExpression>()?.isDefinitelyNull() == true) {
return emptyList()
}
val nullableExpectedType = expectedType.withNullability(KtTypeNullability.NULLABLE)
if (actualType isSubTypeOf nullableExpectedType) {
return listOfNotNull(psi.asAddExclExclCallFix())
@@ -324,6 +324,11 @@ public class HighLevelQuickFixTestGenerated extends AbstractHighLevelQuickFixTes
runTest("idea/testData/quickfix/addExclExclCall/nullExpression.kt");
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
runTest("idea/testData/quickfix/addExclExclCall/nullReceiver.kt");
}
@TestMetadata("operationBinary.kt")
public void testOperationBinary() throws Exception {
runTest("idea/testData/quickfix/addExclExclCall/operationBinary.kt");
+1 -4
View File
@@ -8,7 +8,4 @@ fun foo(arg: String?) {
if (arg == null) {
val x: String = arg<caret>
}
}
// TODO: Need data flow info from null check
/* IGNORE_FIR */
}
@@ -0,0 +1,7 @@
// "Add non-null asserted (!!) call" "false"
fun foo(arg: String?) {
if (arg == null) {
arg<caret>.length
}
}
@@ -0,0 +1,8 @@
// "Add non-null asserted (!!) call" "true"
// DISABLE-ERRORS
fun foo(arg: String?) {
if (arg == null) {
arg<caret>.length
}
}
@@ -0,0 +1,8 @@
// "Add non-null asserted (!!) call" "true"
// DISABLE-ERRORS
fun foo(arg: String?) {
if (arg == null) {
arg!!.length
}
}
@@ -12,7 +12,4 @@ fun test(i: Int?) {
}
}
fun other(i: Int) {}
// TODO: Need data flow info from null check
/* IGNORE_FIR */
fun other(i: Int) {}
@@ -737,6 +737,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
runTest("idea/testData/quickfix/addExclExclCall/nullExpression.kt");
}
@TestMetadata("nullReceiver.kt")
public void testNullReceiver() throws Exception {
runTest("idea/testData/quickfix/addExclExclCall/nullReceiver.kt");
}
@TestMetadata("operationBinary.kt")
public void testOperationBinary() throws Exception {
runTest("idea/testData/quickfix/addExclExclCall/operationBinary.kt");