"Move lambda outside parenthesis" should not be available when not valid

This commit is contained in:
Valentin Kipyatkov
2015-05-22 12:47:18 +03:00
parent 25e323e960
commit 3bca1d1f83
7 changed files with 74 additions and 0 deletions
@@ -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) &rarr; 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) &rarr; 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) &rarr; 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) &rarr; 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 }
}
@@ -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");