diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyExplicitLambdaSignatureIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyExplicitLambdaSignatureIntention.kt index 7da8ca9ef12..a8d84c9ec6d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyExplicitLambdaSignatureIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/SpecifyExplicitLambdaSignatureIntention.kt @@ -25,23 +25,15 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtPsiFactory -import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.isError -class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention(KtLambdaExpression::class.java, "Specify explicit lambda signature"), LowPriorityAction { +class SpecifyExplicitLambdaSignatureIntention : + SelfTargetingIntention(KtLambdaExpression::class.java, "Specify explicit lambda signature"), LowPriorityAction { override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean { - val arrow = element.functionLiteral.arrow - if (arrow != null) { - if (caretOffset > arrow.endOffset) return false - if (element.valueParameters.all { it.typeReference != null }) return false - } - else { - if (!element.leftCurlyBrace.textRange.containsOffset(caretOffset)) return false - } - + if (element.functionLiteral.arrow != null && element.valueParameters.all { it.typeReference != null }) return false val functionDescriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.FUNCTION, element.functionLiteral] ?: return false return functionDescriptor.valueParameters.none { it.type.isError } } @@ -55,12 +47,12 @@ class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention - parameterDescriptor.render(psiName = functionLiteral.valueParameters.getOrNull(index)?.let { - it.name ?: it.destructuringDeclaration?.text - } ) - } - .joinToString() + .mapIndexed { index, parameterDescriptor -> + parameterDescriptor.render(psiName = functionLiteral.valueParameters.getOrNull(index)?.let { + it.name ?: it.destructuringDeclaration?.text + }) + } + .joinToString() applyWithParameters(element, parameterString) } @@ -72,8 +64,7 @@ class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention Int) {} +fun test() { + foo { it.length } +} diff --git a/idea/testData/intentions/specifyExplicitLambdaSignature/cursorOnRightBrace.kt.after b/idea/testData/intentions/specifyExplicitLambdaSignature/cursorOnRightBrace.kt.after new file mode 100644 index 00000000000..bb769c5e6e4 --- /dev/null +++ b/idea/testData/intentions/specifyExplicitLambdaSignature/cursorOnRightBrace.kt.after @@ -0,0 +1,4 @@ +fun foo(f: (String) -> Int) {} +fun test() { + foo { it: String -> it.length } +} diff --git a/idea/testData/intentions/specifyExplicitLambdaSignature/invalidCursorPosition.kt b/idea/testData/intentions/specifyExplicitLambdaSignature/invalidCursorPosition.kt deleted file mode 100644 index 6d25834fb08..00000000000 --- a/idea/testData/intentions/specifyExplicitLambdaSignature/invalidCursorPosition.kt +++ /dev/null @@ -1,4 +0,0 @@ -// IS_APPLICABLE: false -fun main() { - val sum : (Int, Int) -> Int = { x, y -> x + y } -} diff --git a/idea/testData/quickfix/replaceWithSafeCallForScopeFunction/letWithWrongImplicitThis.kt b/idea/testData/quickfix/replaceWithSafeCallForScopeFunction/letWithWrongImplicitThis.kt index fd37a156781..aef816ee857 100644 --- a/idea/testData/quickfix/replaceWithSafeCallForScopeFunction/letWithWrongImplicitThis.kt +++ b/idea/testData/quickfix/replaceWithSafeCallForScopeFunction/letWithWrongImplicitThis.kt @@ -4,6 +4,7 @@ // ACTION: Introduce local variable // ACTION: Move lambda argument into parentheses // ACTION: Replace with safe (this?.) call +// ACTION: Specify explicit lambda signature // ERROR: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? fun String?.foo(a: String?) { diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 3559e0301dd..1c25acca029 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -14682,6 +14682,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("cursorOnRightBrace.kt") + public void testCursorOnRightBrace() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/cursorOnRightBrace.kt"); + doTest(fileName); + } + @TestMetadata("delegate.kt") public void testDelegate() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/delegate.kt"); @@ -14718,12 +14724,6 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } - @TestMetadata("invalidCursorPosition.kt") - public void testInvalidCursorPosition() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/invalidCursorPosition.kt"); - doTest(fileName); - } - @TestMetadata("lambdaWithLambdaAsParam.kt") public void testLambdaWithLambdaAsParam() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/lambdaWithLambdaAsParam.kt");