Option to use 'asSequence()'

This commit is contained in:
Valentin Kipyatkov
2016-08-11 20:36:43 +03:00
parent acdf9e82b4
commit bdd4363802
380 changed files with 2188 additions and 42 deletions
@@ -84,6 +84,7 @@ import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest
import org.jetbrains.kotlin.idea.highlighter.* import org.jetbrains.kotlin.idea.highlighter.*
import org.jetbrains.kotlin.idea.imports.AbstractOptimizeImportsTest import org.jetbrains.kotlin.idea.imports.AbstractOptimizeImportsTest
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest
import org.jetbrains.kotlin.idea.intentions.AbstractIntentionTest2
import org.jetbrains.kotlin.idea.intentions.AbstractMultiFileIntentionTest import org.jetbrains.kotlin.idea.intentions.AbstractMultiFileIntentionTest
import org.jetbrains.kotlin.idea.intentions.declarations.AbstractJoinLinesTest import org.jetbrains.kotlin.idea.intentions.declarations.AbstractJoinLinesTest
import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest
@@ -508,6 +509,10 @@ fun main(args: Array<String>) {
model("intentions", pattern = "^([\\w\\-_]+)\\.kt$") model("intentions", pattern = "^([\\w\\-_]+)\\.kt$")
} }
testClass<AbstractIntentionTest2>() {
model("intentions/loopToCallChain", pattern = "^([\\w\\-_]+)\\.kt$")
}
testClass<AbstractInspectionTest>() { testClass<AbstractInspectionTest>() {
model("intentions", pattern = "^(inspections\\.test)$", singleClass = true) model("intentions", pattern = "^(inspections\\.test)$", singleClass = true)
model("inspections", pattern = "^(inspections\\.test)$", singleClass = true) model("inspections", pattern = "^(inspections\\.test)$", singleClass = true)
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.idea.inspections package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInspection.* import com.intellij.codeInspection.*
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory import com.intellij.openapi.editor.EditorFactory
@@ -88,7 +90,7 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
if (fixes == null) { if (fixes == null) {
fixes = SmartList<LocalQuickFix>() fixes = SmartList<LocalQuickFix>()
} }
fixes!!.add(IntentionBasedQuickFix(intention, intention.text, additionalChecker, targetElement)) fixes!!.add(createQuickFix(intention, additionalChecker, targetElement))
} }
} }
} }
@@ -109,14 +111,27 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
protected open val problemHighlightType: ProblemHighlightType protected open val problemHighlightType: ProblemHighlightType
get() = ProblemHighlightType.GENERIC_ERROR_OR_WARNING get() = ProblemHighlightType.GENERIC_ERROR_OR_WARNING
private fun createQuickFix(
intention: SelfTargetingRangeIntention<TElement>,
additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
targetElement: TElement
): IntentionBasedQuickFix {
return when (intention) {
is LowPriorityAction -> LowPriorityIntentionBasedQuickFix(intention, additionalChecker, targetElement)
is HighPriorityAction -> HighPriorityIntentionBasedQuickFix(intention, additionalChecker, targetElement)
else -> IntentionBasedQuickFix(intention, additionalChecker, targetElement)
}
}
/* we implement IntentionAction to provide isAvailable which will be used to hide outdated items and make sure we never call 'invoke' for such item */ /* we implement IntentionAction to provide isAvailable which will be used to hide outdated items and make sure we never call 'invoke' for such item */
private inner class IntentionBasedQuickFix( private open inner class IntentionBasedQuickFix(
private val intention: SelfTargetingRangeIntention<TElement>, private val intention: SelfTargetingRangeIntention<TElement>,
private val text: String,
private val additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean, private val additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
targetElement: TElement targetElement: TElement
) : LocalQuickFixOnPsiElement(targetElement), IntentionAction { ) : LocalQuickFixOnPsiElement(targetElement), IntentionAction {
private val text = intention.text
// store text into variable because intention instance is shared and may change its text later // store text into variable because intention instance is shared and may change its text later
override fun getFamilyName() = intention.familyName override fun getFamilyName() = intention.familyName
@@ -145,6 +160,18 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
intention.applyTo(startElement as TElement, editor) intention.applyTo(startElement as TElement, editor)
} }
} }
private inner class LowPriorityIntentionBasedQuickFix(
intention: SelfTargetingRangeIntention<TElement>,
additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
targetElement: TElement
) : IntentionBasedQuickFix(intention, additionalChecker, targetElement), LowPriorityAction
private inner class HighPriorityIntentionBasedQuickFix(
intention: SelfTargetingRangeIntention<TElement>,
additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
targetElement: TElement
) : IntentionBasedQuickFix(intention, additionalChecker, targetElement), HighPriorityAction
} }
fun PsiElement.findExistingEditor(): Editor? { fun PsiElement.findExistingEditor(): Editor? {
@@ -0,0 +1,7 @@
fun foo(list: List<String>) {
val sum = <spot>list
.asSequence()
.map { it.calcSomething() }
.filter { it > 0 }
.sumBy { it }</spot>
}
@@ -0,0 +1,9 @@
fun foo(list: List<String>) {
val sum = 0
<spot>for (s in list) {
val x = s.calcSomething()
if (x > 0) {
sum += x
}
}</spot>
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts a for-loop into a sequence of stdlib-operations (like "map", "filter" etc) with lazy evaluation (using 'asSequence()' method)
</body>
</html>
+5
View File
@@ -1018,6 +1018,11 @@
<category>Kotlin</category> <category>Kotlin</category>
</intentionAction> </intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.loopToCallChain.LoopToLazyCallChainIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction> <intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.loopToCallChain.UseWithIndexIntention</className> <className>org.jetbrains.kotlin.idea.intentions.loopToCallChain.UseWithIndexIntention</className>
<category>Kotlin</category> <category>Kotlin</category>
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.intentions.loopToCallChain package org.jetbrains.kotlin.idea.intentions.loopToCallChain
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.core.moveCaret import org.jetbrains.kotlin.idea.core.moveCaret
@@ -26,27 +27,39 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
class LoopToCallChainInspection : IntentionBasedInspection<KtForExpression>( class LoopToCallChainInspection : IntentionBasedInspection<KtForExpression>(
LoopToCallChainIntention(), listOf(IntentionData(LoopToCallChainIntention()), IntentionData(LoopToLazyCallChainIntention())),
problemText = "Loop can be replaced with stdlib operations") problemText = "Loop can be replaced with stdlib operations",
elementType = KtForExpression::class.java)
class LoopToCallChainIntention : SelfTargetingRangeIntention<KtForExpression>( class LoopToCallChainIntention : AbstractLoopToCallChainIntention(lazy = false, text = "Replace with stdlib operations")
class LoopToLazyCallChainIntention : AbstractLoopToCallChainIntention(lazy = true, text = "Replace with stdlib operations with use of 'asSequence()'"), LowPriorityAction
abstract class AbstractLoopToCallChainIntention(private val lazy: Boolean, text: String) : SelfTargetingRangeIntention<KtForExpression>(
KtForExpression::class.java, KtForExpression::class.java,
"Replace with stdlib operations" text
) { ) {
override fun applicabilityRange(element: KtForExpression): TextRange? { override fun applicabilityRange(element: KtForExpression): TextRange? {
val match = match(element) val match = match(element, lazy)
text = if (match != null) "Replace with '${match.transformationMatch.buildPresentation()}'" else defaultText text = if (match != null) "Replace with '${match.transformationMatch.buildPresentation()}'" else defaultText
return if (match != null) element.forKeyword.textRange else null return if (match != null) element.forKeyword.textRange else null
} }
private fun TransformationMatch.Result.buildPresentation(): String { private fun TransformationMatch.Result.buildPresentation(): String {
var transformations = sequenceTransformations + resultTransformation return buildPresentation(sequenceTransformations + resultTransformation, null)
}
private fun buildPresentation(transformations: List<Transformation>, prevPresentation: String?): String {
val MAX = 3 val MAX = 3
var result: String? = null
if (transformations.size > MAX) { if (transformations.size > MAX) {
transformations = transformations.drop(transformations.size - MAX) if (transformations[0] is AsSequenceTransformation) {
result = ".." return buildPresentation(transformations.drop(1), transformations[0].presentation)
}
return buildPresentation(transformations.drop(transformations.size - MAX), prevPresentation?.let { it + ".." } ?: "..")
} }
var result: String? = prevPresentation
for (transformation in transformations) { for (transformation in transformations) {
result = transformation.buildPresentation(result) result = transformation.buildPresentation(result)
} }
@@ -54,7 +67,7 @@ class LoopToCallChainIntention : SelfTargetingRangeIntention<KtForExpression>(
} }
override fun applyTo(element: KtForExpression, editor: Editor?) { override fun applyTo(element: KtForExpression, editor: Editor?) {
val match = match(element)!! val match = match(element, lazy)!!
val result = convertLoop(element, match) val result = convertLoop(element, match)
val offset = when (result) { val offset = when (result) {
@@ -65,4 +78,4 @@ class LoopToCallChainIntention : SelfTargetingRangeIntention<KtForExpression>(
editor?.moveCaret(offset) editor?.moveCaret(offset)
} }
} }
@@ -89,6 +89,9 @@ abstract class AssignToVariableResultTransformation(
override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression { override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression {
return delegate.generateCode(chainedCallGenerator) return delegate.generateCode(chainedCallGenerator)
} }
override val lazyMakesSense: Boolean
get() = delegate.lazyMakesSense
} }
} }
} }
@@ -89,6 +89,9 @@ interface ResultTransformation : Transformation {
* except for the loop itself and the result element returned from this method * except for the loop itself and the result element returned from this method
*/ */
fun convertLoop(resultCallChain: KtExpression, commentSavingRangeHolder: CommentSavingRangeHolder): KtExpression fun convertLoop(resultCallChain: KtExpression, commentSavingRangeHolder: CommentSavingRangeHolder): KtExpression
val lazyMakesSense: Boolean
get() = false
} }
/** /**
@@ -103,6 +106,7 @@ data class MatchingState(
* Matchers can assume that indexVariable is null if it's not used in the rest of the loop * Matchers can assume that indexVariable is null if it's not used in the rest of the loop
*/ */
val indexVariable: KtCallableDeclaration?, val indexVariable: KtCallableDeclaration?,
val lazySequence: Boolean,
val pseudocodeProvider: () -> Pseudocode, val pseudocodeProvider: () -> Pseudocode,
val initializationStatementsToDelete: Collection<KtExpression> = emptyList(), val initializationStatementsToDelete: Collection<KtExpression> = emptyList(),
val previousTransformations: MutableList<SequenceTransformation> = arrayListOf(), val previousTransformations: MutableList<SequenceTransformation> = arrayListOf(),
@@ -210,3 +214,15 @@ class CommentSavingRangeHolder(range: PsiChildRange) {
private fun PsiElement.siblingsBefore() = if (prevSibling != null) PsiChildRange(parent.firstChild, prevSibling) else PsiChildRange.EMPTY private fun PsiElement.siblingsBefore() = if (prevSibling != null) PsiChildRange(parent.firstChild, prevSibling) else PsiChildRange.EMPTY
} }
class AsSequenceTransformation(override val loop: KtForExpression) : SequenceTransformation {
override val presentation: String
get() = "asSequence()"
override val affectsIndex: Boolean
get() = false
override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression {
return chainedCallGenerator.generate("asSequence()")
}
}
@@ -25,10 +25,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.analysis.analyzeInContext import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.AddToCollectionTransformation import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.*
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.CountTransformation
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.FindTransformationMatcher
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.result.ForEachTransformation
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.FilterTransformation import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.FilterTransformation
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.FlatMapTransformation import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.FlatMapTransformation
import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.IntroduceIndexMatcher import org.jetbrains.kotlin.idea.intentions.loopToCallChain.sequence.IntroduceIndexMatcher
@@ -66,10 +63,11 @@ data class MatchResult(
val initializationStatementsToDelete: Collection<KtExpression> val initializationStatementsToDelete: Collection<KtExpression>
) )
fun match(loop: KtForExpression): MatchResult? { //TODO: loop which is already over Sequence
fun match(loop: KtForExpression, useLazySequence: Boolean): MatchResult? {
val (inputVariable, indexVariable, sequenceExpression) = extractLoopData(loop) ?: return null val (inputVariable, indexVariable, sequenceExpression) = extractLoopData(loop) ?: return null
var state = createInitialMatchingState(loop, inputVariable, indexVariable) ?: return null var state = createInitialMatchingState(loop, inputVariable, indexVariable, useLazySequence) ?: return null
// used just as optimization to avoid unnecessary checks // used just as optimization to avoid unnecessary checks
val loopContainsEmbeddedBreakOrContinue = loop.containsEmbeddedBreakOrContinue() val loopContainsEmbeddedBreakOrContinue = loop.containsEmbeddedBreakOrContinue()
@@ -122,9 +120,22 @@ fun match(loop: KtForExpression): MatchResult? {
is TransformationMatch.Result -> { is TransformationMatch.Result -> {
if (restContainsEmbeddedBreakOrContinue && !matcher.embeddedBreakOrContinuePossible) continue@MatchersLoop if (restContainsEmbeddedBreakOrContinue && !matcher.embeddedBreakOrContinuePossible) continue@MatchersLoop
return TransformationMatch.Result(match.resultTransformation, state.previousTransformations) var result = TransformationMatch.Result(match.resultTransformation, state.previousTransformations)
.let { mergeTransformations(it) } result = mergeTransformations(result)
.let { MatchResult(sequenceExpression, it, state.initializationStatementsToDelete) }
if (useLazySequence) {
val sequenceTransformations = result.sequenceTransformations
val resultTransformation = result.resultTransformation
if (sequenceTransformations.isEmpty() && !resultTransformation.lazyMakesSense
|| sequenceTransformations.size == 1 && resultTransformation is AssignToListTransformation) {
return null // it makes no sense to use lazy sequence if no intermediate sequences produced
}
val asSequence = AsSequenceTransformation(loop)
result = TransformationMatch.Result(resultTransformation, listOf(asSequence) + sequenceTransformations)
}
return MatchResult(sequenceExpression, result, state.initializationStatementsToDelete)
.check { checkSmartCastsPreserved(loop, it) } .check { checkSmartCastsPreserved(loop, it) }
} }
} }
@@ -135,7 +146,6 @@ fun match(loop: KtForExpression): MatchResult? {
} }
} }
//TODO: offer to use of .asSequence() as an option
fun convertLoop(loop: KtForExpression, matchResult: MatchResult): KtExpression { fun convertLoop(loop: KtForExpression, matchResult: MatchResult): KtExpression {
val resultTransformation = matchResult.transformationMatch.resultTransformation val resultTransformation = matchResult.transformationMatch.resultTransformation
@@ -191,7 +201,8 @@ private fun extractLoopData(loop: KtForExpression): LoopData? {
private fun createInitialMatchingState( private fun createInitialMatchingState(
loop: KtForExpression, loop: KtForExpression,
inputVariable: KtCallableDeclaration, inputVariable: KtCallableDeclaration,
indexVariable: KtCallableDeclaration? indexVariable: KtCallableDeclaration?,
useLazySequence: Boolean
): MatchingState? { ): MatchingState? {
val pseudocodeProvider: () -> Pseudocode = object : () -> Pseudocode { val pseudocodeProvider: () -> Pseudocode = object : () -> Pseudocode {
@@ -210,6 +221,7 @@ private fun createInitialMatchingState(
statements = listOf(loop.body ?: return null), statements = listOf(loop.body ?: return null),
inputVariable = inputVariable, inputVariable = inputVariable,
indexVariable = indexVariable, indexVariable = indexVariable,
lazySequence = useLazySequence,
pseudocodeProvider = pseudocodeProvider pseudocodeProvider = pseudocodeProvider
) )
} }
@@ -363,7 +375,7 @@ fun matchIndexToIntroduce(loop: KtForExpression): IntroduceIndexData? {
val (inputVariable, indexVariable) = extractLoopData(loop) ?: return null val (inputVariable, indexVariable) = extractLoopData(loop) ?: return null
if (indexVariable != null) return null // loop is already with "withIndex" if (indexVariable != null) return null // loop is already with "withIndex"
val state = createInitialMatchingState(loop, inputVariable, indexVariable)?.unwrapBlock() ?: return null val state = createInitialMatchingState(loop, inputVariable, indexVariable, useLazySequence = false)?.unwrapBlock() ?: return null
val match = IntroduceIndexMatcher.match(state) ?: return null val match = IntroduceIndexMatcher.match(state) ?: return null
assert(match.sequenceTransformations.isEmpty()) assert(match.sequenceTransformations.isEmpty())
@@ -129,14 +129,21 @@ class AddToCollectionTransformation(
CollectionKind.LIST -> { CollectionKind.LIST -> {
when { when {
canChangeInitializerType(collectionInitialization, KotlinBuiltIns.FQ_NAMES.list, state.outerLoop) -> { canChangeInitializerType(collectionInitialization, KotlinBuiltIns.FQ_NAMES.list, state.outerLoop) -> {
val transformation = if (argumentIsInputVariable) { if (argumentIsInputVariable) {
AssignToListTransformation(state.outerLoop, collectionInitialization) val assignToList = AssignToListTransformation(state.outerLoop, collectionInitialization, state.lazySequence)
return TransformationMatch.Result(assignToList)
} }
else { else {
val mapTransformation = MapTransformation(state.outerLoop, state.inputVariable, null, addOperationArgument, mapNotNull = false) val mapTransformation = MapTransformation(state.outerLoop, state.inputVariable, null, addOperationArgument, mapNotNull = false)
AssignSequenceResultTransformation(mapTransformation, collectionInitialization) if (state.lazySequence) {
val assignToList = AssignToListTransformation(state.outerLoop, collectionInitialization, lazySequence = true)
return TransformationMatch.Result(assignToList, mapTransformation)
}
else {
val assignSequence = AssignSequenceResultTransformation(mapTransformation, collectionInitialization)
return TransformationMatch.Result(assignSequence)
}
} }
return TransformationMatch.Result(transformation)
} }
canChangeInitializerType(collectionInitialization, KotlinBuiltIns.FQ_NAMES.mutableList, state.outerLoop) -> { canChangeInitializerType(collectionInitialization, KotlinBuiltIns.FQ_NAMES.mutableList, state.outerLoop) -> {
@@ -325,6 +332,11 @@ class FlatMapToTransformation private constructor(
return chainedCallGenerator.generate("flatMapTo($0) $1:'{}'", targetCollection, lambda) return chainedCallGenerator.generate("flatMapTo($0) $1:'{}'", targetCollection, lambda)
} }
// asSequence().flatMapTo(){} makes real difference (because expression inside lambda is evaluated lazily)
//TODO: return false if expression is input variable
override val lazyMakesSense: Boolean
get() = true
companion object { companion object {
fun create( fun create(
loop: KtForExpression, loop: KtForExpression,
@@ -346,14 +358,16 @@ class FlatMapToTransformation private constructor(
class AssignToListTransformation( class AssignToListTransformation(
loop: KtForExpression, loop: KtForExpression,
initialization: VariableInitialization initialization: VariableInitialization,
private val lazySequence: Boolean
) : AssignToVariableResultTransformation(loop, initialization) { ) : AssignToVariableResultTransformation(loop, initialization) {
override val presentation: String override val presentation: String
get() = "toList()" get() = "toList()"
override fun mergeWithPrevious(previousTransformation: SequenceTransformation): ResultTransformation? { override fun mergeWithPrevious(previousTransformation: SequenceTransformation): ResultTransformation? {
//TODO: can be any SequenceTransformation's that return not List<T>? Also this code needs to be changed when .asSequence() used if (lazySequence) return null // toList() is necessary if the result is Sequence
//TODO: can be any SequenceTransformation's that return not List<T>?
return AssignSequenceResultTransformation(previousTransformation, initialization) return AssignSequenceResultTransformation(previousTransformation, initialization)
} }
@@ -70,7 +70,8 @@ class FlatMapTransformation(
// if nested loop range uses index, convert to "mapIndexed {...}.flatMap { it }" // if nested loop range uses index, convert to "mapIndexed {...}.flatMap { it }"
val mapIndexedTransformation = MapTransformation(state.outerLoop, state.inputVariable, state.indexVariable, transform, mapNotNull = false) val mapIndexedTransformation = MapTransformation(state.outerLoop, state.inputVariable, state.indexVariable, transform, mapNotNull = false)
val inputVarExpression = KtPsiFactory(nestedLoop).createExpressionByPattern("$0", state.inputVariable.nameAsSafeName) val inputVarExpression = KtPsiFactory(nestedLoop).createExpressionByPattern("$0", state.inputVariable.nameAsSafeName)
val flatMapTransformation = FlatMapTransformation(state.outerLoop, state.inputVariable, inputVarExpression) val transformToUse = if (state.lazySequence) inputVarExpression.asSequence() else inputVarExpression
val flatMapTransformation = FlatMapTransformation(state.outerLoop, state.inputVariable, transformToUse)
val newState = state.copy( val newState = state.copy(
innerLoop = nestedLoop, innerLoop = nestedLoop,
statements = listOf(nestedLoopBody), statements = listOf(nestedLoopBody),
@@ -79,7 +80,8 @@ class FlatMapTransformation(
return TransformationMatch.Sequence(listOf(mapIndexedTransformation, flatMapTransformation), newState) return TransformationMatch.Sequence(listOf(mapIndexedTransformation, flatMapTransformation), newState)
} }
val transformation = FlatMapTransformation(state.outerLoop, state.inputVariable, transform) val transformToUse = if (state.lazySequence) transform.asSequence() else transform
val transformation = FlatMapTransformation(state.outerLoop, state.inputVariable, transformToUse)
val newState = state.copy( val newState = state.copy(
innerLoop = nestedLoop, innerLoop = nestedLoop,
statements = listOf(nestedLoopBody), statements = listOf(nestedLoopBody),
@@ -87,5 +89,9 @@ class FlatMapTransformation(
) )
return TransformationMatch.Sequence(transformation, newState) return TransformationMatch.Sequence(transformation, newState)
} }
private fun KtExpression.asSequence(): KtExpression {
return KtPsiFactory(this).createExpressionByPattern("$0.asSequence()", this)
}
} }
} }
+1
View File
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.loopToCallChain.LoopToLazyCallChainIntention
@@ -1,7 +1,8 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with '+='" // INTENTION_TEXT: "Replace with '+='"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) { fun foo(list: List<String>, target: MutableList<String>) {
<caret>for (s in list) { <caret>for (s in list) {
target.add(s) target.add(s)
} }
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with '+='" // INTENTION_TEXT: "Replace with '+='"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) { fun foo(list: List<String>, target: MutableList<String>) {
<caret>target += list <caret>target += list
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'toMutableList()'" // INTENTION_TEXT: "Replace with 'toMutableList()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(map: Map<Int, String>): List<String> { fun foo(map: Map<Int, String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'toMutableList()'" // INTENTION_TEXT: "Replace with 'toMutableList()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(map: Map<Int, String>): List<String> { fun foo(map: Map<Int, String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<MutableCollection<Int>>) { fun foo(list: List<MutableCollection<Int>>) {
<caret>for (collection in list) { <caret>for (collection in list) {
collection.add(collection.size) collection.add(collection.size)
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
var globalCollection = ArrayList<Int>() var globalCollection = ArrayList<Int>()
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'mapTo(){}'" // INTENTION_TEXT: "Replace with 'mapTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<MutableCollection<Int>>) { fun foo(list: List<MutableCollection<Int>>) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'mapTo(){}'" // INTENTION_TEXT: "Replace with 'mapTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<MutableCollection<Int>>) { fun foo(list: List<MutableCollection<Int>>) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
var found = false var found = false
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
val <caret>found = list.any { it.length > 0 } val <caret>found = list.any { it.length > 0 }
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
var found = false var found = false
println("Starting the search") println("Starting the search")
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
println("Starting the search") println("Starting the search")
val <caret>found = list.any { it.length > 0 } val <caret>found = list.any { it.length > 0 }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, p: Int) { fun foo(list: List<String>, p: Int) {
var found: Boolean var found: Boolean
if (p > 0) { if (p > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, p: Int) { fun foo(list: List<String>, p: Int) {
var found: Boolean var found: Boolean
if (p > 0) { if (p > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
var found = false var found = false
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
val <caret>found = list.any { it.length > 0 } val <caret>found = list.any { it.length > 0 }
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
var result = 0 var result = 0
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
val <caret>result = if (list.any { it.length > 0 }) 1 else 0 val <caret>result = if (list.any { it.length > 0 }) 1 else 0
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
var result = takeInt() var result = takeInt()
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean { fun foo(list: List<String>): Boolean {
<caret>for (s in list) { <caret>for (s in list) {
if (s.length > 0) { if (s.length > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean { fun foo(list: List<String>): Boolean {
<caret>return list.any { it.length > 0 } <caret>return list.any { it.length > 0 }
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
<caret>for (s in list) { <caret>for (s in list) {
if (s.length > 0) { if (s.length > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'" // INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
<caret>return if (list.any { it.length > 0 }) -1 else takeInt() <caret>return if (list.any { it.length > 0 }) -1 else takeInt()
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.any()'" // INTENTION_TEXT: "Replace with 'filterIndexed{}.any()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.any()'"
fun foo(list: List<String>) { fun foo(list: List<String>) {
var found = false var found = false
<caret>for ((index, s) in list.withIndex()) { <caret>for ((index, s) in list.withIndex()) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.any()'" // INTENTION_TEXT: "Replace with 'filterIndexed{}.any()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.any()'"
fun foo(list: List<String>) { fun foo(list: List<String>) {
val <caret>found = list val <caret>found = list
.filterIndexed { index, s -> s.length > index } .filterIndexed { index, s -> s.length > index }
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.any()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.any()'"
fun foo(list: List<String>) {
val <caret>found = list
.asSequence()
.filterIndexed { index, s -> s.length > index }
.any()
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any()'" // INTENTION_TEXT: "Replace with 'any()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean { fun foo(list: List<String>): Boolean {
<caret>for (s in list) { <caret>for (s in list) {
return true return true
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any()'" // INTENTION_TEXT: "Replace with 'any()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean { fun foo(list: List<String>): Boolean {
<caret>return list.any() <caret>return list.any()
} }
+2
View File
@@ -1,4 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'firstOrNull{}'"
// IS_APPLICABLE_2: false
fun foo(array: Array<String>): String? { fun foo(array: Array<String>): String? {
<caret>for (s in array) { <caret>for (s in array) {
if (s.isNotBlank()) { if (s.isNotBlank()) {
@@ -1,4 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'firstOrNull{}'"
// IS_APPLICABLE_2: false
fun foo(array: Array<String>): String? { fun foo(array: Array<String>): String? {
<caret>return array.firstOrNull { it.isNotBlank() } <caret>return array.firstOrNull { it.isNotBlank() }
} }
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'" // INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): List<String> { fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'" // INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): List<String> { fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'" // INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>, p: Int): List<String> { fun foo(list: List<String>, p: Int): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'" // INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>, p: Int): List<String> { fun foo(list: List<String>, p: Int): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}'" // INTENTION_TEXT: "Replace with 'filterIndexed{}'"
// IS_APPLICABLE_2: false
import java.util.* import java.util.*
fun foo(list: List<String>): List<String> { fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}'" // INTENTION_TEXT: "Replace with 'filterIndexed{}'"
// IS_APPLICABLE_2: false
import java.util.* import java.util.*
fun foo(list: List<String>): List<String> { fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterNotNull()'" // INTENTION_TEXT: "Replace with 'filterNotNull()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String?>): List<String> { fun foo(list: List<String?>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterNotNull()'" // INTENTION_TEXT: "Replace with 'filterNotNull()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String?>): List<String> { fun foo(list: List<String?>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'" // INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): ArrayList<String> { fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'" // INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): ArrayList<String> { fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'" // INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>, p: Int): ArrayList<String> { fun foo(list: List<String>, p: Int): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'" // INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>, p: Int): ArrayList<String> { fun foo(list: List<String>, p: Int): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'" // INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.* import java.util.*
fun foo(list: List<String>): ArrayList<String> { fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'" // INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.* import java.util.*
fun foo(list: List<String>): ArrayList<String> { fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.toMutableList()'" // INTENTION_TEXT: "Replace with 'filter{}.toMutableList()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.toMutableList()'"
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): MutableList<String> { fun foo(list: List<String>): MutableList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.toMutableList()'" // INTENTION_TEXT: "Replace with 'filter{}.toMutableList()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.toMutableList()'"
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): MutableList<String> { fun foo(list: List<String>): MutableList<String> {
@@ -0,0 +1,12 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.toMutableList()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.toMutableList()'"
import java.util.ArrayList
fun foo(list: List<String>): MutableList<String> {
val <caret>result = list
.asSequence()
.filter { it.length > 0 }
.toMutableList()
return result
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'" // INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(): List<String> { fun foo(): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'" // INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList import java.util.ArrayList
fun foo(): List<String> { fun foo(): List<String> {
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.map{}'" // INTENTION_TEXT: "Replace with 'filter{}.map{}'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.map{}.toList()'"
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): List<Int> { fun foo(list: List<String>): List<Int> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.map{}'" // INTENTION_TEXT: "Replace with 'filter{}.map{}'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.map{}.toList()'"
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): List<Int> { fun foo(list: List<String>): List<Int> {
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.map{}'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.map{}.toList()'"
import java.util.ArrayList
fun foo(list: List<String>): List<Int> {
val result = list
.asSequence()
.filter { it.length > 0 }
.map { it.hashCode() }
.toList()
return result
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.map{}'" // INTENTION_TEXT: "Replace with 'filter{}.map{}'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.map{}.toList()'"
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): List<Int> { fun foo(list: List<String>): List<Int> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.map{}'" // INTENTION_TEXT: "Replace with 'filter{}.map{}'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.map{}.toList()'"
import java.util.ArrayList import java.util.ArrayList
fun foo(list: List<String>): List<Int> { fun foo(list: List<String>): List<Int> {
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}.map{}'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filter{}.map{}.toList()'"
import java.util.ArrayList
fun foo(list: List<String>): List<Int> {
val <caret>result = list
.asSequence()
.filter { it.length > 0 }
.map { it.hashCode() }
.toList()
return result
}
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean { fun foo(list: List<String>): Boolean {
<caret>for (s in list) { <caret>for (s in list) {
if (s == "a") { if (s == "a") {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean { fun foo(list: List<String>): Boolean {
<caret>return list.contains("a") <caret>return list.contains("a")
} }
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
var v = true var v = true
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
val <caret>v = !list.contains("a") val <caret>v = !list.contains("a")
} }
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
var v = false var v = false
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) { fun foo(list: List<String>) {
val <caret>v = list.contains("a") val <caret>v = list.contains("a")
} }
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
<caret>for (s in list) { <caret>for (s in list) {
if (s == "a") { if (s == "a") {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'" // INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
<caret>return if (list.contains("a")) 1 else 0 <caret>return if (list.contains("a")) 1 else 0
} }
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
var count = 0 var count = 0
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
val <caret>count = list.count { it.isNotBlank() } val <caret>count = list.count { it.isNotBlank() }
return count return count
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count()'" // INTENTION_TEXT: "Replace with 'count()'"
// IS_APPLICABLE_2: false
fun foo(list: Iterable<String>): Int { fun foo(list: Iterable<String>): Int {
var count = 0 var count = 0
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count()'" // INTENTION_TEXT: "Replace with 'count()'"
// IS_APPLICABLE_2: false
fun foo(list: Iterable<String>): Int { fun foo(list: Iterable<String>): Int {
val <caret>count = list.count() val <caret>count = list.count()
return count return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Long { fun foo(list: List<String>): Long {
var count = 0L var count = 0L
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
var count = bar() var count = bar()
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
val <caret>count = bar() + list.count { it.isNotBlank() } val <caret>count = bar() + list.count { it.isNotBlank() }
return count return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
var count = 1 var count = 1
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
val <caret>count = 1 + list.count { it.isNotBlank() } val <caret>count = 1 + list.count { it.isNotBlank() }
return count return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
var count = 0 var count = 0
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'" // INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
val <caret>count = list.count { it.isNotBlank() } val <caret>count = list.count { it.isNotBlank() }
return count return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int { fun foo(list: List<String>): Int {
var count = 0 var count = 0
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// IS_APPLICABLE: false
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
class X { class X {
operator fun iterator(): Iterator<String>{ operator fun iterator(): Iterator<String>{
return emptyList<String>().iterator() return emptyList<String>().iterator()
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String?>, target: MutableList<String>) { fun foo(list: List<String?>, target: MutableList<String>) {
<caret>for (s in list) { <caret>for (s in list) {
val length = s?.length ?: break val length = s?.length ?: break
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) { fun foo(list: List<String>, target: MutableList<String>) {
<caret>for (s in list) { <caret>for (s in list) {
val length = if (s.isNotEmpty()) s.length else break val length = if (s.isNotEmpty()) s.length else break
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// IS_APPLICABLE: false // IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) { fun foo(list: List<String>, target: MutableList<String>) {
<caret>for (s in list) { <caret>for (s in list) {
val length = if (s.isNotEmpty()) s.length else continue val length = if (s.isNotEmpty()) s.length else continue
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'" // INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? { fun foo(list: List<String>): String? {
<caret>for ((index, s) in list.withIndex()) { <caret>for ((index, s) in list.withIndex()) {
if (s.length > index) { if (s.length > index) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'" // INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? { fun foo(list: List<String>): String? {
<caret>return list <caret>return list
.filterIndexed { index, s -> s.length > index } .filterIndexed { index, s -> s.length > index }
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? {
<caret>return list
.asSequence()
.filterIndexed { index, s -> s.length > index }
.firstOrNull()
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'" // INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? { fun foo(list: List<String>): String? {
var i = 0 var i = 0
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'" // INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? { fun foo(list: List<String>): String? {
<caret>return list <caret>return list
.filterIndexed { i, s -> s.length > i } .filterIndexed { i, s -> s.length > i }
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? {
<caret>return list
.asSequence()
.filterIndexed { i, s -> s.length > i }
.firstOrNull()
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with '...flatMap{}.filterNot{}.mapTo(){}'" // INTENTION_TEXT: "Replace with '...flatMap{}.filterNot{}.mapTo(){}'"
// INTENTION_TEXT_2: "Replace with 'asSequence()...flatMap{}.filterNot{}.mapTo(){}'"
fun foo(list: List<String>, target: MutableCollection<String>) { fun foo(list: List<String>, target: MutableCollection<String>) {
var i = 0 var i = 0
<caret>for (s in list) { <caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// INTENTION_TEXT: "Replace with '...flatMap{}.filterNot{}.mapTo(){}'" // INTENTION_TEXT: "Replace with '...flatMap{}.filterNot{}.mapTo(){}'"
// INTENTION_TEXT_2: "Replace with 'asSequence()...flatMap{}.filterNot{}.mapTo(){}'"
fun foo(list: List<String>, target: MutableCollection<String>) { fun foo(list: List<String>, target: MutableCollection<String>) {
<caret>list <caret>list
.filterIndexed { i, s -> i % 10 != 0 } .filterIndexed { i, s -> i % 10 != 0 }

Some files were not shown because too many files have changed in this diff Show More