KT-14336 for to stdlib to takeWhile: propose conversion into takeWhile if break is located in else branch
#KT-14336 Fixed
This commit is contained in:
+33
-8
@@ -155,16 +155,41 @@ abstract class FilterTransformationBase : SequenceTransformation {
|
||||
|
||||
private fun matchOneTransformation(state: MatchingState): Pair<SequenceTransformation, MatchingState>? {
|
||||
val ifStatement = state.statements.firstOrNull() as? KtIfExpression ?: return null
|
||||
if (ifStatement.`else` != null) return null
|
||||
val condition = ifStatement.condition ?: return null
|
||||
val then = ifStatement.then ?: return null
|
||||
val thenBranch = ifStatement.then ?: return null
|
||||
val elseBranch = ifStatement.`else`
|
||||
|
||||
if (elseBranch == null) {
|
||||
return matchOneTransformation(state, condition, false, thenBranch, state.statements.drop(1))
|
||||
}
|
||||
else if (state.statements.size == 1) {
|
||||
val thenStatement = thenBranch.blockExpressionsOrSingle().singleOrNull()
|
||||
if (thenStatement is KtBreakExpression || thenStatement is KtContinueExpression) {
|
||||
return matchOneTransformation(state, condition, false, thenBranch, elseBranch.singletonList())
|
||||
}
|
||||
|
||||
val elseStatement = elseBranch.blockExpressionsOrSingle().singleOrNull()
|
||||
if (elseStatement is KtBreakExpression || elseStatement is KtContinueExpression) {
|
||||
return matchOneTransformation(state, condition, true, elseBranch, thenBranch.singletonList())
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun matchOneTransformation(
|
||||
state: MatchingState,
|
||||
condition: KtExpression,
|
||||
negateCondition: Boolean,
|
||||
then: KtExpression,
|
||||
restStatements: List<KtExpression>
|
||||
): Pair<SequenceTransformation, MatchingState>? {
|
||||
// we do not allow filter() which uses neither input variable nor index variable (though is technically possible but looks confusing)
|
||||
// shouldUseInputVariables = false does not work for us because we sometimes return Result match in this matcher
|
||||
if (!state.inputVariable.hasUsages(condition) && (state.indexVariable == null || !state.indexVariable.hasUsages(condition))) return null
|
||||
|
||||
if (state.statements.size == 1) {
|
||||
val transformation = createFilterTransformation(state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition))
|
||||
if (restStatements.isEmpty()) {
|
||||
val transformation = createFilterTransformation(state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition, negateCondition))
|
||||
val newState = state.copy(statements = listOf(then))
|
||||
return transformation to newState
|
||||
}
|
||||
@@ -173,15 +198,15 @@ abstract class FilterTransformationBase : SequenceTransformation {
|
||||
when (statement) {
|
||||
is KtContinueExpression -> {
|
||||
if (statement.targetLoop() != state.innerLoop) return null
|
||||
val transformation = createFilterTransformation(state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition, negated = true))
|
||||
val newState = state.copy(statements = state.statements.drop(1))
|
||||
val transformation = createFilterTransformation(state.outerLoop, state.inputVariable, state.indexVariable, Condition.create(condition, !negateCondition))
|
||||
val newState = state.copy(statements = restStatements)
|
||||
return transformation to newState
|
||||
}
|
||||
|
||||
is KtBreakExpression -> {
|
||||
if (statement.targetLoop() != state.outerLoop) return null
|
||||
val transformation = TakeWhileTransformation(state.outerLoop, state.inputVariable, condition.negate())
|
||||
val newState = state.copy(statements = state.statements.drop(1))
|
||||
val transformation = TakeWhileTransformation(state.outerLoop, state.inputVariable, if (negateCondition) condition else condition.negate())
|
||||
val newState = state.copy(statements = restStatements)
|
||||
return transformation to newState
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'firstOrNull{}'"
|
||||
// IS_APPLICABLE_2: false
|
||||
fun foo(list: List<String>): String? {
|
||||
<caret>for (s in list) {
|
||||
if (s.isEmpty()) continue
|
||||
else return s
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'firstOrNull{}'"
|
||||
// IS_APPLICABLE_2: false
|
||||
fun foo(list: List<String>): String? {
|
||||
return list.firstOrNull { !it.isEmpty() }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'takeWhile{}'"
|
||||
// IS_APPLICABLE_2: false
|
||||
fun foo(n: Int, list: List<Int>): List<Int>{
|
||||
val result = mutableListOf<Int>()
|
||||
<caret>for (i in list) {
|
||||
if (i >= n)
|
||||
result.add(i)
|
||||
else
|
||||
break
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'takeWhile{}'"
|
||||
// IS_APPLICABLE_2: false
|
||||
fun foo(n: Int, list: List<Int>): List<Int>{
|
||||
val result = list.takeWhile { it >= n }
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'takeWhile{}'"
|
||||
// IS_APPLICABLE_2: false
|
||||
fun foo(n: Int, list: List<Int>): List<Int>{
|
||||
val result = mutableListOf<Int>()
|
||||
<caret>for (i in list) {
|
||||
if (i < n)
|
||||
break
|
||||
else
|
||||
result.add(i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
// INTENTION_TEXT: "Replace with 'takeWhile{}'"
|
||||
// IS_APPLICABLE_2: false
|
||||
fun foo(n: Int, list: List<Int>): List<Int>{
|
||||
val result = list.takeWhile { it >= n }
|
||||
return result
|
||||
}
|
||||
@@ -574,6 +574,12 @@ public class IntentionTest2Generated extends AbstractIntentionTest2 {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ifElse.kt")
|
||||
public void testIfElse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/filter/ifElse.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inputVarNotUsed.kt")
|
||||
public void testInputVarNotUsed() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/filter/inputVarNotUsed.kt");
|
||||
@@ -1444,6 +1450,18 @@ public class IntentionTest2Generated extends AbstractIntentionTest2 {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/loopToCallChain/takeWhile"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ifElse1.kt")
|
||||
public void testIfElse1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/takeWhile/ifElse1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ifElse2.kt")
|
||||
public void testIfElse2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/takeWhile/ifElse2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedLoop.kt")
|
||||
public void testNestedLoop() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/takeWhile/nestedLoop.kt");
|
||||
|
||||
@@ -8482,6 +8482,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ifElse.kt")
|
||||
public void testIfElse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/filter/ifElse.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inputVarNotUsed.kt")
|
||||
public void testInputVarNotUsed() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/filter/inputVarNotUsed.kt");
|
||||
@@ -9352,6 +9358,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/loopToCallChain/takeWhile"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ifElse1.kt")
|
||||
public void testIfElse1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/takeWhile/ifElse1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ifElse2.kt")
|
||||
public void testIfElse2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/takeWhile/ifElse2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedLoop.kt")
|
||||
public void testNestedLoop() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/takeWhile/nestedLoop.kt");
|
||||
|
||||
Reference in New Issue
Block a user