From 6db0785615465b90ba8253cc068b4fdeb231b4b6 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Wed, 8 Jul 2020 09:50:03 +0900 Subject: [PATCH] Wrap with let: apply to unsafe qualified expression #KT-18125 Fixed --- .../idea/quickfix/WrapWithSafeLetCallFix.kt | 28 +++++++++++-------- .../quickfix/wrapWithSafeLetCall/unsafe.kt | 7 +++++ .../wrapWithSafeLetCall/unsafe.kt.after | 7 +++++ .../quickfix/wrapWithSafeLetCall/unsafe2.kt | 13 +++++++++ .../wrapWithSafeLetCall/unsafe2.kt.after | 13 +++++++++ .../unsafeForNullableParameter.kt | 12 ++++++++ .../idea/quickfix/QuickFixTestGenerated.java | 15 ++++++++++ 7 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt create mode 100644 idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt.after create mode 100644 idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt create mode 100644 idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt.after create mode 100644 idea/testData/quickfix/wrapWithSafeLetCall/unsafeForNullableParameter.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt index de3ae9ad115..2b7cd0920f5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt @@ -31,10 +31,9 @@ import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer -import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow -import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector +import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument +import org.jetbrains.kotlin.types.isNullable import org.jetbrains.kotlin.types.typeUtil.isNullabilityMismatch class WrapWithSafeLetCallFix( @@ -83,18 +82,23 @@ class WrapWithSafeLetCallFix( object UnsafeFactory : KotlinSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { val element = diagnostic.psiElement - if (element is KtNameReferenceExpression) { val resolvedCall = element.resolveToCall() if (resolvedCall?.call?.callType != Call.CallType.INVOKE) return null } - - val expression = element.getParentOfType(true) ?: return null - - val parent = element.parent - val nullableExpression = (parent as? KtCallExpression)?.calleeExpression ?: return null - - return WrapWithSafeLetCallFix(expression, nullableExpression) + val expression = element.getStrictParentOfType() ?: return null + val (targetExpression, nullableExpression) = if (expression is KtQualifiedExpression) { + val argument = expression.parent as? KtValueArgument ?: return null + val call = argument.getStrictParentOfType() ?: return null + val parameter = call.resolveToCall()?.getParameterForArgument(argument) ?: return null + if (parameter.type.isNullable()) return null + val targetExpression = call.getLastParentOfTypeInRow() ?: call + targetExpression to expression.receiverExpression + } else { + val nullableExpression = (element.parent as? KtCallExpression)?.calleeExpression ?: return null + expression to nullableExpression + } + return WrapWithSafeLetCallFix(targetExpression, nullableExpression) } } diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt new file mode 100644 index 00000000000..68f2aac1d51 --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt @@ -0,0 +1,7 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME +fun foo(s: String) {} + +fun bar(s: String?) { + foo(s.substring(1)) +} \ No newline at end of file diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt.after b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt.after new file mode 100644 index 00000000000..9407c2ece76 --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt.after @@ -0,0 +1,7 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME +fun foo(s: String) {} + +fun bar(s: String?) { + s?.let { foo(it.substring(1)) } +} \ No newline at end of file diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt new file mode 100644 index 00000000000..5d426e3b941 --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt @@ -0,0 +1,13 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME +class A(val b: B) +class B { + fun c(s: String) {} +} + +class X(val y: Y) +class Y(val z: String) + +fun test(a: A, x: X?) { + a.b.c(x?.y.z) +} \ No newline at end of file diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt.after b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt.after new file mode 100644 index 00000000000..7667693e8f6 --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt.after @@ -0,0 +1,13 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME +class A(val b: B) +class B { + fun c(s: String) {} +} + +class X(val y: Y) +class Y(val z: String) + +fun test(a: A, x: X?) { + x?.y?.let { a.b.c(it.z) } +} \ No newline at end of file diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/unsafeForNullableParameter.kt b/idea/testData/quickfix/wrapWithSafeLetCall/unsafeForNullableParameter.kt new file mode 100644 index 00000000000..164a2517068 --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/unsafeForNullableParameter.kt @@ -0,0 +1,12 @@ +// "Wrap with '?.let { ... }' call" "false" +// ACTION: Add 's =' to argument +// ACTION: Add non-null asserted (!!) call +// ACTION: Replace with safe (?.) call +// ACTION: Surround with null check +// DISABLE-ERRORS +// WITH_RUNTIME +fun foo(s: String?) {} + +fun bar(s: String?) { + foo(s.substring(1)) +} \ 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 eb731ac49e8..359e6751ad5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -15529,6 +15529,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/wrapWithSafeLetCall/objectQualifier.kt"); } + @TestMetadata("unsafe.kt") + public void testUnsafe() throws Exception { + runTest("idea/testData/quickfix/wrapWithSafeLetCall/unsafe.kt"); + } + + @TestMetadata("unsafe2.kt") + public void testUnsafe2() throws Exception { + runTest("idea/testData/quickfix/wrapWithSafeLetCall/unsafe2.kt"); + } + + @TestMetadata("unsafeForNullableParameter.kt") + public void testUnsafeForNullableParameter() throws Exception { + runTest("idea/testData/quickfix/wrapWithSafeLetCall/unsafeForNullableParameter.kt"); + } + @TestMetadata("unstableValue.kt") public void testUnstableValue() throws Exception { runTest("idea/testData/quickfix/wrapWithSafeLetCall/unstableValue.kt");