[kotlin] Share ConvertLambdaLineIntention between k1 and k2

ConvertLambdaLineIntention includes two inheritors: ConvertLambdaToMultiLineIntention and ConvertLambdaToSingleLineIntention

^KTIJ-22968 fixed
^KTIJ-22969 fixed
^KTIJ-22970 fixed

GitOrigin-RevId: de729d85dc00f5bb26a5abbf464b4a434822923c
This commit is contained in:
Andrey Cherkasov
2024-03-12 13:05:21 +04:00
committed by intellij-monorepo-bot
parent 2d252ff519
commit 678f31ee1c
48 changed files with 233 additions and 127 deletions

View File

@@ -195,5 +195,19 @@
<bundleName>messages.KotlinBundle</bundleName>
<categoryKey>group.names.kotlin</categoryKey>
</intentionAction>
<intentionAction>
<language>kotlin</language>
<className>org.jetbrains.kotlin.idea.codeInsight.intentions.shared.ConvertLambdaToMultiLineIntention</className>
<bundleName>messages.KotlinBundle</bundleName>
<categoryKey>group.names.kotlin</categoryKey>
</intentionAction>
<intentionAction>
<language>kotlin</language>
<className>org.jetbrains.kotlin.idea.codeInsight.intentions.shared.ConvertLambdaToSingleLineIntention</className>
<bundleName>messages.KotlinBundle</bundleName>
<categoryKey>group.names.kotlin</categoryKey>
</intentionAction>
</extensions>
</idea-plugin>

View File

@@ -0,0 +1,65 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeInsight.intentions.shared
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiComment
import org.jetbrains.kotlin.idea.base.psi.getLineNumber
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.codeinsight.api.classic.intentions.SelfTargetingIntention
import org.jetbrains.kotlin.idea.codeinsight.utils.isRedundantSemicolon
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.psi.psiUtil.getNextSiblingIgnoringWhitespace
import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespace
internal sealed class ConvertLambdaLineIntention(private val toMultiLine: Boolean) : SelfTargetingIntention<KtLambdaExpression>(
KtLambdaExpression::class.java,
KotlinBundle.lazyMessage("intention.convert.lambda.line", 1.takeIf { toMultiLine } ?: 0),
) {
override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean {
val functionLiteral = element.functionLiteral
val body = functionLiteral.bodyBlockExpression ?: return false
val startLine = functionLiteral.getLineNumber(start = true)
val endLine = functionLiteral.getLineNumber(start = false)
return if (toMultiLine) {
startLine == endLine
} else {
if (startLine == endLine) return false
val allChildren = body.allChildren
if (allChildren.any { it is PsiComment && it.node.elementType == KtTokens.EOL_COMMENT }) return false
val first = allChildren.first?.getNextSiblingIgnoringWhitespace(withItself = true) ?: return true
val last = allChildren.last?.getPrevSiblingIgnoringWhitespace(withItself = true)
first.getLineNumber(start = true) == last?.getLineNumber(start = false)
}
}
override fun applyTo(element: KtLambdaExpression, editor: Editor?) {
val functionLiteral = element.functionLiteral
val body = functionLiteral.bodyBlockExpression ?: return
val psiFactory = KtPsiFactory(element.project)
if (toMultiLine) {
body.allChildren.forEach {
if (it.node.elementType == KtTokens.SEMICOLON) {
body.addAfter(psiFactory.createNewLine(), it)
if (isRedundantSemicolon(it)) it.delete()
}
}
}
val bodyText = body.text
val startLineBreak = if (toMultiLine) "\n" else ""
val endLineBreak = if (toMultiLine && bodyText != "") "\n" else ""
element.replace(
psiFactory.createLambdaExpression(
functionLiteral.valueParameters.joinToString { it.text },
"$startLineBreak$bodyText$endLineBreak"
)
)
}
}
internal class ConvertLambdaToMultiLineIntention : ConvertLambdaLineIntention(toMultiLine = true)
internal class ConvertLambdaToSingleLineIntention : ConvertLambdaLineIntention(toMultiLine = false)

View File

