From 35459d2ca70d12c223770273eff6091bd6738ef2 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Thu, 21 May 2020 20:16:54 +0900 Subject: [PATCH] "Add not-null asserted (!!) call": add '!!' to receiver of function reference #KT-37841 Fixed --- .../kotlin/idea/quickfix/ExclExclCallFixes.kt | 22 +++++++++++++------ .../addExclExclCall/functionReference.kt | 8 +++++++ .../functionReference.kt.after | 8 +++++++ .../addExclExclCall/functionReference2.kt | 12 ++++++++++ .../functionReference2.kt.after | 12 ++++++++++ .../addExclExclCall/functionReference3.kt | 8 +++++++ .../functionReference3.kt.after | 8 +++++++ .../idea/quickfix/QuickFixTestGenerated.java | 15 +++++++++++++ 8 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 idea/testData/quickfix/addExclExclCall/functionReference.kt create mode 100644 idea/testData/quickfix/addExclExclCall/functionReference.kt.after create mode 100644 idea/testData/quickfix/addExclExclCall/functionReference2.kt create mode 100644 idea/testData/quickfix/addExclExclCall/functionReference2.kt.after create mode 100644 idea/testData/quickfix/addExclExclCall/functionReference3.kt create mode 100644 idea/testData/quickfix/addExclExclCall/functionReference3.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt index 8f33e80febf..a3fb52a7471 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExclExclCallFixes.kt @@ -48,6 +48,7 @@ import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.isValidOperator +import org.jetbrains.kotlin.utils.addToStdlib.safeAs abstract class ExclExclCallFix(psiElement: PsiElement) : KotlinQuickFixAction(psiElement) { @@ -96,10 +97,15 @@ class AddExclExclCallFix(psiElement: PsiElement, val checkImplicitReceivers: Boo val expr = getExpressionForIntroduceCall() ?: return val modifiedExpression = expr.expression + val psiFactory = KtPsiFactory(project) val exclExclExpression = if (expr.implicitReceiver) { - KtPsiFactory(project).createExpressionByPattern("this!!.$0", modifiedExpression) + if (modifiedExpression is KtCallableReferenceExpression) { + psiFactory.createExpressionByPattern("this!!::$0", modifiedExpression.callableReference) + } else { + psiFactory.createExpressionByPattern("this!!.$0", modifiedExpression) + } } else { - KtPsiFactory(project).createExpressionByPattern("$0!!", modifiedExpression) + psiFactory.createExpressionByPattern("$0!!", modifiedExpression) } modifiedExpression.replace(exclExclExpression) } @@ -129,24 +135,26 @@ class AddExclExclCallFix(psiElement: PsiElement, val checkImplicitReceivers: Boo } } is KtExpression -> { + val parent = psiElement.parent val context = psiElement.analyze() if (checkImplicitReceivers && psiElement.getResolvedCall(context)?.getImplicitReceiverValue() is ExtensionReceiver) { - val expressionToReplace = psiElement.parent as? KtCallExpression ?: psiElement + val expressionToReplace = parent as? KtCallExpression ?: parent as? KtCallableReferenceExpression ?: psiElement expressionToReplace.expressionForCall(implicitReceiver = true) } else { - context[BindingContext.EXPRESSION_TYPE_INFO, psiElement]?.let { + val targetElement = parent.safeAs()?.receiverExpression ?: psiElement + context[BindingContext.EXPRESSION_TYPE_INFO, targetElement]?.let { val type = it.type - val dataFlowValueFactory = psiElement.getResolutionFacade().getDataFlowValueFactory() + val dataFlowValueFactory = targetElement.getResolutionFacade().getDataFlowValueFactory() if (type != null) { val nullability = it.dataFlowInfo.getStableNullability( - dataFlowValueFactory.createDataFlowValue(psiElement, type, context, psiElement.findModuleDescriptor()) + dataFlowValueFactory.createDataFlowValue(targetElement, type, context, targetElement.findModuleDescriptor()) ) if (!nullability.canBeNonNull()) return null } } - psiElement.expressionForCall() + targetElement.expressionForCall() } } else -> null diff --git a/idea/testData/quickfix/addExclExclCall/functionReference.kt b/idea/testData/quickfix/addExclExclCall/functionReference.kt new file mode 100644 index 00000000000..a7becab8230 --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/functionReference.kt @@ -0,0 +1,8 @@ +// "Add non-null asserted (!!) call" "true" +class Foo { + fun f() = 1 +} + +fun test(foo: Foo?) { + val f = foo::f +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/functionReference.kt.after b/idea/testData/quickfix/addExclExclCall/functionReference.kt.after new file mode 100644 index 00000000000..bae9309032e --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/functionReference.kt.after @@ -0,0 +1,8 @@ +// "Add non-null asserted (!!) call" "true" +class Foo { + fun f() = 1 +} + +fun test(foo: Foo?) { + val f = foo!!::f +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/functionReference2.kt b/idea/testData/quickfix/addExclExclCall/functionReference2.kt new file mode 100644 index 00000000000..402ad17b4ad --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/functionReference2.kt @@ -0,0 +1,12 @@ +// "Add non-null asserted (!!) call" "true" +class Foo { + val bar = Bar() +} + +class Bar { + fun f() = 1 +} + +fun test(foo: Foo?) { + val f = foo?.bar::f +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/functionReference2.kt.after b/idea/testData/quickfix/addExclExclCall/functionReference2.kt.after new file mode 100644 index 00000000000..443f80786c2 --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/functionReference2.kt.after @@ -0,0 +1,12 @@ +// "Add non-null asserted (!!) call" "true" +class Foo { + val bar = Bar() +} + +class Bar { + fun f() = 1 +} + +fun test(foo: Foo?) { + val f = foo?.bar!!::f +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/functionReference3.kt b/idea/testData/quickfix/addExclExclCall/functionReference3.kt new file mode 100644 index 00000000000..47c982cc7be --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/functionReference3.kt @@ -0,0 +1,8 @@ +// "Add non-null asserted (!!) call" "true" +class Foo { + fun f() = 1 +} + +fun Foo?.test() { + val f = ::f +} \ No newline at end of file diff --git a/idea/testData/quickfix/addExclExclCall/functionReference3.kt.after b/idea/testData/quickfix/addExclExclCall/functionReference3.kt.after new file mode 100644 index 00000000000..6ba8cfc8c13 --- /dev/null +++ b/idea/testData/quickfix/addExclExclCall/functionReference3.kt.after @@ -0,0 +1,8 @@ +// "Add non-null asserted (!!) call" "true" +class Foo { + fun f() = 1 +} + +fun Foo?.test() { + val f = this!!::f +} \ 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 466c3ed4e4f..39b227b294c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -641,6 +641,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/addExclExclCall/array4.kt"); } + @TestMetadata("functionReference.kt") + public void testFunctionReference() throws Exception { + runTest("idea/testData/quickfix/addExclExclCall/functionReference.kt"); + } + + @TestMetadata("functionReference2.kt") + public void testFunctionReference2() throws Exception { + runTest("idea/testData/quickfix/addExclExclCall/functionReference2.kt"); + } + + @TestMetadata("functionReference3.kt") + public void testFunctionReference3() throws Exception { + runTest("idea/testData/quickfix/addExclExclCall/functionReference3.kt"); + } + @TestMetadata("implicit.kt") public void testImplicit() throws Exception { runTest("idea/testData/quickfix/addExclExclCall/implicit.kt");