Fix "move suspicious reference into parentheses" for functional types
So #KT-21743 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
3fbf85dc37
commit
fbd06dc74f
+22
-10
@@ -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
|
||||||
@@ -33,7 +35,7 @@ class MoveSuspiciousCallableReferenceIntoParenthesesInspection : AbstractKotlinI
|
|||||||
val parentResolvedCall = lambdaExpression.getParentResolvedCall(context)
|
val parentResolvedCall = lambdaExpression.getParentResolvedCall(context)
|
||||||
if (parentResolvedCall != null) {
|
if (parentResolvedCall != null) {
|
||||||
val originalParameterDescriptor =
|
val originalParameterDescriptor =
|
||||||
parentResolvedCall.getParameterForArgument(lambdaExpression.parent as? ValueArgument)?.original
|
parentResolvedCall.getParameterForArgument(lambdaExpression.parent as? ValueArgument)?.original
|
||||||
if (originalParameterDescriptor != null) {
|
if (originalParameterDescriptor != null) {
|
||||||
val expectedType = originalParameterDescriptor.type
|
val expectedType = originalParameterDescriptor.type
|
||||||
if (expectedType.isBuiltinFunctionalType) {
|
if (expectedType.isBuiltinFunctionalType) {
|
||||||
@@ -43,10 +45,10 @@ class MoveSuspiciousCallableReferenceIntoParenthesesInspection : AbstractKotlinI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
lambdaExpression,
|
lambdaExpression,
|
||||||
"Suspicious callable reference as the only lambda element",
|
"Suspicious callable reference as the only lambda element",
|
||||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
IntentionWrapper(MoveIntoParenthesesIntention(), lambdaExpression.containingFile)
|
IntentionWrapper(MoveIntoParenthesesIntention(), lambdaExpression.containingFile)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,15 +56,25 @@ class MoveSuspiciousCallableReferenceIntoParenthesesInspection : AbstractKotlinI
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MoveIntoParenthesesIntention : ConvertLambdaToReferenceIntention(
|
class MoveIntoParenthesesIntention : ConvertLambdaToReferenceIntention(
|
||||||
"Move suspicious callable reference into parentheses '()'"
|
"Move suspicious callable reference into parentheses '()'"
|
||||||
) {
|
) {
|
||||||
override fun buildReferenceText(element: KtLambdaExpression): String? {
|
override fun buildReferenceText(element: KtLambdaExpression): String? {
|
||||||
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
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Test {
|
||||||
|
fun function(s: String): Boolean = true
|
||||||
|
fun test() {
|
||||||
|
"".let {<caret> this::function }
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Test {
|
||||||
|
fun function(s: String): Boolean = true
|
||||||
|
fun test() {
|
||||||
|
"".let(this::function)
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Test {
|
||||||
|
fun function(s: String): Boolean = true
|
||||||
|
fun test() {
|
||||||
|
"".let {<caret> ::function }
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Test {
|
||||||
|
fun function(s: String): Boolean = true
|
||||||
|
fun test() {
|
||||||
|
"".let(::function)
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Test {
|
||||||
|
val lambda = { s: String -> true }
|
||||||
|
fun test() {
|
||||||
|
"".let {<caret> lambda::invoke }
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Test {
|
||||||
|
val lambda = { s: String -> true }
|
||||||
|
fun test() {
|
||||||
|
"".let(lambda::invoke)
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user