diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt index 8acec2df471..75bfffd5eb7 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/psiModificationUtils.kt @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.idea.core +import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement 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 com.intellij.psi.util.elementType import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings @@ -187,10 +189,31 @@ fun KtCallExpression.moveFunctionLiteralOutsideParentheses() { val expression = argument.getArgumentExpression()!! assert(expression.unpackFunctionLiteral() != null) - val dummyCall = KtPsiFactory(project).createExpression("foo() {}") as KtCallExpression + fun isWhiteSpaceOrComment(e: PsiElement) = e is PsiWhiteSpace || e is PsiComment + val prevComma = argument.siblings(forward = false, withItself = false).firstOrNull { it.elementType == KtTokens.COMMA } + val prevComments = (prevComma ?: argumentList.leftParenthesis) + ?.siblings(forward = true, withItself = false) + ?.takeWhile(::isWhiteSpaceOrComment)?.toList().orEmpty() + val nextComments = argumentList.rightParenthesis + ?.siblings(forward = false, withItself = false) + ?.takeWhile(::isWhiteSpaceOrComment)?.toList()?.reversed().orEmpty() + + val psiFactory = KtPsiFactory(project) + val dummyCall = psiFactory.createExpression("foo() {}") as KtCallExpression val functionLiteralArgument = dummyCall.lambdaArguments.single() functionLiteralArgument.getArgumentExpression()?.replace(expression) + + if (prevComments.any { it is PsiComment }) { + if (prevComments.firstOrNull() !is PsiWhiteSpace) this.add(psiFactory.createWhiteSpace()) + prevComments.forEach { this.add(it) } + prevComments.forEach { if (it is PsiComment) it.delete() } + } this.add(functionLiteralArgument) + if (nextComments.any { it is PsiComment }) { + nextComments.forEach { this.add(it) } + nextComments.forEach { if (it is PsiComment) it.delete() } + } + /* we should not remove empty parenthesis when callee is a call too - it won't parse */ if (argumentList.arguments.size == 1 && calleeExpression !is KtCallExpression) { argumentList.delete() diff --git a/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments.kt b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments.kt new file mode 100644 index 00000000000..93ed31f9432 --- /dev/null +++ b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments.kt @@ -0,0 +1,5 @@ +fun foo(f: () -> Unit) {} + +fun test() { + foo(/* c1 */ { /* c2 */ } /* c3 */) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments.kt.after b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments.kt.after new file mode 100644 index 00000000000..c48a5380f39 --- /dev/null +++ b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments.kt.after @@ -0,0 +1,5 @@ +fun foo(f: () -> Unit) {} + +fun test() { + foo /* c1 */ { /* c2 */ } /* c3 */ +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments2.kt b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments2.kt new file mode 100644 index 00000000000..7a2fe0a024a --- /dev/null +++ b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments2.kt @@ -0,0 +1,5 @@ +fun foo(i: Int, f: () -> Unit) {} + +fun test() { + foo(1, /* c1 */ /* c2 */ { /* c3 */ } /* c4 */ /* c5 */) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments2.kt.after b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments2.kt.after new file mode 100644 index 00000000000..4fb88ca5697 --- /dev/null +++ b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments2.kt.after @@ -0,0 +1,5 @@ +fun foo(i: Int, f: () -> Unit) {} + +fun test() { + foo(1) /* c1 */ /* c2 */ { /* c3 */ } /* c4 */ /* c5 */ +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/lambdaWithCommas3.kt.after b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/lambdaWithCommas3.kt.after index f7dc6e8fb75..b8d8a25c142 100644 --- a/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/lambdaWithCommas3.kt.after +++ b/idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/lambdaWithCommas3.kt.after @@ -3,7 +3,7 @@ fun bar(a: Int, b: Int, f: () -> Unit) {} fun foo(a: Int, b: Int) = 2 fun test() { - bar(1, 2 /* , , */) { + bar(1, 2) /* , , */ { val a = foo(1, 2) } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 748f6b0d661..c4071687dad 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -6581,6 +6581,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/functionalValueCall.kt"); } + @TestMetadata("hasComments.kt") + public void testHasComments() throws Exception { + runTest("idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments.kt"); + } + + @TestMetadata("hasComments2.kt") + public void testHasComments2() throws Exception { + runTest("idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/hasComments2.kt"); + } + @TestMetadata("inapplicable1.kt") public void testInapplicable1() throws Exception { runTest("idea/testData/inspectionsLocal/moveLambdaOutsideParentheses/inapplicable1.kt");