From 26cdd0d5d52c6054bf381bc302d69f105b2a58cf Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 17 Aug 2016 18:06:34 +0300 Subject: [PATCH] KT-13482 "Loop can be replaced with stdlib operations" changes semantics #KT-13482 Fixed --- .../result/ForEachTransformation.kt | 11 ++++++++--- .../intentions/loopToCallChain/asSequenceOnly.kt | 14 ++++++++++++++ .../loopToCallChain/asSequenceOnly.kt.after2 | 13 +++++++++++++ .../idea/intentions/IntentionTest2Generated.java | 6 ++++++ .../idea/intentions/IntentionTestGenerated.java | 6 ++++++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 idea/testData/intentions/loopToCallChain/asSequenceOnly.kt create mode 100644 idea/testData/intentions/loopToCallChain/asSequenceOnly.kt.after2 diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt index dd5dfcf8e99..2868420ead5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/loopToCallChain/result/ForEachTransformation.kt @@ -17,9 +17,9 @@ package org.jetbrains.kotlin.idea.intentions.loopToCallChain.result import org.jetbrains.kotlin.idea.intentions.loopToCallChain.* -import org.jetbrains.kotlin.psi.KtCallableDeclaration -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtForExpression +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtPsiUtil.isAssignment +import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType class ForEachTransformation( loop: KtForExpression, @@ -53,6 +53,11 @@ class ForEachTransformation( if (state.previousTransformations.isEmpty()) return null // do not suggest conversion to just ".forEach{}" or ".forEachIndexed{}" val statement = state.statements.singleOrNull() ?: return null + + // check if contains assignment to non-qualified variable - in this case only use of lazy sequence is correct + if (!state.lazySequence + && statement.anyDescendantOfType { isAssignment(it) && it.left is KtNameReferenceExpression }) return null + //TODO: should we disallow it for complicated statements like loops, if, when? val transformation = ForEachTransformation(state.outerLoop, state.inputVariable, state.indexVariable, statement) return TransformationMatch.Result(transformation) diff --git a/idea/testData/intentions/loopToCallChain/asSequenceOnly.kt b/idea/testData/intentions/loopToCallChain/asSequenceOnly.kt new file mode 100644 index 00000000000..e3dede069cf --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/asSequenceOnly.kt @@ -0,0 +1,14 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.forEach{}'" +fun getMaxLineWidth(lineCount: Int): Float { + var max_width = 0.0f + for (i in 0..lineCount - 1) { + if (getLineWidth(i) > max_width) { + max_width = getLineWidth(i) + } + } + return max_width +} + +fun getLineWidth(i: Int): Float = TODO() diff --git a/idea/testData/intentions/loopToCallChain/asSequenceOnly.kt.after2 b/idea/testData/intentions/loopToCallChain/asSequenceOnly.kt.after2 new file mode 100644 index 00000000000..297c28eb432 --- /dev/null +++ b/idea/testData/intentions/loopToCallChain/asSequenceOnly.kt.after2 @@ -0,0 +1,13 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false +// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.forEach{}'" +fun getMaxLineWidth(lineCount: Int): Float { + var max_width = 0.0f + (0..lineCount - 1) + .asSequence() + .filter { getLineWidth(it) > max_width } + .forEach { max_width = getLineWidth(it) } + return max_width +} + +fun getLineWidth(i: Int): Float = TODO() diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java index 26f0364e466..ecb0d61cf9a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTest2Generated.java @@ -131,6 +131,12 @@ public class IntentionTest2Generated extends AbstractIntentionTest2 { doTest(fileName); } + @TestMetadata("asSequenceOnly.kt") + public void testAsSequenceOnly() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/asSequenceOnly.kt"); + doTest(fileName); + } + @TestMetadata("assignFilter.kt") public void testAssignFilter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/assignFilter.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 5c86385ccb0..96bb2b54fa7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -7291,6 +7291,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("asSequenceOnly.kt") + public void testAsSequenceOnly() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/asSequenceOnly.kt"); + doTest(fileName); + } + @TestMetadata("assignFilter.kt") public void testAssignFilter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/loopToCallChain/assignFilter.kt");