From 4f678fa85cc3ff78319c5c6cff4fbcd2f5a9fe86 Mon Sep 17 00:00:00 2001 From: Dmitry Neverov Date: Wed, 28 Jun 2017 07:31:09 +0300 Subject: [PATCH] Do not suggest !! on expression which is always null Related to KT-14643 --- .../kotlin/idea/quickfix/ExclExclCallFixes.kt | 17 +++++++++++++++-- .../quickfix/addExclExclCall/nullExpression.kt | 11 +++++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 6 ++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 idea/testData/quickfix/addExclExclCall/nullExpression.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt index 04d843b1e3b..664509c0ecc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt @@ -30,12 +30,15 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf @@ -128,11 +131,21 @@ class AddExclExclCallFix(psiElement: PsiElement, val checkImplicitReceivers: Boo } } else if (psiElement is KtExpression) { - if (checkImplicitReceivers && psiElement.getResolvedCall(psiElement.analyze())?.getImplicitReceiverValue() != null) { + val context = psiElement.analyze() + if (checkImplicitReceivers && psiElement.getResolvedCall(context)?.getImplicitReceiverValue() != null) { val expressionToReplace = psiElement.parent as? KtCallExpression ?: psiElement expressionToReplace.expressionForCall(implicitReceiver = true) } - else psiElement.expressionForCall() + else { + context[BindingContext.EXPRESSION_TYPE_INFO, psiElement]?.let { + val type = it.type + if (type != null) { + val nullability = it.dataFlowInfo.getStableNullability(DataFlowValueFactory.createDataFlowValue(psiElement, type, context, psiElement.findModuleDescriptor())) + if (!nullability.canBeNonNull()) return null + } + } + psiElement.expressionForCall() + } } else { null diff --git a/idea/testData/quickfix/addExclExclCall/nullExpression.kt b/idea/testData/quickfix/addExclExclCall/nullExpression.kt new file mode 100644 index 00000000000..0da26f48e2e --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/nullExpression.kt @@ -0,0 +1,11 @@ +// "Add non-null asserted (!!) call" "false" +// ACTION: Add 'toString()' call +// ACTION: Change type of 'x' to 'String?' +// ACTION: Remove braces from 'if' statement +// ERROR: Type mismatch: inferred type is String? but String was expected + +fun foo(arg: String?) { + if (arg == null) { + val x: String = arg + } +} \ 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 da2eb4612a5..04acfc59723 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -272,6 +272,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("nullExpression.kt") + public void testNullExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addExclExclCall/nullExpression.kt"); + doTest(fileName); + } + @TestMetadata("operationIn.kt") public void testOperationIn() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/addExclExclCall/operationIn.kt");