"Move lambda outside parenthesis" should not be available when not valid
This commit is contained in:
+22
@@ -17,16 +17,38 @@
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.util.psiModificationUtil.moveLambdaOutsideParentheses
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
public class MoveLambdaOutsideParenthesesIntention : JetSelfTargetingIntention<JetCallExpression>(javaClass(), "Move lambda argument out of parentheses") {
|
||||
override fun isApplicableTo(element: JetCallExpression, caretOffset: Int): Boolean {
|
||||
val argument = element.getValueArgumentsInParentheses().lastOrNull() ?: return false
|
||||
val expression = argument.getArgumentExpression() ?: return false
|
||||
val functionLiteral = getFunctionLiteral(expression) ?: return false
|
||||
|
||||
val callee = element.getCalleeExpression()
|
||||
if (callee is JetSimpleNameExpression) {
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
val targets = bindingContext[BindingContext.REFERENCE_TARGET, callee]?.let { listOf(it) }
|
||||
?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, callee]
|
||||
?: listOf()
|
||||
val candidates = targets.filterIsInstance<FunctionDescriptor>()
|
||||
// if there are functions among candidates but none of them have last function parameter then not show the intention
|
||||
if (candidates.isNotEmpty() && candidates.none {
|
||||
val lastParameter = it.getValueParameters().lastOrNull()
|
||||
lastParameter != null && KotlinBuiltIns.isFunctionOrExtensionFunctionType(lastParameter.getType())
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (caretOffset < argument.asElement().startOffset) return false
|
||||
val bodyRange = functionLiteral.getBodyExpression()?.getTextRange() ?: return true
|
||||
return !bodyRange.containsInside(caretOffset)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// IS_AVAILABLE: true
|
||||
// ERROR: <html>None of the following functions can be called with the arguments supplied. <ul><li>bar(<font color=red><b>Int = ...</b></font>, <font color=red><b>(Int) → Int</b></font>) <i>defined in</i> root package</li><li>bar(<font color=red><b>Int</b></font>, <font color=red><b>Int</b></font>, <font color=red><b>(Int) → Int</b></font>) <i>defined in</i> root package</li></ul></html>
|
||||
// ERROR: Unresolved reference: it
|
||||
|
||||
fun foo() {
|
||||
bar(<caret>{ it })
|
||||
}
|
||||
|
||||
fun bar(a: Int = 0, f: (Int) -> Int) { }
|
||||
fun bar(a: Int, b: Int, f: (Int) -> Int) { }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// IS_AVAILABLE: true
|
||||
// ERROR: <html>None of the following functions can be called with the arguments supplied. <ul><li>bar(<font color=red><b>Int = ...</b></font>, <font color=red><b>(Int) → Int</b></font>) <i>defined in</i> root package</li><li>bar(<font color=red><b>Int</b></font>, <font color=red><b>Int</b></font>, <font color=red><b>(Int) → Int</b></font>) <i>defined in</i> root package</li></ul></html>
|
||||
// ERROR: Unresolved reference: it
|
||||
|
||||
fun foo() {
|
||||
bar <caret>{ it }
|
||||
}
|
||||
|
||||
fun bar(a: Int = 0, f: (Int) -> Int) { }
|
||||
fun bar(a: Int, b: Int, f: (Int) -> Int) { }
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo(p: (Int, () -> Int) -> Unit) {
|
||||
p(1, <caret>{ 2 })
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo(p: (Int, () -> Int) -> Unit) {
|
||||
p(1) <caret>{ 2 }
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// IS_APPLICABLE: false
|
||||
fun foo() {
|
||||
bar(<caret>{ it })
|
||||
}
|
||||
|
||||
fun bar(b: (Int) -> Int, option: Int = 0) { }
|
||||
@@ -4921,6 +4921,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/moveLambdaOutsideParentheses"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ambigousOverload.kt")
|
||||
public void testAmbigousOverload() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaOutsideParentheses/ambigousOverload.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functionalValueCall.kt")
|
||||
public void testFunctionalValueCall() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaOutsideParentheses/functionalValueCall.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inapplicable1.kt")
|
||||
public void testInapplicable1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaOutsideParentheses/inapplicable1.kt");
|
||||
@@ -4939,6 +4951,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inapplicableOptionalParametersAfter.kt")
|
||||
public void testInapplicableOptionalParametersAfter() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaOutsideParentheses/inapplicableOptionalParametersAfter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("labeledLambda.kt")
|
||||
public void testLabeledLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaOutsideParentheses/labeledLambda.kt");
|
||||
|
||||
Reference in New Issue
Block a user