Convert lambda to reference: use fully qualified type names if needed #KT-13438 Fixed
(cherry picked from commit e2e761e)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
a41c4b9a0f
commit
2ab553243c
@@ -24,8 +24,10 @@ import org.jetbrains.kotlin.builtins.isFunctionType
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.core.isVisible
|
import org.jetbrains.kotlin.idea.core.isVisible
|
||||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
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.idea.util.approximateFlexibleTypes
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
@@ -157,13 +159,13 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
|
|||||||
|
|
||||||
override fun applyTo(element: KtLambdaExpression, editor: Editor?) {
|
override fun applyTo(element: KtLambdaExpression, editor: Editor?) {
|
||||||
val body = element.bodyExpression ?: return
|
val body = element.bodyExpression ?: return
|
||||||
val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return) ?: return
|
val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return, shortTypes = false) ?: return
|
||||||
val factory = KtPsiFactory(element)
|
val factory = KtPsiFactory(element)
|
||||||
val lambdaArgument = element.parent as? KtLambdaArgument
|
val lambdaArgument = element.parent as? KtLambdaArgument
|
||||||
if (lambdaArgument == null) {
|
if (lambdaArgument == null) {
|
||||||
// Without lambda argument syntax, just replace lambda with reference
|
// Without lambda argument syntax, just replace lambda with reference
|
||||||
val callableReferenceExpr = factory.createCallableReferenceExpression(referenceName) ?: return
|
val callableReferenceExpr = factory.createCallableReferenceExpression(referenceName) ?: return
|
||||||
element.replace(callableReferenceExpr)
|
(element.replace(callableReferenceExpr) as? KtElement)?.let { ShortenReferences.DEFAULT.process(it) }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Otherwise, replace the whole argument list for lambda argument-using call
|
// Otherwise, replace the whole argument list for lambda argument-using call
|
||||||
@@ -196,10 +198,10 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
|
|||||||
}
|
}
|
||||||
val argumentList = outerCallExpression.valueArgumentList
|
val argumentList = outerCallExpression.valueArgumentList
|
||||||
if (argumentList == null) {
|
if (argumentList == null) {
|
||||||
lambdaArgument.replace(newArgumentList)
|
(lambdaArgument.replace(newArgumentList) as? KtElement)?.let { ShortenReferences.DEFAULT.process(it) }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
argumentList.replace(newArgumentList)
|
(argumentList.replace(newArgumentList) as? KtElement)?.let { ShortenReferences.DEFAULT.process(it) }
|
||||||
lambdaArgument.delete()
|
lambdaArgument.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,11 +210,11 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
|
|||||||
companion object {
|
companion object {
|
||||||
internal fun shouldSuggestToConvert(element: KtLambdaExpression): Boolean {
|
internal fun shouldSuggestToConvert(element: KtLambdaExpression): Boolean {
|
||||||
val body = element.bodyExpression ?: return false
|
val body = element.bodyExpression ?: return false
|
||||||
val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return false) ?: return false
|
val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return false, shortTypes = true) ?: return false
|
||||||
return referenceName.length < element.text.length
|
return referenceName.length < element.text.length
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildReferenceText(expression: KtExpression): String? {
|
private fun buildReferenceText(expression: KtExpression, shortTypes: Boolean): String? {
|
||||||
return when (expression) {
|
return when (expression) {
|
||||||
is KtCallExpression -> "::${expression.getCallReferencedName()}"
|
is KtCallExpression -> "::${expression.getCallReferencedName()}"
|
||||||
is KtDotQualifiedExpression -> {
|
is KtDotQualifiedExpression -> {
|
||||||
@@ -227,7 +229,12 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
|
|||||||
val receiverDescriptor = context[REFERENCE_TARGET, receiver] as? ParameterDescriptor ?: return null
|
val receiverDescriptor = context[REFERENCE_TARGET, receiver] as? ParameterDescriptor ?: return null
|
||||||
val originalReceiverType = receiverDescriptor.type
|
val originalReceiverType = receiverDescriptor.type
|
||||||
val receiverType = originalReceiverType.approximateFlexibleTypes()
|
val receiverType = originalReceiverType.approximateFlexibleTypes()
|
||||||
"$receiverType::$selectorReferenceName"
|
if (shortTypes) {
|
||||||
|
"${IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(receiverType)}::$selectorReferenceName"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"${IdeDescriptorRenderers.SOURCE_CODE.renderType(receiverType)}::$selectorReferenceName"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class Foo {
|
||||||
|
class Bar {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun use() {
|
||||||
|
val f: (Foo.Bar) -> Unit = { <caret>it.foo() }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class Foo {
|
||||||
|
class Bar {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun use() {
|
||||||
|
val f: (Foo.Bar) -> Unit = Foo.Bar::foo
|
||||||
|
}
|
||||||
@@ -3955,6 +3955,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("fqNameForReceiver.kt")
|
||||||
|
public void testFqNameForReceiver() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertLambdaToReference/fqNameForReceiver.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("generic.kt")
|
@TestMetadata("generic.kt")
|
||||||
public void testGeneric() throws Exception {
|
public void testGeneric() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertLambdaToReference/generic.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertLambdaToReference/generic.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user