Fix "move suspicious reference into parentheses" for functional types

So #KT-21743 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-02-19 17:44:37 +03:00
committed by Mikhail Glukhikh
parent 3fbf85dc37
commit fbd06dc74f
8 changed files with 82 additions and 10 deletions
@@ -13,9 +13,11 @@ import com.intellij.psi.PsiElementVisitor
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.intentions.ConvertLambdaToReferenceIntention import org.jetbrains.kotlin.idea.intentions.ConvertLambdaToReferenceIntention
import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.psi.ValueArgument
@@ -60,9 +62,19 @@ class MoveSuspiciousCallableReferenceIntoParenthesesInspection : AbstractKotlinI
val callableReferenceExpression = val callableReferenceExpression =
element.bodyExpression?.statements?.singleOrNull() as? KtCallableReferenceExpression ?: return null element.bodyExpression?.statements?.singleOrNull() as? KtCallableReferenceExpression ?: return null
val callableReference = callableReferenceExpression.callableReference val callableReference = callableReferenceExpression.callableReference
val resolvedCall = callableReference.resolveToCall(BodyResolveMode.FULL) val receiverExpression = callableReferenceExpression.receiverExpression
val receiverValue = resolvedCall?.let { it.extensionReceiver ?: it.dispatchReceiver } val receiver = if (receiverExpression == null) {
return (receiverValue?.let { "${it.type}" } ?: "") + "::${callableReference.text}" ""
} else {
val descriptor = receiverExpression.getCallableDescriptor()
if (descriptor == null || descriptor is ValueParameterDescriptor)
callableReference.resolveToCall(BodyResolveMode.FULL)
?.let { it.extensionReceiver ?: it.dispatchReceiver }
?.let { "${it.type}" } ?: ""
else
receiverExpression.text
}
return "$receiver::${callableReference.text}"
} }
override fun isApplicableTo(element: KtLambdaExpression) = true override fun isApplicableTo(element: KtLambdaExpression) = true
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class Test {
fun function(s: String): Boolean = true
fun test() {
"".let {<caret> this::function }
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class Test {
fun function(s: String): Boolean = true
fun test() {
"".let(this::function)
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class Test {
fun function(s: String): Boolean = true
fun test() {
"".let {<caret> ::function }
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class Test {
fun function(s: String): Boolean = true
fun test() {
"".let(::function)
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class Test {
val lambda = { s: String -> true }
fun test() {
"".let {<caret> lambda::invoke }
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
class Test {
val lambda = { s: String -> true }
fun test() {
"".let(lambda::invoke)
}
}
@@ -2301,6 +2301,18 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("explicitThisReceiver.kt")
public void testExplicitThisReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses/explicitThisReceiver.kt");
doTest(fileName);
}
@TestMetadata("implicitThisReceiver.kt")
public void testImplicitThisReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses/implicitThisReceiver.kt");
doTest(fileName);
}
@TestMetadata("it.kt") @TestMetadata("it.kt")
public void testIt() throws Exception { public void testIt() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses/it.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses/it.kt");
@@ -2348,6 +2360,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses/parameter2.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses/parameter2.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("variableReceiver.kt")
public void testVariableReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/moveSuspiciousCallableReferenceIntoParentheses/variableReceiver.kt");
doTest(fileName);
}
} }
@TestMetadata("idea/testData/inspectionsLocal/nullChecksToSafeCall") @TestMetadata("idea/testData/inspectionsLocal/nullChecksToSafeCall")