Do not suggest "convert ref to lambda" for reflect types #KT-19283 Fixed

This commit is contained in:
Mikhail Glukhikh
2017-12-21 18:45:36 +03:00
parent fc93e7a727
commit 3f00592443
5 changed files with 69 additions and 2 deletions
@@ -18,8 +18,10 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME
import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
@@ -29,10 +31,12 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET import org.jetbrains.kotlin.resolve.BindingContext.REFERENCE_TARGET
import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
@@ -41,7 +45,6 @@ class ConvertReferenceToLambdaInspection : IntentionBasedInspection<KtCallableRe
class ConvertReferenceToLambdaIntention : SelfTargetingOffsetIndependentIntention<KtCallableReferenceExpression>( class ConvertReferenceToLambdaIntention : SelfTargetingOffsetIndependentIntention<KtCallableReferenceExpression>(
KtCallableReferenceExpression::class.java, "Convert reference to lambda" KtCallableReferenceExpression::class.java, "Convert reference to lambda"
) { ) {
private val SOURCE_RENDERER = IdeDescriptorRenderers.SOURCE_CODE
override fun applyTo(element: KtCallableReferenceExpression, editor: Editor?) { override fun applyTo(element: KtCallableReferenceExpression, editor: Editor?) {
val context = element.analyze(BodyResolveMode.PARTIAL) val context = element.analyze(BodyResolveMode.PARTIAL)
@@ -127,5 +130,15 @@ class ConvertReferenceToLambdaIntention : SelfTargetingOffsetIndependentIntentio
} }
} }
override fun isApplicableTo(element: KtCallableReferenceExpression) = true override fun isApplicableTo(element: KtCallableReferenceExpression): Boolean {
val context = element.analyze(BodyResolveMode.PARTIAL)
val expectedType = context[BindingContext.EXPECTED_EXPRESSION_TYPE, element] ?: return true
val expectedTypeDescriptor = expectedType.constructor.declarationDescriptor as? ClassDescriptor ?: return true
val expectedTypeFqName = expectedTypeDescriptor.fqNameSafe
return expectedTypeFqName.parent() == KOTLIN_REFLECT_FQ_NAME
}
companion object {
private val SOURCE_RENDERER = IdeDescriptorRenderers.SOURCE_CODE
}
} }
@@ -0,0 +1,12 @@
// IS_APPLICABLE: false
import kotlin.reflect.KFunction
fun <P : Any> p(p: KFunction<P>) {}
class B {
fun getS(): String = ""
init {
p(<caret>this::getS)
}
}
@@ -0,0 +1,12 @@
// IS_APPLICABLE: false
import kotlin.reflect.KProperty
fun <P : Any> p(p: KProperty<P>) {}
class B {
val s: String = ""
init {
p(<caret>this::s)
}
}
@@ -0,0 +1,12 @@
// IS_APPLICABLE: false
import kotlin.reflect.KProperty0
fun <P : Any> p(p: KProperty0<P>) {}
class B {
val s: String = ""
init {
p(<caret>this::s)
}
}
@@ -5471,6 +5471,24 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("kfunction.kt")
public void testKfunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/kfunction.kt");
doTest(fileName);
}
@TestMetadata("kproperty.kt")
public void testKproperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/kproperty.kt");
doTest(fileName);
}
@TestMetadata("kproperty0.kt")
public void testKproperty0() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/kproperty0.kt");
doTest(fileName);
}
@TestMetadata("length.kt") @TestMetadata("length.kt")
public void testLength() throws Exception { public void testLength() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/length.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertReferenceToLambda/length.kt");