From e904e56de383d592dbfcadd952a8475e276ab058 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 2 Dec 2016 15:37:52 +0300 Subject: [PATCH] Convert reference to lambda: correct handling of static method references #KT-14982 Fixed --- .../ConvertReferenceToLambdaIntention.kt | 17 +++++++++---- .../convertReferenceToLambda/companion.kt | 11 +++++++++ .../companion.kt.after | 11 +++++++++ .../convertReferenceToLambda/object.kt | 7 ++++++ .../convertReferenceToLambda/static.1.java | 3 +++ .../static.1.java.after | 3 +++ .../convertReferenceToLambda/static.kt | 2 ++ .../convertReferenceToLambda/static.kt.after | 2 ++ .../staticTwoParameters.1.java | 3 +++ .../staticTwoParameters.1.java.after | 3 +++ .../staticTwoParameters.kt | 1 + .../staticTwoParameters.kt.after | 1 + .../intentions/IntentionTestGenerated.java | 24 +++++++++++++++++++ 13 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 idea/testData/intentions/convertReferenceToLambda/companion.kt create mode 100644 idea/testData/intentions/convertReferenceToLambda/companion.kt.after create mode 100644 idea/testData/intentions/convertReferenceToLambda/object.kt create mode 100644 idea/testData/intentions/convertReferenceToLambda/static.1.java create mode 100644 idea/testData/intentions/convertReferenceToLambda/static.1.java.after create mode 100644 idea/testData/intentions/convertReferenceToLambda/static.kt create mode 100644 idea/testData/intentions/convertReferenceToLambda/static.kt.after create mode 100644 idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java create mode 100644 idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java.after create mode 100644 idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt create mode 100644 idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt index 91f6dde8521..08d97e1e2ae 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertReferenceToLambdaIntention.kt @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.expressions.DoubleColonLHS -import org.jetbrains.kotlin.utils.singletonOrEmptyList class ConvertReferenceToLambdaInspection : IntentionBasedInspection(ConvertReferenceToLambdaIntention::class) @@ -51,23 +50,31 @@ class ConvertReferenceToLambdaIntention : SelfTargetingOffsetIndependentIntentio val receiverNameAndType = receiverType?.let { KotlinNameSuggester.suggestNamesByType(it, validator = { name -> name !in parameterNamesAndTypes.map { it.first } }, defaultName = "receiver").first() to it } + val acceptsReceiverAsParameter = receiverNameAndType != null && + (targetDescriptor.dispatchReceiverParameter != null || + targetDescriptor.extensionReceiverParameter != null) val referenceParent = element.parent val insideCall = referenceParent is KtValueArgument val factory = KtPsiFactory(element) val targetName = reference.text - val lambdaParameterNamesAndTypes = receiverNameAndType.singletonOrEmptyList() + parameterNamesAndTypes - val receiverPrefix = receiverNameAndType?.let { it.first + "." } ?: "" + val lambdaParameterNamesAndTypes = + if (acceptsReceiverAsParameter) listOf(receiverNameAndType!!) + parameterNamesAndTypes + else parameterNamesAndTypes + + val receiverPrefix = + if (acceptsReceiverAsParameter) receiverNameAndType!!.first + "." + else receiverExpression?.let { it.text + "." } ?: "" val lambdaExpression = if (insideCall && lambdaParameterNamesAndTypes.size == 1) { factory.createLambdaExpression( parameters = "", body = when { - receiverNameAndType != null -> + acceptsReceiverAsParameter -> if (targetDescriptor is PropertyDescriptor) "it.$targetName" else "it.$targetName()" else -> - "$targetName(it)" + "$receiverPrefix$targetName(it)" } ) } diff --git a/idea/testData/intentions/convertReferenceToLambda/companion.kt b/idea/testData/intentions/convertReferenceToLambda/companion.kt new file mode 100644 index 00000000000..3226fd98f7f --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/companion.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +import Utils.Companion.foo + +val list = listOf(1, 2, 3).map(::foo) + +class Utils { + companion object { + fun foo(x: Int) = x + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/companion.kt.after b/idea/testData/intentions/convertReferenceToLambda/companion.kt.after new file mode 100644 index 00000000000..0d26e12aceb --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/companion.kt.after @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +import Utils.Companion.foo + +val list = listOf(1, 2, 3).map { foo(it) } + +class Utils { + companion object { + fun foo(x: Int) = x + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/object.kt b/idea/testData/intentions/convertReferenceToLambda/object.kt new file mode 100644 index 00000000000..3e21ca06219 --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/object.kt @@ -0,0 +1,7 @@ +// IS_APPLICABLE: false +// WITH_RUNTIME +val list = listOf(1, 2, 3).map(Utils::foo) + +object Utils { + fun foo(x: Int) = x +} \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/static.1.java b/idea/testData/intentions/convertReferenceToLambda/static.1.java new file mode 100644 index 00000000000..cdb4259a301 --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/static.1.java @@ -0,0 +1,3 @@ +class Utils { + public static int foo(int arg) { return arg; } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/static.1.java.after b/idea/testData/intentions/convertReferenceToLambda/static.1.java.after new file mode 100644 index 00000000000..cdb4259a301 --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/static.1.java.after @@ -0,0 +1,3 @@ +class Utils { + public static int foo(int arg) { return arg; } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/static.kt b/idea/testData/intentions/convertReferenceToLambda/static.kt new file mode 100644 index 00000000000..2767a50b8ff --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/static.kt @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val list = listOf(1, 2, 3).map(Utils::foo) \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/static.kt.after b/idea/testData/intentions/convertReferenceToLambda/static.kt.after new file mode 100644 index 00000000000..962c0dadb9e --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/static.kt.after @@ -0,0 +1,2 @@ +// WITH_RUNTIME +val list = listOf(1, 2, 3).map { Utils.foo(it) } \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java new file mode 100644 index 00000000000..28ce580510f --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java @@ -0,0 +1,3 @@ +class Utils { + public static int foo(int x, int y) { return x + y; } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java.after b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java.after new file mode 100644 index 00000000000..28ce580510f --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.1.java.after @@ -0,0 +1,3 @@ +class Utils { + public static int foo(int x, int y) { return x + y; } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt new file mode 100644 index 00000000000..3904b76e612 --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt @@ -0,0 +1 @@ +val x = Utils::foo \ No newline at end of file diff --git a/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt.after b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt.after new file mode 100644 index 00000000000..a7c793e5414 --- /dev/null +++ b/idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt.after @@ -0,0 +1 @@ +val x = { x: Int, y: Int -> Utils.foo(x, y) } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 38ab0d75767..69025beeb08 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -4967,6 +4967,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("companion.kt") + public void testCompanion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/companion.kt"); + doTest(fileName); + } + @TestMetadata("constructor.kt") public void testConstructor() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/constructor.kt"); @@ -5015,6 +5021,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("object.kt") + public void testObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/object.kt"); + doTest(fileName); + } + @TestMetadata("receiverParameter.kt") public void testReceiverParameter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/receiverParameter.kt"); @@ -5027,6 +5039,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("static.kt") + public void testStatic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/static.kt"); + doTest(fileName); + } + + @TestMetadata("staticTwoParameters.kt") + public void testStaticTwoParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/staticTwoParameters.kt"); + doTest(fileName); + } + @TestMetadata("threeParameters.kt") public void testThreeParameters() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/threeParameters.kt");