Convert lambda to reference: use fully qualified type names if needed #KT-13438 Fixed

(cherry picked from commit e2e761e)
This commit is contained in:
Mikhail Glukhikh
2016-08-31 15:39:01 +03:00
committed by Mikhail Glukhikh
parent a41c4b9a0f
commit 2ab553243c
4 changed files with 46 additions and 7 deletions
@@ -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");