KT-33384 Intention to switch between single-line/multi-line lambda (#2790)
Add intention for single-line lambda <-> multi-line lambda conversion #KT-33384 Fixed
This commit is contained in:
committed by
GitHub
parent
f94d026e64
commit
ebe3619251
@@ -1704,6 +1704,16 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.ConvertLambdaToMultiLineIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.ConvertLambdaToSingleLineIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<lang.inspectionSuppressor language="kotlin" implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinInspectionSuppressor"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
list.forEach { item ->
|
||||
println(item)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
list.forEach { item -> println(item) }
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention converts a single-line lambda to a multi-line one.
|
||||
</body>
|
||||
</html>
|
||||
+1
@@ -0,0 +1 @@
|
||||
list.forEach { item -> println(item) }
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
list.forEach { item ->
|
||||
println(item)
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention converts a multi-line lambda to a single-line one.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.psi.PsiComment
|
||||
import org.jetbrains.kotlin.idea.inspections.RedundantSemicolonInspection
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
||||
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
|
||||
|
||||
sealed class ConvertLambdaLineIntention(private val toMultiLine: Boolean) : SelfTargetingIntention<KtLambdaExpression>(
|
||||
KtLambdaExpression::class.java, "Convert to ${if (toMultiLine) "multi" else "single"}-line lambda"
|
||||
) {
|
||||
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)
|
||||
if (toMultiLine) {
|
||||
body.allChildren.forEach {
|
||||
if (it.node.elementType == KtTokens.SEMICOLON) {
|
||||
body.addAfter(psiFactory.createNewLine(), it)
|
||||
if (RedundantSemicolonInspection.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"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ConvertLambdaToMultiLineIntention : ConvertLambdaLineIntention(toMultiLine = true)
|
||||
|
||||
class ConvertLambdaToSingleLineIntention : ConvertLambdaLineIntention(toMultiLine = false)
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.ConvertLambdaToMultiLineIntention
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach {
|
||||
println(it)
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach <caret>{}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { <caret>println(it) }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach {
|
||||
println(it)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item -> println(item)<caret> }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item ->
|
||||
println(item)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item -> println(item); println(item); println(item) /* comment */ }<caret>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item ->
|
||||
println(item)
|
||||
println(item)
|
||||
println(item) /* comment */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEachIndexed { index, s -> println(index) }<caret>
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEachIndexed { index, s ->
|
||||
println(index)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<Pair<String, Int>>) {
|
||||
list.forEach { (s, _) -> println(s) }<caret>
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<Pair<String, Int>>) {
|
||||
list.forEach { (s, _) ->
|
||||
println(s)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.ConvertLambdaToSingleLineIntention
|
||||
@@ -0,0 +1,7 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item ->
|
||||
println(item) // comment
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item ->
|
||||
println(item)
|
||||
println(item)
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item ->
|
||||
|
||||
|
||||
println(item) /* comment */
|
||||
|
||||
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item -> println(item) /* comment */ }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach {
|
||||
item ->
|
||||
println(item)
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item -> println(item) }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach <caret>{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach {
|
||||
<caret>println(it)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { println(it) }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item ->
|
||||
println(item)<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item -> println(item) }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item ->
|
||||
println(item); println(item); println(item) /* comment */
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { item -> println(item); println(item); println(item) /* comment */ }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEachIndexed { index, s ->
|
||||
println(index)
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEachIndexed { index, s -> println(index) }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<Pair<String, Int>>) {
|
||||
list.forEach { (s, _) ->
|
||||
println(s)
|
||||
}<caret>
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<Pair<String, Int>>) {
|
||||
list.forEach { (s, _) -> println(s) }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<String>) {
|
||||
list.forEach { println(it) }
|
||||
}<caret>
|
||||
+116
@@ -4692,6 +4692,54 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/convertLambdaToMultiLine")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ConvertLambdaToMultiLine extends AbstractIntentionTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInConvertLambdaToMultiLine() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/convertLambdaToMultiLine"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("multiLine.kt")
|
||||
public void testMultiLine() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToMultiLine/multiLine.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToMultiLine/simple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple2.kt")
|
||||
public void testSimple2() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToMultiLine/simple2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple3.kt")
|
||||
public void testSimple3() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToMultiLine/simple3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple4.kt")
|
||||
public void testSimple4() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToMultiLine/simple4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple5.kt")
|
||||
public void testSimple5() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToMultiLine/simple5.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple6.kt")
|
||||
public void testSimple6() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToMultiLine/simple6.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/convertLambdaToReference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@@ -5050,6 +5098,74 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/convertLambdaToSingleLine")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ConvertLambdaToSingleLine extends AbstractIntentionTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInConvertLambdaToSingleLine() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/convertLambdaToSingleLine"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("hasEolComment.kt")
|
||||
public void testHasEolComment() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/hasEolComment.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multiLineBody.kt")
|
||||
public void testMultiLineBody() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/multiLineBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multiLineBody2.kt")
|
||||
public void testMultiLineBody2() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/multiLineBody2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multiLineBody3.kt")
|
||||
public void testMultiLineBody3() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/multiLineBody3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/simple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple2.kt")
|
||||
public void testSimple2() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/simple2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple3.kt")
|
||||
public void testSimple3() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/simple3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple4.kt")
|
||||
public void testSimple4() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/simple4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple5.kt")
|
||||
public void testSimple5() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/simple5.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple6.kt")
|
||||
public void testSimple6() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/simple6.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("singleLine.kt")
|
||||
public void testSingleLine() throws Exception {
|
||||
runTest("idea/testData/intentions/convertLambdaToSingleLine/singleLine.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/convertLateinitPropertyToNullable")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user