KT-18482: "Move lambda argument to parenthesis" action generate uncompilable code fixed (#1226)
* KT-18482 fixed * Moved code to separate method and changed code to cover few more cases. * Code style fixes.
This commit is contained in:
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -43,7 +44,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import org.jetbrains.kotlin.types.isError
|
import org.jetbrains.kotlin.types.isError
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
inline fun <reified T: PsiElement> PsiElement.replaced(newElement: T): T {
|
inline fun <reified T : PsiElement> PsiElement.replaced(newElement: T): T {
|
||||||
val result = replace(newElement)
|
val result = replace(newElement)
|
||||||
return if (result is T)
|
return if (result is T)
|
||||||
result
|
result
|
||||||
@@ -51,7 +52,8 @@ inline fun <reified T: PsiElement> PsiElement.replaced(newElement: T): T {
|
|||||||
(result as KtParenthesizedExpression).expression as T
|
(result as KtParenthesizedExpression).expression as T
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST") fun <T: PsiElement> T.copied(): T = copy() as T
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T : PsiElement> T.copied(): T = copy() as T
|
||||||
|
|
||||||
fun KtLambdaArgument.moveInsideParentheses(bindingContext: BindingContext): KtCallExpression {
|
fun KtLambdaArgument.moveInsideParentheses(bindingContext: BindingContext): KtCallExpression {
|
||||||
return moveInsideParenthesesAndReplaceWith(this.getArgumentExpression(), bindingContext)
|
return moveInsideParenthesesAndReplaceWith(this.getArgumentExpression(), bindingContext)
|
||||||
@@ -70,7 +72,8 @@ fun KtLambdaArgument.moveInsideParenthesesAndReplaceWith(
|
|||||||
val newCallExpression = oldCallExpression.copy() as KtCallExpression
|
val newCallExpression = oldCallExpression.copy() as KtCallExpression
|
||||||
|
|
||||||
val psiFactory = KtPsiFactory(project)
|
val psiFactory = KtPsiFactory(project)
|
||||||
val argument = if (newCallExpression.getValueArgumentsInParentheses().any { it.isNamed() }) {
|
|
||||||
|
val argument = if (shouldLambdaParameterBeNamed(newCallExpression.getValueArgumentsInParentheses(), oldCallExpression)) {
|
||||||
psiFactory.createArgument(replacement, functionLiteralArgumentName)
|
psiFactory.createArgument(replacement, functionLiteralArgumentName)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -92,6 +95,13 @@ fun KtLambdaArgument.moveInsideParenthesesAndReplaceWith(
|
|||||||
return oldCallExpression.replace(newCallExpression) as KtCallExpression
|
return oldCallExpression.replace(newCallExpression) as KtCallExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun shouldLambdaParameterBeNamed(args: List<ValueArgument>, callExpr: KtCallExpression): Boolean {
|
||||||
|
if (args.any { it.isNamed() }) return true
|
||||||
|
val calee = (callExpr.calleeExpression?.mainReference?.resolve() as? KtFunction) ?: return true
|
||||||
|
return if (calee.valueParameters.any { it.isVarArg }) true else calee.valueParameters.size - 1 > args.size
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun KtCallExpression.moveFunctionLiteralOutsideParentheses() {
|
fun KtCallExpression.moveFunctionLiteralOutsideParentheses() {
|
||||||
assert(lambdaArguments.isEmpty())
|
assert(lambdaArguments.isEmpty())
|
||||||
val argumentList = valueArgumentList!!
|
val argumentList = valueArgumentList!!
|
||||||
@@ -169,7 +179,7 @@ fun PsiElement.deleteSingle() {
|
|||||||
CodeEditUtil.removeChild(parent?.node ?: return, node ?: return)
|
CodeEditUtil.removeChild(parent?.node ?: return, node ?: return)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtClass.getOrCreateCompanionObject() : KtObjectDeclaration {
|
fun KtClass.getOrCreateCompanionObject(): KtObjectDeclaration {
|
||||||
companionObjects.firstOrNull()?.let { return it }
|
companionObjects.firstOrNull()?.let { return it }
|
||||||
return addDeclaration(KtPsiFactory(this).createCompanionObject())
|
return addDeclaration(KtPsiFactory(this).createCompanionObject())
|
||||||
}
|
}
|
||||||
@@ -354,11 +364,11 @@ fun KtTypeParameterListOwner.addTypeParameter(typeParameter: KtTypeParameter): K
|
|||||||
val list = KtPsiFactory(this).createTypeParameterList("<X>")
|
val list = KtPsiFactory(this).createTypeParameterList("<X>")
|
||||||
list.parameters[0].replace(typeParameter)
|
list.parameters[0].replace(typeParameter)
|
||||||
val leftAnchor = when (this) {
|
val leftAnchor = when (this) {
|
||||||
is KtClass -> nameIdentifier ?: getClassOrInterfaceKeyword()
|
is KtClass -> nameIdentifier ?: getClassOrInterfaceKeyword()
|
||||||
is KtNamedFunction -> funKeyword
|
is KtNamedFunction -> funKeyword
|
||||||
is KtProperty -> valOrVarKeyword
|
is KtProperty -> valOrVarKeyword
|
||||||
else -> null
|
else -> null
|
||||||
} ?: return null
|
} ?: return null
|
||||||
return (addAfter(list, leftAnchor) as KtTypeParameterList).parameters.first()
|
return (addAfter(list, leftAnchor) as KtTypeParameterList).parameters.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// IS_APPLICABLE: true
|
||||||
|
fun foo() {
|
||||||
|
bar <caret>{
|
||||||
|
it * 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(a : Int = 2, b: (Int) -> Int) {
|
||||||
|
b(a)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// IS_APPLICABLE: true
|
||||||
|
fun foo() {
|
||||||
|
bar(b = {
|
||||||
|
it * 3
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(a : Int = 2, b: (Int) -> Int) {
|
||||||
|
b(a)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// IS_APPLICABLE: true
|
||||||
|
fun foo() {
|
||||||
|
bar(1) <caret>{
|
||||||
|
it * 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(c: Int, a: Int = 2, b: (Int) -> Int) {
|
||||||
|
b(a)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// IS_APPLICABLE: true
|
||||||
|
fun foo() {
|
||||||
|
bar(1, b = {
|
||||||
|
it * 3
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(c: Int, a: Int = 2, b: (Int) -> Int) {
|
||||||
|
b(a)
|
||||||
|
}
|
||||||
@@ -11132,6 +11132,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("moveLambda13.kt")
|
||||||
|
public void testMoveLambda13() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaInsideParentheses/moveLambda13.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("moveLambda14.kt")
|
||||||
|
public void testMoveLambda14() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaInsideParentheses/moveLambda14.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("moveLambda2.kt")
|
@TestMetadata("moveLambda2.kt")
|
||||||
public void testMoveLambda2() throws Exception {
|
public void testMoveLambda2() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaInsideParentheses/moveLambda2.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/moveLambdaInsideParentheses/moveLambda2.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user