Lambda to reference: check potential reference arguments by descriptors and not by names #KT-14420 Fixed
This commit is contained in:
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.approximateFlexibleTypes
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.FUNCTION
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
@@ -105,10 +106,14 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
|
||||
val receiverShift = if (callHasReceiver) 1 else 0
|
||||
val parametersCount = if (hasSpecification) lambdaExpression.valueParameters.size else 1
|
||||
if (parametersCount != callableArgumentsCount + receiverShift) return false
|
||||
val lambdaValueParameters = context[FUNCTION, lambdaExpression.functionLiteral]?.valueParameters ?: return false
|
||||
if (explicitReceiver != null) {
|
||||
if (explicitReceiver !is KtNameReferenceExpression) return false
|
||||
val callReceiverDescriptor = context[REFERENCE_TARGET, explicitReceiver] as? ParameterDescriptor ?: return false
|
||||
val receiverType = callReceiverDescriptor.type
|
||||
if (lambdaValueParameters.isEmpty()) return false
|
||||
val explicitReceiverTarget = context[REFERENCE_TARGET, explicitReceiver] as? ParameterDescriptor ?: return false
|
||||
if (explicitReceiverTarget != lambdaValueParameters[0]) return false
|
||||
|
||||
val receiverType = explicitReceiverTarget.type
|
||||
// No exotic receiver types
|
||||
if (receiverType.isTypeParameter() || receiverType.isError || receiverType.isDynamic() ||
|
||||
!receiverType.constructor.isDenotable || receiverType.isFunctionType) return false
|
||||
@@ -121,16 +126,14 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
|
||||
explicitReceiver, null, context, explicitReceiver.getResolutionFacade()
|
||||
)) return false
|
||||
}
|
||||
|
||||
val parameterName = if (hasSpecification) lambdaExpression.valueParameters[0].name else "it"
|
||||
if (explicitReceiver.getReferencedName() != parameterName) return false
|
||||
}
|
||||
// Same lambda / references function parameter order
|
||||
if (callableExpression is KtCallExpression) {
|
||||
if (lambdaValueParameters.size < receiverShift + callableExpression.valueArguments.size) return false
|
||||
callableExpression.valueArguments.forEachIndexed { i, argument ->
|
||||
val argumentExpression = argument.getArgumentExpression() as? KtNameReferenceExpression ?: return false
|
||||
val parameterName = if (hasSpecification) lambdaExpression.valueParameters[i + receiverShift].name else "it"
|
||||
if (argumentExpression.getReferencedName() != parameterName) return false
|
||||
val argumentTarget = context[REFERENCE_TARGET, argumentExpression] as? ValueParameterDescriptor ?: return false
|
||||
if (argumentTarget != lambdaValueParameters[i + receiverShift]) return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo() {
|
||||
listOf(1).forEach { run { <caret>bar(it) } }
|
||||
}
|
||||
|
||||
fun bar(i: Int) {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo() {
|
||||
listOf(1).forEach { run { <caret>it.bar() } }
|
||||
}
|
||||
|
||||
fun Int.bar() {
|
||||
}
|
||||
@@ -4123,6 +4123,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedLambda.kt")
|
||||
public void testNestedLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertLambdaToReference/nestedLambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedLambdaWithReceiver.kt")
|
||||
public void testNestedLambdaWithReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertLambdaToReference/nestedLambdaWithReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nullable.kt")
|
||||
public void testNullable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertLambdaToReference/nullable.kt");
|
||||
|
||||
Reference in New Issue
Block a user