Convert reference to lambda: fix it works correctly when referenced function has default argument

#KT-17222 Fixed
#KT-24138 Fixed
#KT-39532
This commit is contained in:
Toshiaki Kameyama
2020-06-12 17:48:47 +09:00
committed by Roman Golyshev
parent bc34f7f7f5
commit 2fd3af73eb
8 changed files with 77 additions and 15 deletions
@@ -37,27 +37,32 @@ class ConvertReferenceToLambdaIntention : SelfTargetingOffsetIndependentIntentio
val context = element.analyze(BodyResolveMode.PARTIAL)
val reference = element.callableReference
val targetDescriptor = context[REFERENCE_TARGET, reference] as? CallableMemberDescriptor ?: return
val parameterNamesAndTypes = targetDescriptor.valueParameters.map { it.name.asString() to it.type }
val receiverExpression = element.receiverExpression
val receiverType = receiverExpression?.let {
(context[DOUBLE_COLON_LHS, it] as? DoubleColonLHS.Type)?.type
}
val receiverNameAndType = receiverType?.let {
KotlinNameSuggester.suggestNamesByType(it, validator = { name ->
name !in parameterNamesAndTypes.map { pair -> pair.first }
}, defaultName = "receiver").first() to it
}
val valueArgumentParent = element.parent as? KtValueArgument
val callGrandParent = valueArgumentParent?.parent?.parent as? KtCallExpression
val resolvedCall = callGrandParent?.getResolvedCall(context)
val matchingParameterType = resolvedCall?.getParameterForArgument(valueArgumentParent)?.type
val matchingParameterIsExtension = matchingParameterType?.isExtensionFunctionType ?: false
val acceptsReceiverAsParameter = receiverNameAndType != null && !matchingParameterIsExtension &&
(targetDescriptor.dispatchReceiverParameter != null ||
targetDescriptor.extensionReceiverParameter != null)
val receiverExpression = element.receiverExpression
val receiverType = receiverExpression?.let {
(context[DOUBLE_COLON_LHS, it] as? DoubleColonLHS.Type)?.type
}
val acceptsReceiverAsParameter = receiverType != null && !matchingParameterIsExtension &&
(targetDescriptor.dispatchReceiverParameter != null || targetDescriptor.extensionReceiverParameter != null)
val parameterNamesAndTypes = targetDescriptor.valueParameters.map { it.name.asString() to it.type }.let {
if (matchingParameterType != null) {
val parameterSize = matchingParameterType.arguments.size - (if (acceptsReceiverAsParameter) 2 else 1)
if (parameterSize >= 0) it.take(parameterSize) else it
} else {
it
}
}
val receiverNameAndType = receiverType?.let {
KotlinNameSuggester.suggestNamesByType(it, validator = { name ->
name !in parameterNamesAndTypes.map { pair -> pair.first }
}, defaultName = "receiver").first() to it
}
val factory = KtPsiFactory(element)
val targetName = reference.text
@@ -0,0 +1,7 @@
fun test() {
foo1(<caret>::convert2)
}
fun foo1(convert: (Int) -> Unit) {}
fun convert2(i: Int, j: Int = 0) {}
@@ -0,0 +1,7 @@
fun test() {
foo1 { convert2(it) }
}
fun foo1(convert: (Int) -> Unit) {}
fun convert2(i: Int, j: Int = 0) {}
@@ -0,0 +1,7 @@
fun test() {
foo2(<caret>::convert3)
}
fun foo2(convert: (Int, Int) -> Unit) {}
fun convert3(i: Int, j: Int, k: Int = 0) {}
@@ -0,0 +1,7 @@
fun test() {
foo2 { i, j -> convert3(i, j) }
}
fun foo2(convert: (Int, Int) -> Unit) {}
fun convert3(i: Int, j: Int, k: Int = 0) {}
@@ -0,0 +1,7 @@
fun test() {
bar(<caret>Int::foo)
}
fun Int.foo(x: Int, y: Int = 42) = x + y
fun bar(f: (Int, Int) -> Int) {}
@@ -0,0 +1,7 @@
fun test() {
bar { i, x -> i.foo(x) }
}
fun Int.foo(x: Int, y: Int = 42) = x + y
fun bar(f: (Int, Int) -> Int) {}
@@ -6500,6 +6500,21 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/convertReferenceToLambda/receiverParameter.kt");
}
@TestMetadata("referencedFunctionWithDefaultArugment.kt")
public void testReferencedFunctionWithDefaultArugment() throws Exception {
runTest("idea/testData/intentions/convertReferenceToLambda/referencedFunctionWithDefaultArugment.kt");
}
@TestMetadata("referencedFunctionWithDefaultArugment2.kt")
public void testReferencedFunctionWithDefaultArugment2() throws Exception {
runTest("idea/testData/intentions/convertReferenceToLambda/referencedFunctionWithDefaultArugment2.kt");
}
@TestMetadata("referencedFunctionWithDefaultArugment3.kt")
public void testReferencedFunctionWithDefaultArugment3() throws Exception {
runTest("idea/testData/intentions/convertReferenceToLambda/referencedFunctionWithDefaultArugment3.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/testData/intentions/convertReferenceToLambda/simple.kt");