Skip to content

Commit 86e6f3c

Browse files
committed
Make add / remove labeled return working for hierarchical blocks
Related to KT-20439
1 parent 59f6dc0 commit 86e6f3c

File tree

8 files changed

+78
-28
lines changed

8 files changed

+78
-28
lines changed

idea/src/org/jetbrains/kotlin/idea/intentions/AddLabeledReturnInLambdaIntention.kt

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,36 @@ import org.jetbrains.kotlin.psi.*
1313
import org.jetbrains.kotlin.psi.psiUtil.*
1414
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
1515

16-
class AddLabeledReturnInLambdaIntention : SelfTargetingRangeIntention<KtLambdaExpression>(
17-
KtLambdaExpression::class.java,
16+
class AddLabeledReturnInLambdaIntention : SelfTargetingRangeIntention<KtBlockExpression>(
17+
KtBlockExpression::class.java,
1818
"Add labeled return to last expression in a lambda"
1919
), LowPriorityAction {
20-
override fun applicabilityRange(element: KtLambdaExpression): TextRange? {
20+
override fun applicabilityRange(element: KtBlockExpression): TextRange? {
2121
if (!isApplicableTo(element)) return null
2222
val labelName = createLabelName(element) ?: return null
2323
text = "Add return@$labelName"
24-
return element.bodyExpression?.statements?.last()?.textRange
24+
return element.statements.lastOrNull()?.textRange
2525
}
2626

27-
override fun applyTo(element: KtLambdaExpression, editor: Editor?) {
27+
override fun applyTo(element: KtBlockExpression, editor: Editor?) {
2828
if (!isApplicableTo(element)) return
2929
val labelName = createLabelName(element) ?: return
30-
val lastStatement = element.bodyExpression?.statements?.last() ?: return
30+
val lastStatement = element.statements.lastOrNull() ?: return
3131
val newExpression = KtPsiFactory(element.project).createExpressionByPattern("return@$labelName $0", lastStatement)
3232
lastStatement.replace(newExpression)
3333
}
3434

35-
private fun isApplicableTo(element: KtLambdaExpression): Boolean {
36-
val block = element.bodyExpression ?: return false
37-
val lastStatement = block.statements.last()
38-
return lastStatement !is KtReturnExpression && lastStatement.isUsedAsExpression(lastStatement.analyze())
35+
private fun isApplicableTo(block: KtBlockExpression): Boolean {
36+
val lastStatement = block.statements.lastOrNull()
37+
return lastStatement !is KtReturnExpression && lastStatement?.isUsedAsExpression(lastStatement.analyze()) == true
3938
}
4039

41-
private fun createLabelName(element: KtLambdaExpression): String? {
42-
val block = element.bodyExpression ?: return null
43-
val callExpression = element.getStrictParentOfType<KtCallExpression>() ?: return null
44-
val valueArgument = callExpression.valueArguments.findArgumentWithGivenBlock(block) ?: return null
40+
private fun createLabelName(block: KtBlockExpression): String? {
41+
val lambdaExpression = block.getStrictParentOfType<KtLambdaExpression>() ?: return null
42+
val callExpression = lambdaExpression.getStrictParentOfType<KtCallExpression>() ?: return null
43+
val valueArgument = callExpression.valueArguments.find {
44+
it.getArgumentExpression()?.unpackFunctionLiteral(allowParentheses = false) === lambdaExpression
45+
} ?: return null
4546
val lambdaLabelName = (valueArgument.getArgumentExpression() as? KtLabeledExpression)?.getLabelName()
4647
return lambdaLabelName ?: callExpression.getCallNameExpression()?.text
4748
}

idea/src/org/jetbrains/kotlin/idea/intentions/RemoveLabeledReturnInLambdaIntention.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ class RemoveLabeledReturnInLambdaIntention : SelfTargetingIntention<KtReturnExpr
1919
val labelName = element.getLabelName() ?: return false
2020
val block = element.getStrictParentOfType<KtBlockExpression>() ?: return false
2121
if (block.statements.lastOrNull() != element) return false
22-
val callExpression = block.getStrictParentOfType<KtCallExpression>() ?: return false
23-
val lambdaArgument = callExpression.lambdaArguments.findArgumentWithGivenBlock(block) ?: return false
22+
val lambdaExpression = block.getStrictParentOfType<KtLambdaExpression>() ?: return false
23+
val callExpression = lambdaExpression.getStrictParentOfType<KtCallExpression>() ?: return false
24+
val lambdaArgument = callExpression.lambdaArguments.find {
25+
it.getArgumentExpression().unpackFunctionLiteral(allowParentheses = false) === lambdaExpression
26+
} ?: return false
2427
val callName = (lambdaArgument.getArgumentExpression() as? KtLabeledExpression)?.getLabelName()
2528
?: callExpression.getCallNameExpression()?.text ?: return false
2629
if (labelName != callName) return false

idea/src/org/jetbrains/kotlin/idea/intentions/Utils.kt

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -294,15 +294,3 @@ fun KtCallExpression.isArrayOfMethod(): Boolean {
294294
return (descriptor.containingDeclaration as? PackageFragmentDescriptor)?.fqName == KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME &&
295295
ARRAY_OF_METHODS.contains(descriptor.name)
296296
}
297-
298-
fun <T : KtValueArgument> List<T>.findArgumentWithGivenBlock(
299-
block: KtBlockExpression
300-
): T? = firstOrNull {
301-
val argumentExpression = it.getArgumentExpression()
302-
val lambda = when (argumentExpression) {
303-
is KtLambdaExpression -> argumentExpression
304-
is KtLabeledExpression -> argumentExpression.baseExpression as? KtLambdaExpression
305-
else -> null
306-
}
307-
lambda?.bodyExpression === block
308-
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// WITH_RUNTIME
2+
// INTENTION_TEXT: "Add return@find"
3+
4+
fun foo() {
5+
listOf(1,2,3).find {
6+
if (it > 0) {
7+
<caret>true
8+
} else {
9+
false
10+
}
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// WITH_RUNTIME
2+
// INTENTION_TEXT: "Add return@find"
3+
4+
fun foo() {
5+
listOf(1,2,3).find {
6+
if (it > 0) {
7+
return@find true
8+
} else {
9+
false
10+
}
11+
}
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// WITH_RUNTIME
2+
3+
fun foo() {
4+
listOf(1,2,3).find {
5+
if (it > 0) {
6+
return@find <caret>true
7+
} else {
8+
false
9+
}
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// WITH_RUNTIME
2+
3+
fun foo() {
4+
listOf(1,2,3).find {
5+
if (it > 0) {
6+
true
7+
} else {
8+
false
9+
}
10+
}
11+
}

idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)