diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddExclExclCallFixFactories.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddExclExclCallFixFactories.kt index e792e358601..e10ea9a4e9e 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddExclExclCallFixFactories.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddExclExclCallFixFactories.kt @@ -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 { 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()?.isDefinitelyNull() == true) { + return emptyList() + } + return listOfNotNull(target.asAddExclExclCallFix(hasImplicitReceiver = hasImplicitReceiver)) } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/TypeMismatchFactories.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/TypeMismatchFactories.kt index 2efe24dc3fe..e55e46da526 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/TypeMismatchFactories.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/TypeMismatchFactories.kt @@ -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 { diagnostic -> @@ -37,6 +39,14 @@ object TypeMismatchFactories { ): List { // 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()?.isDefinitelyNull() == true) { + return emptyList() + } val nullableExpectedType = expectedType.withNullability(KtTypeNullability.NULLABLE) if (actualType isSubTypeOf nullableExpectedType) { return listOfNotNull(psi.asAddExclExclCallFix()) diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixTestGenerated.java index c24aea87dfd..96d1a3849bc 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/quickfix/HighLevelQuickFixTestGenerated.java @@ -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"); diff --git a/idea/testData/quickfix/addExclExclCall/nullExpression.kt b/idea/testData/quickfix/addExclExclCall/nullExpression.kt index dafab36c9c6..0da26f48e2e 100644 --- a/idea/testData/quickfix/addExclExclCall/nullExpression.kt +++ b/idea/testData/quickfix/addExclExclCall/nullExpression.kt @@ -8,7 +8,4 @@ fun foo(arg: String?) { if (arg == null) { val x: String = arg } -} - -// TODO: Need data flow info from null check -/* IGNORE_FIR */ +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/nullReceiver.fir.kt b/idea/testData/quickfix/addExclExclCall/nullReceiver.fir.kt new file mode 100644 index 00000000000..906797853c1 --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/nullReceiver.fir.kt @@ -0,0 +1,7 @@ +// "Add non-null asserted (!!) call" "false" + +fun foo(arg: String?) { + if (arg == null) { + arg.length + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/nullReceiver.kt b/idea/testData/quickfix/addExclExclCall/nullReceiver.kt new file mode 100644 index 00000000000..eb622ad8eef --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/nullReceiver.kt @@ -0,0 +1,8 @@ +// "Add non-null asserted (!!) call" "true" +// DISABLE-ERRORS + +fun foo(arg: String?) { + if (arg == null) { + arg.length + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/nullReceiver.kt.after b/idea/testData/quickfix/addExclExclCall/nullReceiver.kt.after new file mode 100644 index 00000000000..4446623f4fc --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/nullReceiver.kt.after @@ -0,0 +1,8 @@ +// "Add non-null asserted (!!) call" "true" +// DISABLE-ERRORS + +fun foo(arg: String?) { + if (arg == null) { + arg!!.length + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/typeMismatch/argumentAfterNullCheck.kt b/idea/testData/quickfix/addExclExclCall/typeMismatch/argumentAfterNullCheck.kt index da55e096765..2d6f7dea978 100644 --- a/idea/testData/quickfix/addExclExclCall/typeMismatch/argumentAfterNullCheck.kt +++ b/idea/testData/quickfix/addExclExclCall/typeMismatch/argumentAfterNullCheck.kt @@ -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) {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index c8dfc143316..6e1685e006e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -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");