mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-06 15:51:57 +00:00
Refactor: Move canMoveLambdaOutsideParentheses() function to idea-core module
This commit is contained in:
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiWhiteSpace
|
||||
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
@@ -100,6 +101,32 @@ private fun shouldLambdaParameterBeNamed(args: List<ValueArgument>, callExpr: Kt
|
||||
return if (calee.valueParameters.any { it.isVarArg }) true else calee.valueParameters.size - 1 > args.size
|
||||
}
|
||||
|
||||
fun KtCallExpression.getLastLambdaExpression(): KtLambdaExpression? {
|
||||
if (lambdaArguments.isNotEmpty()) return null
|
||||
return valueArguments.lastOrNull()?.getArgumentExpression()?.unpackFunctionLiteral()
|
||||
}
|
||||
|
||||
fun KtCallExpression.canMoveLambdaOutsideParentheses(): Boolean {
|
||||
if (getLastLambdaExpression() == null) return false
|
||||
|
||||
val callee = calleeExpression
|
||||
if (callee is KtNameReferenceExpression) {
|
||||
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||
val targets = bindingContext[BindingContext.REFERENCE_TARGET, callee]?.let { listOf(it) }
|
||||
?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, callee]
|
||||
?: listOf()
|
||||
val candidates = targets.filterIsInstance<FunctionDescriptor>()
|
||||
// if there are functions among candidates but none of them have last function parameter then not show the intention
|
||||
if (candidates.isNotEmpty() && candidates.none {
|
||||
val lastParameter = it.valueParameters.lastOrNull()
|
||||
lastParameter != null && lastParameter.type.isFunctionType
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun KtCallExpression.moveFunctionLiteralOutsideParentheses() {
|
||||
assert(lambdaArguments.isEmpty())
|
||||
|
||||
@@ -17,58 +17,31 @@
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.core.getLastLambdaExpression
|
||||
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.KtValueArgument
|
||||
import org.jetbrains.kotlin.psi.KtValueArgumentList
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containsInside
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
class MoveLambdaOutsideParenthesesIntention : SelfTargetingIntention<KtCallExpression>(KtCallExpression::class.java, "Move lambda argument out of parentheses") {
|
||||
companion object {
|
||||
private fun getLambdaExpression(callExpression: KtCallExpression): KtLambdaExpression? {
|
||||
if (callExpression.lambdaArguments.isNotEmpty()) return null
|
||||
return callExpression.valueArguments.lastOrNull()?.getArgumentExpression()?.unpackFunctionLiteral()
|
||||
}
|
||||
|
||||
fun canMove(element: KtCallExpression): Boolean {
|
||||
if (getLambdaExpression(element) == null) return false
|
||||
|
||||
val callee = element.calleeExpression
|
||||
if (callee is KtNameReferenceExpression) {
|
||||
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
|
||||
val targets = bindingContext[BindingContext.REFERENCE_TARGET, callee]?.let { listOf(it) }
|
||||
?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, callee]
|
||||
?: listOf()
|
||||
val candidates = targets.filterIsInstance<FunctionDescriptor>()
|
||||
// if there are functions among candidates but none of them have last function parameter then not show the intention
|
||||
if (candidates.isNotEmpty() && candidates.none {
|
||||
val lastParameter = it.valueParameters.lastOrNull()
|
||||
lastParameter != null && lastParameter.type.isFunctionType
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun moveFunctionLiteralOutsideParenthesesIfPossible(expression: KtLambdaExpression) {
|
||||
val call = ((expression.parent as? KtValueArgument)?.parent as? KtValueArgumentList)?.parent as? KtCallExpression ?: return
|
||||
if (canMove(call)) {
|
||||
if (call.canMoveLambdaOutsideParentheses()) {
|
||||
call.moveFunctionLiteralOutsideParentheses()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isApplicableTo(element: KtCallExpression, caretOffset: Int): Boolean {
|
||||
if (!canMove(element)) return false
|
||||
if (!element.canMoveLambdaOutsideParentheses()) return false
|
||||
|
||||
val lambdaExpression = getLambdaExpression(element) ?: return false
|
||||
val lambdaExpression = element.getLastLambdaExpression() ?: return false
|
||||
val argument = lambdaExpression.getStrictParentOfType<KtValueArgument>() ?: return false
|
||||
if (caretOffset < argument.startOffset) return false
|
||||
val bodyRange = lambdaExpression.bodyExpression?.textRange ?: return true
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
@@ -36,7 +37,10 @@ import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.contentRange
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
@@ -152,7 +156,7 @@ class ObjectLiteralToLambdaIntention : SelfTargetingRangeIntention<KtObjectLiter
|
||||
?.parent as? KtCallExpression
|
||||
if (parentCall != null && RedundantSamConstructorInspection.samConstructorCallsToBeConverted(parentCall).singleOrNull() == callExpression) {
|
||||
RedundantSamConstructorInspection.replaceSamConstructorCall(callExpression)
|
||||
if (MoveLambdaOutsideParenthesesIntention.canMove(parentCall)) {
|
||||
if (parentCall.canMoveLambdaOutsideParentheses()) {
|
||||
parentCall.moveFunctionLiteralOutsideParentheses()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user