Make "Specify explicit lambda signature" available on whole lambda
So #KT-22492 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
059a797e10
commit
5499078fcc
+10
-19
@@ -25,23 +25,15 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences
|
|||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.isError
|
import org.jetbrains.kotlin.types.isError
|
||||||
|
|
||||||
class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention<KtLambdaExpression>(KtLambdaExpression::class.java, "Specify explicit lambda signature"), LowPriorityAction {
|
class SpecifyExplicitLambdaSignatureIntention :
|
||||||
|
SelfTargetingIntention<KtLambdaExpression>(KtLambdaExpression::class.java, "Specify explicit lambda signature"), LowPriorityAction {
|
||||||
|
|
||||||
override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean {
|
override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean {
|
||||||
val arrow = element.functionLiteral.arrow
|
if (element.functionLiteral.arrow != null && element.valueParameters.all { it.typeReference != null }) return false
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
val functionDescriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.FUNCTION, element.functionLiteral] ?: return false
|
val functionDescriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.FUNCTION, element.functionLiteral] ?: return false
|
||||||
return functionDescriptor.valueParameters.none { it.type.isError }
|
return functionDescriptor.valueParameters.none { it.type.isError }
|
||||||
}
|
}
|
||||||
@@ -55,12 +47,12 @@ class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention<KtLambdaE
|
|||||||
val functionDescriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.FUNCTION, functionLiteral]!!
|
val functionDescriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.FUNCTION, functionLiteral]!!
|
||||||
|
|
||||||
val parameterString = functionDescriptor.valueParameters
|
val parameterString = functionDescriptor.valueParameters
|
||||||
.mapIndexed { index, parameterDescriptor ->
|
.mapIndexed { index, parameterDescriptor ->
|
||||||
parameterDescriptor.render(psiName = functionLiteral.valueParameters.getOrNull(index)?.let {
|
parameterDescriptor.render(psiName = functionLiteral.valueParameters.getOrNull(index)?.let {
|
||||||
it.name ?: it.destructuringDeclaration?.text
|
it.name ?: it.destructuringDeclaration?.text
|
||||||
} )
|
})
|
||||||
}
|
}
|
||||||
.joinToString()
|
.joinToString()
|
||||||
applyWithParameters(element, parameterString)
|
applyWithParameters(element, parameterString)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,8 +64,7 @@ class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention<KtLambdaE
|
|||||||
val oldParameterList = functionLiteral.valueParameterList
|
val oldParameterList = functionLiteral.valueParameterList
|
||||||
if (oldParameterList != null && newParameterList != null) {
|
if (oldParameterList != null && newParameterList != null) {
|
||||||
oldParameterList.replace(newParameterList)
|
oldParameterList.replace(newParameterList)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val openBraceElement = functionLiteral.lBrace
|
val openBraceElement = functionLiteral.lBrace
|
||||||
val nextSibling = openBraceElement.nextSibling
|
val nextSibling = openBraceElement.nextSibling
|
||||||
val addNewline = nextSibling is PsiWhiteSpace && nextSibling.text?.contains("\n") ?: false
|
val addNewline = nextSibling is PsiWhiteSpace && nextSibling.text?.contains("\n") ?: false
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(f: (String) -> Int) {}
|
||||||
|
fun test() {
|
||||||
|
foo { it.length <caret>}
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
fun foo(f: (String) -> Int) {}
|
||||||
|
fun test() {
|
||||||
|
foo { it: String -> it.length <caret>}
|
||||||
|
}
|
||||||
-4
@@ -1,4 +0,0 @@
|
|||||||
// IS_APPLICABLE: false
|
|
||||||
fun main() {
|
|
||||||
val sum : (Int, Int) -> Int = { x, y -> <caret>x + y }
|
|
||||||
}
|
|
||||||
+1
@@ -4,6 +4,7 @@
|
|||||||
// ACTION: Introduce local variable
|
// ACTION: Introduce local variable
|
||||||
// ACTION: Move lambda argument into parentheses
|
// ACTION: Move lambda argument into parentheses
|
||||||
// ACTION: Replace with safe (this?.) call
|
// 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?
|
// ERROR: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
|
||||||
|
|
||||||
fun String?.foo(a: String?) {
|
fun String?.foo(a: String?) {
|
||||||
|
|||||||
+6
-6
@@ -14682,6 +14682,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("delegate.kt")
|
||||||
public void testDelegate() throws Exception {
|
public void testDelegate() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/delegate.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/delegate.kt");
|
||||||
@@ -14718,12 +14724,6 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("lambdaWithLambdaAsParam.kt")
|
||||||
public void testLambdaWithLambdaAsParam() throws Exception {
|
public void testLambdaWithLambdaAsParam() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/lambdaWithLambdaAsParam.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/lambdaWithLambdaAsParam.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user