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.imports.AbstractOptimizeImportsTest
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.declarations.AbstractJoinLinesTest
import org.jetbrains.kotlin.idea.internal.AbstractBytecodeToolWindowTest
@@ -508,6 +509,10 @@ fun main(args: Array<String>) {
model("intentions", pattern = "^([\\w\\-_]+)\\.kt$")
}
testClass<AbstractIntentionTest2>() {
model("intentions/loopToCallChain", pattern = "^([\\w\\-_]+)\\.kt$")
}
testClass<AbstractInspectionTest>() {
model("intentions", pattern = "^(inspections\\.test)$", singleClass = true)
model("inspections", pattern = "^(inspections\\.test)$", singleClass = true)
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.idea.inspections
import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInspection.*
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory
@@ -88,7 +90,7 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
if (fixes == null) {
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
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 */
private inner class IntentionBasedQuickFix(
private open inner class IntentionBasedQuickFix(
private val intention: SelfTargetingRangeIntention<TElement>,
private val text: String,
private val additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
targetElement: TElement
) : LocalQuickFixOnPsiElement(targetElement), IntentionAction {
private val text = intention.text
// store text into variable because intention instance is shared and may change its text later
override fun getFamilyName() = intention.familyName
@@ -145,6 +160,18 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
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? {
@@ -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>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.loopToCallChain.LoopToLazyCallChainIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.loopToCallChain.UseWithIndexIntention</className>
<category>Kotlin</category>
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.intentions.loopToCallChain
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.core.moveCaret
@@ -26,27 +27,39 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.startOffset
class LoopToCallChainInspection : IntentionBasedInspection<KtForExpression>(
LoopToCallChainIntention(),
problemText = "Loop can be replaced with stdlib operations")
listOf(IntentionData(LoopToCallChainIntention()), IntentionData(LoopToLazyCallChainIntention())),
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,
"Replace with stdlib operations"
text
) {
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
return if (match != null) element.forKeyword.textRange else null
}
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
var result: String? = null
if (transformations.size > MAX) {
transformations = transformations.drop(transformations.size - MAX)
result = ".."
if (transformations[0] is AsSequenceTransformation) {
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) {
result = transformation.buildPresentation(result)
}
@@ -54,7 +67,7 @@ class LoopToCallChainIntention : SelfTargetingRangeIntention<KtForExpression>(
}
override fun applyTo(element: KtForExpression, editor: Editor?) {
val match = match(element)!!
val match = match(element, lazy)!!
val result = convertLoop(element, match)
val offset = when (result) {
@@ -65,4 +78,4 @@ class LoopToCallChainIntention : SelfTargetingRangeIntention<KtForExpression>(
editor?.moveCaret(offset)
}
}
}
@@ -89,6 +89,9 @@ abstract class AssignToVariableResultTransformation(
override fun generateCode(chainedCallGenerator: ChainedCallGenerator): KtExpression {
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
*/
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
*/
val indexVariable: KtCallableDeclaration?,
val lazySequence: Boolean,
val pseudocodeProvider: () -> Pseudocode,
val initializationStatementsToDelete: Collection<KtExpression> = emptyList(),
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
}
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.caches.resolve.analyze
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.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.result.*
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.IntroduceIndexMatcher
@@ -66,10 +63,11 @@ data class MatchResult(
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
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
val loopContainsEmbeddedBreakOrContinue = loop.containsEmbeddedBreakOrContinue()
@@ -122,9 +120,22 @@ fun match(loop: KtForExpression): MatchResult? {
is TransformationMatch.Result -> {
if (restContainsEmbeddedBreakOrContinue && !matcher.embeddedBreakOrContinuePossible) continue@MatchersLoop
return TransformationMatch.Result(match.resultTransformation, state.previousTransformations)
.let { mergeTransformations(it) }
.let { MatchResult(sequenceExpression, it, state.initializationStatementsToDelete) }
var result = TransformationMatch.Result(match.resultTransformation, state.previousTransformations)
result = mergeTransformations(result)
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) }
}
}
@@ -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 {
val resultTransformation = matchResult.transformationMatch.resultTransformation
@@ -191,7 +201,8 @@ private fun extractLoopData(loop: KtForExpression): LoopData? {
private fun createInitialMatchingState(
loop: KtForExpression,
inputVariable: KtCallableDeclaration,
indexVariable: KtCallableDeclaration?
indexVariable: KtCallableDeclaration?,
useLazySequence: Boolean
): MatchingState? {
val pseudocodeProvider: () -> Pseudocode = object : () -> Pseudocode {
@@ -210,6 +221,7 @@ private fun createInitialMatchingState(
statements = listOf(loop.body ?: return null),
inputVariable = inputVariable,
indexVariable = indexVariable,
lazySequence = useLazySequence,
pseudocodeProvider = pseudocodeProvider
)
}
@@ -363,7 +375,7 @@ fun matchIndexToIntroduce(loop: KtForExpression): IntroduceIndexData? {
val (inputVariable, indexVariable) = extractLoopData(loop) ?: return null
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
assert(match.sequenceTransformations.isEmpty())
@@ -129,14 +129,21 @@ class AddToCollectionTransformation(
CollectionKind.LIST -> {
when {
canChangeInitializerType(collectionInitialization, KotlinBuiltIns.FQ_NAMES.list, state.outerLoop) -> {
val transformation = if (argumentIsInputVariable) {
AssignToListTransformation(state.outerLoop, collectionInitialization)
if (argumentIsInputVariable) {
val assignToList = AssignToListTransformation(state.outerLoop, collectionInitialization, state.lazySequence)
return TransformationMatch.Result(assignToList)
}
else {
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) -> {
@@ -325,6 +332,11 @@ class FlatMapToTransformation private constructor(
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 {
fun create(
loop: KtForExpression,
@@ -346,14 +358,16 @@ class FlatMapToTransformation private constructor(
class AssignToListTransformation(
loop: KtForExpression,
initialization: VariableInitialization
initialization: VariableInitialization,
private val lazySequence: Boolean
) : AssignToVariableResultTransformation(loop, initialization) {
override val presentation: String
get() = "toList()"
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)
}
@@ -70,7 +70,8 @@ class FlatMapTransformation(
// if nested loop range uses index, convert to "mapIndexed {...}.flatMap { it }"
val mapIndexedTransformation = MapTransformation(state.outerLoop, state.inputVariable, state.indexVariable, transform, mapNotNull = false)
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(
innerLoop = nestedLoop,
statements = listOf(nestedLoopBody),
@@ -79,7 +80,8 @@ class FlatMapTransformation(
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(
innerLoop = nestedLoop,
statements = listOf(nestedLoopBody),
@@ -87,5 +89,9 @@ class FlatMapTransformation(
)
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
// INTENTION_TEXT: "Replace with '+='"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) {
<caret>for (s in list) {
target.add(s)
}
}
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with '+='"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) {
<caret>target += list
}
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'toMutableList()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(map: Map<Int, String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'toMutableList()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(map: Map<Int, String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<MutableCollection<Int>>) {
<caret>for (collection in list) {
collection.add(collection.size)
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
import java.util.ArrayList
var globalCollection = ArrayList<Int>()
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'mapTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<MutableCollection<Int>>) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'mapTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<MutableCollection<Int>>) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
var found = false
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
val <caret>found = list.any { it.length > 0 }
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
var found = false
println("Starting the search")
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
println("Starting the search")
val <caret>found = list.any { it.length > 0 }
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, p: Int) {
var found: Boolean
if (p > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>, p: Int) {
var found: Boolean
if (p > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
var found = false
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
val <caret>found = list.any { it.length > 0 }
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
var result = 0
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
val <caret>result = if (list.any { it.length > 0 }) 1 else 0
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
var result = takeInt()
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean {
<caret>for (s in list) {
if (s.length > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean {
<caret>return list.any { it.length > 0 }
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
<caret>for (s in list) {
if (s.length > 0) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
<caret>return if (list.any { it.length > 0 }) -1 else takeInt()
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.any()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.any()'"
fun foo(list: List<String>) {
var found = false
<caret>for ((index, s) in list.withIndex()) {
@@ -1,5 +1,6 @@
// 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
.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
// INTENTION_TEXT: "Replace with 'any()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean {
<caret>for (s in list) {
return true
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'any()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean {
<caret>return list.any()
}
+2
View File
@@ -1,4 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'firstOrNull{}'"
// IS_APPLICABLE_2: false
fun foo(array: Array<String>): String? {
<caret>for (s in array) {
if (s.isNotBlank()) {
@@ -1,4 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'firstOrNull{}'"
// IS_APPLICABLE_2: false
fun foo(array: Array<String>): String? {
<caret>return array.firstOrNull { it.isNotBlank() }
}
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>, p: Int): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>, p: Int): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}'"
// IS_APPLICABLE_2: false
import java.util.*
fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}'"
// IS_APPLICABLE_2: false
import java.util.*
fun foo(list: List<String>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterNotNull()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String?>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterNotNull()'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String?>): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>, p: Int): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(list: List<String>, p: Int): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.*
fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterTo(){}'"
// IS_APPLICABLE_2: false
import java.util.*
fun foo(list: List<String>): ArrayList<String> {
@@ -1,5 +1,6 @@
// 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> {
@@ -1,5 +1,6 @@
// 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> {
@@ -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
// INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(): List<String> {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filter{}'"
// IS_APPLICABLE_2: false
import java.util.ArrayList
fun foo(): List<String> {
+1
View File
@@ -1,5 +1,6 @@
// 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> {
@@ -1,5 +1,6 @@
// 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> {
@@ -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
// 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> {
@@ -1,5 +1,6 @@
// 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> {
@@ -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
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean {
<caret>for (s in list) {
if (s == "a") {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Boolean {
<caret>return list.contains("a")
}
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
var v = true
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
val <caret>v = !list.contains("a")
}
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
var v = false
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>) {
val <caret>v = list.contains("a")
}
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
<caret>for (s in list) {
if (s == "a") {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'contains()'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
<caret>return if (list.contains("a")) 1 else 0
}
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
var count = 0
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
val <caret>count = list.count { it.isNotBlank() }
return count
+1
View File
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count()'"
// IS_APPLICABLE_2: false
fun foo(list: Iterable<String>): Int {
var count = 0
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count()'"
// IS_APPLICABLE_2: false
fun foo(list: Iterable<String>): Int {
val <caret>count = list.count()
return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Long {
var count = 0L
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
var count = bar()
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
val <caret>count = bar() + list.count { it.isNotBlank() }
return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
var count = 1
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
val <caret>count = 1 + list.count { it.isNotBlank() }
return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
var count = 0
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'count{}'"
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
val <caret>count = list.count { it.isNotBlank() }
return count
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>): Int {
var count = 0
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
class X {
operator fun iterator(): Iterator<String>{
return emptyList<String>().iterator()
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String?>, target: MutableList<String>) {
<caret>for (s in list) {
val length = s?.length ?: break
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) {
<caret>for (s in list) {
val length = if (s.isNotEmpty()) s.length else break
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
// IS_APPLICABLE_2: false
fun foo(list: List<String>, target: MutableList<String>) {
<caret>for (s in list) {
val length = if (s.isNotEmpty()) s.length else continue
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? {
<caret>for ((index, s) in list.withIndex()) {
if (s.length > index) {
@@ -1,5 +1,6 @@
// 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
.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
// INTENTION_TEXT: "Replace with 'filterIndexed{}.firstOrNull()'"
// INTENTION_TEXT_2: "Replace with 'asSequence().filterIndexed{}.firstOrNull()'"
fun foo(list: List<String>): String? {
var i = 0
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// 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
.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
// INTENTION_TEXT: "Replace with '...flatMap{}.filterNot{}.mapTo(){}'"
// INTENTION_TEXT_2: "Replace with 'asSequence()...flatMap{}.filterNot{}.mapTo(){}'"
fun foo(list: List<String>, target: MutableCollection<String>) {
var i = 0
<caret>for (s in list) {
@@ -1,5 +1,6 @@
// WITH_RUNTIME
// INTENTION_TEXT: "Replace with '...flatMap{}.filterNot{}.mapTo(){}'"
// INTENTION_TEXT_2: "Replace with 'asSequence()...flatMap{}.filterNot{}.mapTo(){}'"
fun foo(list: List<String>, target: MutableCollection<String>) {
<caret>list
.filterIndexed { i, s -> i % 10 != 0 }

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