Specify lambda signature: handle special parameters correctly

So #KT-17372 Fixed
This commit is contained in:
Mikhail Glukhikh
2017-04-12 16:05:44 +03:00
parent 6453e10d44
commit 02e9a3d027
6 changed files with 51 additions and 2 deletions
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -44,13 +45,21 @@ class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention<KtLambdaE
return functionDescriptor.valueParameters.none { it.type.isError }
}
private fun ValueParameterDescriptor.render(psiName: String?): String = IdeDescriptorRenderers.SOURCE_CODE.let {
"${psiName ?: it.renderName(name)}: ${it.renderType(type)}"
}
override fun applyTo(element: KtLambdaExpression, editor: Editor?) {
val functionLiteral = element.functionLiteral
val functionDescriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.FUNCTION, functionLiteral]!!
val parameterString = functionDescriptor.valueParameters
.map { "${it.name}: ${IdeDescriptorRenderers.SOURCE_CODE.renderType(it.type)}" }
.joinToString(", ")
.mapIndexed { index, parameterDescriptor ->
parameterDescriptor.render(psiName = functionLiteral.valueParameters.getOrNull(index)?.let {
it.name ?: it.destructuringDeclaration?.text
} )
}
.joinToString()
applyWithParameters(element, parameterString)
}
@@ -0,0 +1,7 @@
class Declaration {
fun lambdaType(p: Int, f: (Int) -> Int) = f(p)
}
fun call(declaration: Declaration) {
declaration.lambdaType(10) {<caret> _ -> 11 }
}
@@ -0,0 +1,7 @@
class Declaration {
fun lambdaType(p: Int, f: (Int) -> Int) = f(p)
}
fun call(declaration: Declaration) {
declaration.lambdaType(10) { _: Int -> 11 }
}
@@ -0,0 +1,7 @@
data class Declaration(val x: Int, val y: Int) {
fun lambdaType(p: Declaration, f: (Declaration) -> Int) = f(p)
}
fun call(declaration: Declaration) {
declaration.lambdaType(declaration) {<caret> (x, y) -> 11 }
}
@@ -0,0 +1,7 @@
data class Declaration(val x: Int, val y: Int) {
fun lambdaType(p: Declaration, f: (Declaration) -> Int) = f(p)
}
fun call(declaration: Declaration) {
declaration.lambdaType(declaration) { (x, y): Declaration -> 11 }
}
@@ -14407,6 +14407,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/specifyExplicitLambdaSignature"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("anonymous.kt")
public void testAnonymous() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/anonymous.kt");
doTest(fileName);
}
@TestMetadata("coercionToUnit.kt")
public void testCoercionToUnit() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/coercionToUnit.kt");
@@ -14419,6 +14425,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("destructuring.kt")
public void testDestructuring() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/destructuring.kt");
doTest(fileName);
}
@TestMetadata("emptyParamListWithBrackets.kt")
public void testEmptyParamListWithBrackets() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyExplicitLambdaSignature/emptyParamListWithBrackets.kt");