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:
committed by
Roman Golyshev
parent
bc34f7f7f5
commit
2fd3af73eb
+20
-15
@@ -37,27 +37,32 @@ class ConvertReferenceToLambdaIntention : SelfTargetingOffsetIndependentIntentio
|
|||||||
val context = element.analyze(BodyResolveMode.PARTIAL)
|
val context = element.analyze(BodyResolveMode.PARTIAL)
|
||||||
val reference = element.callableReference
|
val reference = element.callableReference
|
||||||
val targetDescriptor = context[REFERENCE_TARGET, reference] as? CallableMemberDescriptor ?: return
|
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 valueArgumentParent = element.parent as? KtValueArgument
|
||||||
val callGrandParent = valueArgumentParent?.parent?.parent as? KtCallExpression
|
val callGrandParent = valueArgumentParent?.parent?.parent as? KtCallExpression
|
||||||
val resolvedCall = callGrandParent?.getResolvedCall(context)
|
val resolvedCall = callGrandParent?.getResolvedCall(context)
|
||||||
val matchingParameterType = resolvedCall?.getParameterForArgument(valueArgumentParent)?.type
|
val matchingParameterType = resolvedCall?.getParameterForArgument(valueArgumentParent)?.type
|
||||||
val matchingParameterIsExtension = matchingParameterType?.isExtensionFunctionType ?: false
|
val matchingParameterIsExtension = matchingParameterType?.isExtensionFunctionType ?: false
|
||||||
|
|
||||||
val acceptsReceiverAsParameter = receiverNameAndType != null && !matchingParameterIsExtension &&
|
val receiverExpression = element.receiverExpression
|
||||||
(targetDescriptor.dispatchReceiverParameter != null ||
|
val receiverType = receiverExpression?.let {
|
||||||
targetDescriptor.extensionReceiverParameter != null)
|
(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 factory = KtPsiFactory(element)
|
||||||
val targetName = reference.text
|
val targetName = reference.text
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
fun test() {
|
||||||
|
foo1(<caret>::convert2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo1(convert: (Int) -> Unit) {}
|
||||||
|
|
||||||
|
fun convert2(i: Int, j: Int = 0) {}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
fun test() {
|
||||||
|
foo1 { convert2(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo1(convert: (Int) -> Unit) {}
|
||||||
|
|
||||||
|
fun convert2(i: Int, j: Int = 0) {}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
fun test() {
|
||||||
|
foo2(<caret>::convert3)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo2(convert: (Int, Int) -> Unit) {}
|
||||||
|
|
||||||
|
fun convert3(i: Int, j: Int, k: Int = 0) {}
|
||||||
Vendored
+7
@@ -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) {}
|
||||||
Vendored
+7
@@ -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) {}
|
||||||
Vendored
+7
@@ -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");
|
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")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
runTest("idea/testData/intentions/convertReferenceToLambda/simple.kt");
|
runTest("idea/testData/intentions/convertReferenceToLambda/simple.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user