@@ -357,6 +357,112 @@ public abstract class SharedK1IntentionTestGenerated extends AbstractSharedK1Int
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/intentions/convertLambdaToMultiLine")
public static class ConvertLambdaToMultiLine extends AbstractSharedK1IntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("multiLine.kt")
public void testMultiLine() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/multiLine.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple.kt");
}
@TestMetadata("simple2.kt")
public void testSimple2() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple2.kt");
}
@TestMetadata("simple3.kt")
public void testSimple3() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple3.kt");
}
@TestMetadata("simple4.kt")
public void testSimple4() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple4.kt");
}
@TestMetadata("simple5.kt")
public void testSimple5() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple5.kt");
}
@TestMetadata("simple6.kt")
public void testSimple6() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple6.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/intentions/convertLambdaToSingleLine")
public static class ConvertLambdaToSingleLine extends AbstractSharedK1IntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("hasEolComment.kt")
public void testHasEolComment() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/hasEolComment.kt");
}
@TestMetadata("multiLineBody.kt")
public void testMultiLineBody() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/multiLineBody.kt");
}
@TestMetadata("multiLineBody2.kt")
public void testMultiLineBody2() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/multiLineBody2.kt");
}
@TestMetadata("multiLineBody3.kt")
public void testMultiLineBody3() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/multiLineBody3.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple.kt");
}
@TestMetadata("simple2.kt")
public void testSimple2() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple2.kt");
}
@TestMetadata("simple3.kt")
public void testSimple3() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple3.kt");
}
@TestMetadata("simple4.kt")
public void testSimple4() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple4.kt");
}
@TestMetadata("simple5.kt")
public void testSimple5() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple5.kt");
}
@TestMetadata("simple6.kt")
public void testSimple6() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple6.kt");
}
@TestMetadata("singleLine.kt")
public void testSingleLine() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/singleLine.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/intentions/convertLineCommentToBlockComment")
public static class ConvertLineCommentToBlockComment extends AbstractSharedK1IntentionTest {

View File

@@ -357,6 +357,112 @@ public abstract class SharedK2IntentionTestGenerated extends AbstractSharedK2Int
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/intentions/convertLambdaToMultiLine")
public static class ConvertLambdaToMultiLine extends AbstractSharedK2IntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("multiLine.kt")
public void testMultiLine() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/multiLine.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple.kt");
}
@TestMetadata("simple2.kt")
public void testSimple2() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple2.kt");
}
@TestMetadata("simple3.kt")
public void testSimple3() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple3.kt");
}
@TestMetadata("simple4.kt")
public void testSimple4() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple4.kt");
}
@TestMetadata("simple5.kt")
public void testSimple5() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple5.kt");
}
@TestMetadata("simple6.kt")
public void testSimple6() throws Exception {
runTest("../testData/intentions/convertLambdaToMultiLine/simple6.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/intentions/convertLambdaToSingleLine")
public static class ConvertLambdaToSingleLine extends AbstractSharedK2IntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("hasEolComment.kt")
public void testHasEolComment() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/hasEolComment.kt");
}
@TestMetadata("multiLineBody.kt")
public void testMultiLineBody() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/multiLineBody.kt");
}
@TestMetadata("multiLineBody2.kt")
public void testMultiLineBody2() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/multiLineBody2.kt");
}
@TestMetadata("multiLineBody3.kt")
public void testMultiLineBody3() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/multiLineBody3.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple.kt");
}
@TestMetadata("simple2.kt")
public void testSimple2() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple2.kt");
}
@TestMetadata("simple3.kt")
public void testSimple3() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple3.kt");
}
@TestMetadata("simple4.kt")
public void testSimple4() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple4.kt");
}
@TestMetadata("simple5.kt")
public void testSimple5() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple5.kt");
}
@TestMetadata("simple6.kt")
public void testSimple6() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/simple6.kt");
}
@TestMetadata("singleLine.kt")
public void testSingleLine() throws Exception {
runTest("../testData/intentions/convertLambdaToSingleLine/singleLine.kt");
}
}
@RunWith(JUnit3RunnerWithInners.class)
@TestMetadata("../testData/intentions/convertLineCommentToBlockComment")
public static class ConvertLineCommentToBlockComment extends AbstractSharedK2IntentionTest {

View File

@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.codeInsight.intentions.shared.ConvertLambdaToMultiLineIntention

View File

@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach {
println(it)
}<caret>
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach <caret>{}
}

View File

@@ -0,0 +1,5 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach {
}
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { <caret>println(it) }
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach {
println(it)
}
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item -> println(item)<caret> }
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item ->
println(item)
}
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item -> println(item); println(item); println(item) /* comment */ }<caret>
}

View File

@@ -0,0 +1,8 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item ->
println(item)
println(item)
println(item) /* comment */
}
}

View File

@@ -0,0 +1,5 @@
// WITH_STDLIB
// AFTER-WARNING: Parameter 's' is never used, could be renamed to _
fun test(list: List<String>) {
list.forEachIndexed { index, s -> println(index) }<caret>
}

View File

@@ -0,0 +1,7 @@
// WITH_STDLIB
// AFTER-WARNING: Parameter 's' is never used, could be renamed to _
fun test(list: List<String>) {
list.forEachIndexed { index, s ->
println(index)
}
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<Pair<String, Int>>) {
list.forEach { (s, _) -> println(s) }<caret>
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
fun test(list: List<Pair<String, Int>>) {
list.forEach { (s, _) ->
println(s)
}
}

View File

@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.codeInsight.intentions.shared.ConvertLambdaToSingleLineIntention

View File

@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item ->
println(item) // comment
}<caret>
}

View File

@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item ->
println(item)
println(item)
}<caret>
}

View File

@@ -0,0 +1,10 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item ->
println(item) /* comment */
}<caret>
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item -> println(item) /* comment */ }
}

View File

@@ -0,0 +1,7 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach {
item ->
println(item)
}<caret>
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item -> println(item) }
}

View File

@@ -0,0 +1,5 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach <caret>{
}
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { }
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach {
<caret>println(it)
}
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { println(it) }
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item ->
println(item)<caret>
}
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item -> println(item) }
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item ->
println(item); println(item); println(item) /* comment */
}<caret>
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { item -> println(item); println(item); println(item) /* comment */ }
}

View File

@@ -0,0 +1,7 @@
// WITH_STDLIB
// AFTER-WARNING: Parameter 's' is never used, could be renamed to _
fun test(list: List<String>) {
list.forEachIndexed { index, s ->
println(index)
}<caret>
}

View File

@@ -0,0 +1,5 @@
// WITH_STDLIB
// AFTER-WARNING: Parameter 's' is never used, could be renamed to _
fun test(list: List<String>) {
list.forEachIndexed { index, s -> println(index) }
}

View File

@@ -0,0 +1,6 @@
// WITH_STDLIB
fun test(list: List<Pair<String, Int>>) {
list.forEach { (s, _) ->
println(s)
}<caret>
}

View File

@@ -0,0 +1,4 @@
// WITH_STDLIB
fun test(list: List<Pair<String, Int>>) {
list.forEach { (s, _) -> println(s) }
}

View File

@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// WITH_STDLIB
fun test(list: List<String>) {
list.forEach { println(it) }
}<caret>