mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[Kotlin] K2: support when guards in when-to-if intention
KTIJ-31750 GitOrigin-RevId: 965d06ddc9e10077bd176913a72fe5415d47c405
This commit is contained in:
committed by
intellij-monorepo-bot
parent
54f6740bd7
commit
c6e3aee5d6
+2
-3
@@ -168,8 +168,7 @@ internal class WhenToIfIntention :
|
||||
val lastEntry = entries.lastOrNull() ?: return false
|
||||
return !(entries.any { it != lastEntry && it.isElse }) &&
|
||||
!(entries.size == 1 && lastEntry.isElse) && // 'when' with only 'else' branch is not supported
|
||||
element.subjectExpression !is KtProperty &&
|
||||
entries.none { it.guard != null } // Not implemented: KTIJ-31750
|
||||
element.subjectExpression !is KtProperty
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,7 +209,7 @@ internal class WhenToIfIntention :
|
||||
if (entry.isElse || (isTrueOrFalseCondition && i == 1)) {
|
||||
appendExpression(branch)
|
||||
} else {
|
||||
val condition = psiFactory.combineWhenConditions(entry.conditions, subject, isNullableSubject)
|
||||
val condition = psiFactory.combineWhenConditions(entry, subject, isNullableSubject)
|
||||
appendFixedText("if (")
|
||||
appendExpression(condition)
|
||||
appendFixedText(")")
|
||||
|
||||
+30
@@ -5949,6 +5949,31 @@ public abstract class K2IntentionTestGenerated extends AbstractK2IntentionTest {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithEqualityTests.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardIncorrectTwoConditions.kt")
|
||||
public void testWhenWithGuardIncorrectTwoConditions() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithGuardIncorrectTwoConditions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardNoParentheses.kt")
|
||||
public void testWhenWithGuardNoParentheses() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithGuardNoParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardOrOrNoParentheses.kt")
|
||||
public void testWhenWithGuardOrOrNoParentheses() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithGuardOrOrNoParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardOrOrParentheses.kt")
|
||||
public void testWhenWithGuardOrOrParentheses() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithGuardOrOrParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardParentheses.kt")
|
||||
public void testWhenWithGuardParentheses() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithGuardParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuards.kt")
|
||||
public void testWhenWithGuards() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithGuards.kt");
|
||||
@@ -5969,6 +5994,11 @@ public abstract class K2IntentionTestGenerated extends AbstractK2IntentionTest {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithMultipleConditionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithMultipleGuards.kt")
|
||||
public void testWhenWithMultipleGuards() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithMultipleGuards.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithNegativePatterns.kt")
|
||||
public void testWhenWithNegativePatterns() throws Exception {
|
||||
runTest("../../../idea/tests/testData/intentions/branched/ifWhen/whenToIf/whenWithNegativePatterns.kt");
|
||||
|
||||
+32
-2
@@ -73,15 +73,45 @@ fun KtWhenCondition.generateNewConditionWithSubject(subject: KtExpression?, isNu
|
||||
*
|
||||
* // After:
|
||||
* n == 0 || n == 3 ..
|
||||
*
|
||||
* If a guard condition is present, it will be combined with the last condition with the '&&' operation.
|
||||
* This will be done regardless of the number of entry conditions.
|
||||
* Even though it's not correct to use `when` guards with multiple conditions in one branch, transforming it in user code is sensible.
|
||||
* It preserves the intended meaning and makes the code correct.
|
||||
*
|
||||
* For example:
|
||||
* ```
|
||||
* when (foo) {
|
||||
* is String,
|
||||
* is Int if foo > 0 -> ..
|
||||
* }
|
||||
* ```
|
||||
* transforms nicely into
|
||||
* ```
|
||||
* if (foo is String || foo is Int && foo > 0) ..
|
||||
* ```
|
||||
*/
|
||||
fun KtPsiFactory.combineWhenConditions(conditions: Array<KtWhenCondition>, subject: KtExpression?, isNullableSubject: Boolean) =
|
||||
when (conditions.size) {
|
||||
fun KtPsiFactory.combineWhenConditions(entry: KtWhenEntry, subject: KtExpression?, isNullableSubject: Boolean): KtExpression? {
|
||||
val conditions = entry.conditions
|
||||
val combinedConditionsWithSubject = when (conditions.size) {
|
||||
0 -> null
|
||||
1 -> conditions[0].generateNewConditionWithSubject(subject, isNullableSubject)
|
||||
else -> buildExpression {
|
||||
appendExpressions(conditions.map { it.generateNewConditionWithSubject(subject, isNullableSubject) }, separator = "||")
|
||||
}
|
||||
}
|
||||
return handleWhenGuard(combinedConditionsWithSubject, entry)
|
||||
}
|
||||
|
||||
private fun KtPsiFactory.handleWhenGuard(ktExpression: KtExpression?, entry: KtWhenEntry): KtExpression? {
|
||||
val guardExpression = entry.guard?.getExpression()
|
||||
if (ktExpression == null) return guardExpression
|
||||
if (guardExpression == null) return ktExpression
|
||||
|
||||
val needParentheses = guardExpression is KtBinaryExpression && guardExpression.operationToken == KtTokens.OROR
|
||||
val preparedGuard = if (needParentheses) createExpression("(${guardExpression.text})") else guardExpression
|
||||
return createExpression("${ktExpression.text} && ${preparedGuard.text}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new [KtWhenExpression] with introduced subject in brackets.
|
||||
|
||||
+30
@@ -3191,6 +3191,31 @@ public abstract class K1IntentionTestGenerated extends AbstractK1IntentionTest {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithEqualityTests.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardIncorrectTwoConditions.kt")
|
||||
public void testWhenWithGuardIncorrectTwoConditions() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithGuardIncorrectTwoConditions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardNoParentheses.kt")
|
||||
public void testWhenWithGuardNoParentheses() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithGuardNoParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardOrOrNoParentheses.kt")
|
||||
public void testWhenWithGuardOrOrNoParentheses() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithGuardOrOrNoParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardOrOrParentheses.kt")
|
||||
public void testWhenWithGuardOrOrParentheses() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithGuardOrOrParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuardParentheses.kt")
|
||||
public void testWhenWithGuardParentheses() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithGuardParentheses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithGuards.kt")
|
||||
public void testWhenWithGuards() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithGuards.kt");
|
||||
@@ -3211,6 +3236,11 @@ public abstract class K1IntentionTestGenerated extends AbstractK1IntentionTest {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithMultipleConditionTypes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithMultipleGuards.kt")
|
||||
public void testWhenWithMultipleGuards() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithMultipleGuards.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("whenWithNegativePatterns.kt")
|
||||
public void testWhenWithNegativePatterns() throws Exception {
|
||||
runTest("testData/intentions/branched/ifWhen/whenToIf/whenWithNegativePatterns.kt");
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
when (s) {
|
||||
is String,
|
||||
is Int <caret>if s > 5 -> { println("1") }
|
||||
else -> { println("2") }
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
if (s is String || s is Int && s > 5) { println("1") }
|
||||
else { println("2") }
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
when (s) {
|
||||
is String -> println("1")
|
||||
is Int <caret>if s > 5 -> { println("2") }
|
||||
else -> { println("3") }
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
if (s is String) println("1")
|
||||
else if (s is Int && s > 5) { println("2") }
|
||||
else { println("3") }
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
when (s) {
|
||||
is String -> println("1")
|
||||
is Int <caret>if s > 5 || s < 3 -> { println("2") }
|
||||
else -> { println("3") }
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
if (s is String) println("1")
|
||||
else if (s is Int && (s > 5 || s < 3)) { println("2") }
|
||||
else { println("3") }
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
when (s) {
|
||||
is String -> println("1")
|
||||
is Int <caret>if (s > 5 || s < 3) -> { println("2") }
|
||||
else -> { println("3") }
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
if (s is String) println("1")
|
||||
else if (s is Int && (s > 5 || s < 3)) { println("2") }
|
||||
else { println("3") }
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
when (s) {
|
||||
is String -> println("1")
|
||||
is Int <caret>if (s > 5) -> { println("2") }
|
||||
else -> { println("3") }
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
if (s is String) println("1")
|
||||
else if (s is Int && (s > 5)) { println("2") }
|
||||
else { println("3") }
|
||||
}
|
||||
+1
-5
@@ -1,6 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_STDLIB
|
||||
// Issue: KTIJ-31745
|
||||
// IGNORE_K1
|
||||
|
||||
private sealed class MySealed {
|
||||
object A : MySealed()
|
||||
@@ -14,6 +13,3 @@ private fun mySealed(s: MySealed) {
|
||||
else -> { println("3") }
|
||||
}
|
||||
}
|
||||
|
||||
// Not enabled to have the test work for K1: -Xwhen-guards doesn't fix the error because of a low language version
|
||||
// ERROR: The feature "when guards" is experimental and should be enabled explicitly. This can be done by supplying the compiler argument '-Xwhen-guards', but note that no stability guarantees are provided.
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private sealed class MySealed {
|
||||
object A : MySealed()
|
||||
class B(val x: Int) : MySealed()
|
||||
}
|
||||
|
||||
private fun mySealed(s: MySealed) {
|
||||
if (s is MySealed.A) println("1")
|
||||
else if (s is MySealed.B && (s.x > 5)) { println("2") }
|
||||
else { println("3") }
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
when<caret> (s) {
|
||||
is String -> println("1")
|
||||
is Int if s > 5 -> println("2")
|
||||
else if s.toString() == "foo" -> println("3")
|
||||
is Int if s < 0 -> println("4")
|
||||
else if s.toString() == "bar" -> println("5")
|
||||
else -> println("6")
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// WITH_STDLIB
|
||||
// IGNORE_K1
|
||||
|
||||
private fun test(s: Any) {
|
||||
if (s is String) println("1")
|
||||
else if (s is Int && s > 5) println("2")
|
||||
else if (s.toString() == "foo") println("3")
|
||||
else if (s is Int && s < 0) println("4")
|
||||
else if (s.toString() == "bar") println("5")
|
||||
else println("6")
|
||||
}
|
||||
Reference in New Issue
Block a user