diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt index c54240f550e..de3ae9ad115 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/WrapWithSafeLetCallFix.kt @@ -20,12 +20,16 @@ import com.intellij.codeInsight.intention.HighPriorityAction import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.builtins.isFunctionType +import org.jetbrains.kotlin.descriptors.PropertyDescriptor 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.resolveToCall import org.jetbrains.kotlin.idea.core.KotlinNameSuggester 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 @@ -48,13 +52,25 @@ class WrapWithSafeLetCallFix( val nullableExpression = nullableExpressionPointer.element ?: return val qualifiedExpression = element.getQualifiedExpressionForSelector() val receiverExpression = qualifiedExpression?.receiverExpression + val isInvokingFunctionType = if (nullableExpression.parent is KtCallExpression) { + val property = nullableExpression.mainReference?.resolve() as? KtProperty + (property?.descriptor as? PropertyDescriptor)?.type?.isFunctionType == true + } else { + false + } + val factory = KtPsiFactory(element) - val nullableText = nullableExpression.text + val nullableText = if (receiverExpression != null && isInvokingFunctionType) { + "${receiverExpression.text}${qualifiedExpression.operationSign.value}${nullableExpression.text}" + } else { + nullableExpression.text + } val validator = NewDeclarationNameValidator(element, nullableExpression, NewDeclarationNameValidator.Target.VARIABLES) val name = KotlinNameSuggester.suggestNameByName("it", validator) + nullableExpression.replace(factory.createExpression(name)) val underLetExpression = when { - receiverExpression != null -> factory.createExpressionByPattern("$0.$1", receiverExpression, element) + receiverExpression != null && !isInvokingFunctionType -> factory.createExpressionByPattern("$0.$1", receiverExpression, element) else -> element } val wrapped = when (name) { diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType.kt b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType.kt new file mode 100644 index 00000000000..bdce4074000 --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType.kt @@ -0,0 +1,10 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME + +interface Foo { + val bar: ((Int) -> Unit)? +} + +fun test(foo: Foo) { + foo.bar(1) +} diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType.kt.after b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType.kt.after new file mode 100644 index 00000000000..dc43415d40b --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType.kt.after @@ -0,0 +1,10 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME + +interface Foo { + val bar: ((Int) -> Unit)? +} + +fun test(foo: Foo) { + foo.bar?.let { it(1) } +} diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType2.kt b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType2.kt new file mode 100644 index 00000000000..3e313c9c180 --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType2.kt @@ -0,0 +1,10 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME + +interface Foo { + val bar: ((Int) -> Unit)? +} + +fun Foo.test() { + bar(1) +} \ No newline at end of file diff --git a/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType2.kt.after b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType2.kt.after new file mode 100644 index 00000000000..d2168201a2e --- /dev/null +++ b/idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType2.kt.after @@ -0,0 +1,10 @@ +// "Wrap with '?.let { ... }' call" "true" +// WITH_RUNTIME + +interface Foo { + val bar: ((Int) -> Unit)? +} + +fun Foo.test() { + bar?.let { it(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 b45c6db092d..a48dfb53164 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -15474,6 +15474,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/wrapWithSafeLetCall/invokeFuncUnsafe.kt"); } + @TestMetadata("invokeFunctionType.kt") + public void testInvokeFunctionType() throws Exception { + runTest("idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType.kt"); + } + + @TestMetadata("invokeFunctionType2.kt") + public void testInvokeFunctionType2() throws Exception { + runTest("idea/testData/quickfix/wrapWithSafeLetCall/invokeFunctionType2.kt"); + } + @TestMetadata("invokeUnsafe.kt") public void testInvokeUnsafe() throws Exception { runTest("idea/testData/quickfix/wrapWithSafeLetCall/invokeUnsafe.kt");