diff --git a/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/after.kt.template b/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/after.kt.template new file mode 100644 index 00000000000..51551a0d780 --- /dev/null +++ b/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/after.kt.template @@ -0,0 +1,5 @@ +fun foo() { + listOf(1,2,3).find { + true + } +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/before.kt.template b/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/before.kt.template new file mode 100644 index 00000000000..f0f1216fc33 --- /dev/null +++ b/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/before.kt.template @@ -0,0 +1,5 @@ +fun foo() { + listOf(1,2,3).find { + return@find true + } +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/description.html b/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/description.html new file mode 100644 index 00000000000..9d0ed638425 --- /dev/null +++ b/idea/resources/intentionDescriptions/RemoveLabeledReturnInLambdaIntention/description.html @@ -0,0 +1,5 @@ + + +This intention removes labeled return from last expression in a lambda. + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 80eb3a14b39..0b0e7b16f81 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -1557,6 +1557,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.RemoveLabeledReturnInLambdaIntention + Kotlin + + ( + KtReturnExpression::class.java, + "Remove labeled return from last expression in a lambda" +), LowPriorityAction { + override fun isApplicableTo(element: KtReturnExpression, caretOffset: Int): Boolean { + val labelName = element.getLabelName() ?: return false + val block = element.getStrictParentOfType() ?: return false + if (block.statements.lastOrNull() != element) return false + val callExpression = block.getStrictParentOfType() ?: return false + val lambdaArgument = callExpression.lambdaArguments.firstOrNull { + val argumentExpression = it.getArgumentExpression() + val lambda = when (argumentExpression) { + is KtLambdaExpression -> argumentExpression + is KtLabeledExpression -> argumentExpression.baseExpression as? KtLambdaExpression + else -> null + } + lambda?.bodyExpression === block + } ?: return false + val callName = (lambdaArgument.getArgumentExpression() as? KtLabeledExpression)?.getLabelName() + ?: callExpression.getCallNameExpression()?.text ?: return false + if (labelName != callName) return false + text = "Remove return@$labelName" + return true + } + + override fun applyTo(element: KtReturnExpression, editor: Editor?) { + val returnedExpression = element.returnedExpression + if (returnedExpression == null) { + element.delete() + } else { + element.replace(returnedExpression) + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/.intention b/idea/testData/intentions/removeLabeledReturnInLambda/.intention new file mode 100644 index 00000000000..58b806f80fc --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.RemoveLabeledReturnInLambdaIntention \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/labeledLambda.kt b/idea/testData/intentions/removeLabeledReturnInLambda/labeledLambda.kt new file mode 100644 index 00000000000..4adb08a05d7 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/labeledLambda.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Remove return@label" + +fun foo() { + listOf(1,2,3).find label@{ + return@label true + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/labeledLambda.kt.after b/idea/testData/intentions/removeLabeledReturnInLambda/labeledLambda.kt.after new file mode 100644 index 00000000000..9e38c36ca9c --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/labeledLambda.kt.after @@ -0,0 +1,8 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Remove return@label" + +fun foo() { + listOf(1,2,3).find label@{ + true + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/normal.kt b/idea/testData/intentions/removeLabeledReturnInLambda/normal.kt new file mode 100644 index 00000000000..4770218534f --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/normal.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Remove return@find" + +fun foo() { + listOf(1,2,3).find { + return@find true + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/normal.kt.after b/idea/testData/intentions/removeLabeledReturnInLambda/normal.kt.after new file mode 100644 index 00000000000..864641b8452 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/normal.kt.after @@ -0,0 +1,8 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Remove return@find" + +fun foo() { + listOf(1,2,3).find { + true + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/notInsideLabeled.kt b/idea/testData/intentions/removeLabeledReturnInLambda/notInsideLabeled.kt new file mode 100644 index 00000000000..910445d4134 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/notInsideLabeled.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +// IS_APPLICABLE: FALSE + +fun foo(): Boolean { + return@foo true +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/notLabeled.kt b/idea/testData/intentions/removeLabeledReturnInLambda/notLabeled.kt new file mode 100644 index 00000000000..b98d5aa2ba4 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/notLabeled.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// IS_APPLICABLE: FALSE + +fun foo(): Boolean { + listOf(1,2,3).find { + return true + } + return false +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/notLastLine.kt b/idea/testData/intentions/removeLabeledReturnInLambda/notLastLine.kt new file mode 100644 index 00000000000..8f4c1d7b098 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/notLastLine.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// IS_APPLICABLE: FALSE + +fun foo() { + listOf(1,2,3).find { + 1 + return@find true + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/outerLambda.kt b/idea/testData/intentions/removeLabeledReturnInLambda/outerLambda.kt new file mode 100644 index 00000000000..47beb1f1d36 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/outerLambda.kt @@ -0,0 +1,10 @@ +// WITH_RUNTIME +// IS_APPLICABLE: FALSE + +fun foo() { + listOf(1,2,3).forEach { + listOf(1,2,3).find { + return@forEach + } + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/unit.kt b/idea/testData/intentions/removeLabeledReturnInLambda/unit.kt new file mode 100644 index 00000000000..6db30593a83 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/unit.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Remove return@forEach" + +fun foo() { + listOf(1,2,3).forEach { + return@forEach + } +} \ No newline at end of file diff --git a/idea/testData/intentions/removeLabeledReturnInLambda/unit.kt.after b/idea/testData/intentions/removeLabeledReturnInLambda/unit.kt.after new file mode 100644 index 00000000000..c419f84bf89 --- /dev/null +++ b/idea/testData/intentions/removeLabeledReturnInLambda/unit.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +// INTENTION_TEXT: "Remove return@forEach" + +fun foo() { + listOf(1,2,3).forEach { + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 08e4e7d94cc..286e30e6b0d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -13216,6 +13216,57 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/removeLabeledReturnInLambda") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RemoveLabeledReturnInLambda extends AbstractIntentionTest { + public void testAllFilesPresentInRemoveLabeledReturnInLambda() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/removeLabeledReturnInLambda"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("labeledLambda.kt") + public void testLabeledLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeLabeledReturnInLambda/labeledLambda.kt"); + doTest(fileName); + } + + @TestMetadata("normal.kt") + public void testNormal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeLabeledReturnInLambda/normal.kt"); + doTest(fileName); + } + + @TestMetadata("notInsideLabeled.kt") + public void testNotInsideLabeled() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeLabeledReturnInLambda/notInsideLabeled.kt"); + doTest(fileName); + } + + @TestMetadata("notLabeled.kt") + public void testNotLabeled() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeLabeledReturnInLambda/notLabeled.kt"); + doTest(fileName); + } + + @TestMetadata("notLastLine.kt") + public void testNotLastLine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeLabeledReturnInLambda/notLastLine.kt"); + doTest(fileName); + } + + @TestMetadata("outerLambda.kt") + public void testOuterLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeLabeledReturnInLambda/outerLambda.kt"); + doTest(fileName); + } + + @TestMetadata("unit.kt") + public void testUnit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/removeLabeledReturnInLambda/unit.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/removeRedundantCallsOfConversionMethods") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)