diff --git a/idea/resources/inspectionDescriptions/ConvertCallChainIntoSequence.html b/idea/resources/inspectionDescriptions/ConvertCallChainIntoSequence.html
new file mode 100644
index 00000000000..ecee8462150
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/ConvertCallChainIntoSequence.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports call chain on collection should be converted into Sequence.
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 8a852cfa69b..538118ae80e 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2967,6 +2967,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.173 b/idea/src/META-INF/plugin.xml.173
index 694fcda736b..5ed173c780d 100644
--- a/idea/src/META-INF/plugin.xml.173
+++ b/idea/src/META-INF/plugin.xml.173
@@ -2966,6 +2966,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.181 b/idea/src/META-INF/plugin.xml.181
index c44273b2ddc..b4c23f5ce71 100644
--- a/idea/src/META-INF/plugin.xml.181
+++ b/idea/src/META-INF/plugin.xml.181
@@ -2966,6 +2966,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.as31 b/idea/src/META-INF/plugin.xml.as31
index 3f778c6c6f5..ce31b9a9528 100644
--- a/idea/src/META-INF/plugin.xml.as31
+++ b/idea/src/META-INF/plugin.xml.as31
@@ -2966,6 +2966,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.as32 b/idea/src/META-INF/plugin.xml.as32
index e02aae45ddf..811598e069f 100644
--- a/idea/src/META-INF/plugin.xml.as32
+++ b/idea/src/META-INF/plugin.xml.as32
@@ -2966,6 +2966,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/META-INF/plugin.xml.as33 b/idea/src/META-INF/plugin.xml.as33
index 10ac958aa35..d709672fd4e 100644
--- a/idea/src/META-INF/plugin.xml.as33
+++ b/idea/src/META-INF/plugin.xml.as33
@@ -2967,6 +2967,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
language="kotlin"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt
new file mode 100644
index 00000000000..d8ac79de19e
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
+ * that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.inspections.collections
+
+import com.intellij.codeInspection.LocalQuickFix
+import com.intellij.codeInspection.ProblemDescriptor
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiWhiteSpace
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.idea.core.replaced
+import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
+import org.jetbrains.kotlin.idea.intentions.callExpression
+import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor
+import org.jetbrains.kotlin.idea.util.CommentSaver
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
+import org.jetbrains.kotlin.psi.psiUtil.siblings
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
+
+class ConvertCallChainIntoSequenceInspection : AbstractKotlinInspection() {
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
+ qualifiedExpressionVisitor(fun(expression) {
+ val (targetQualified, targetCall) = expression.findTarget() ?: return
+ val rangeInElement = targetCall.calleeExpression?.textRange?.shiftRight(-targetQualified.startOffset) ?: return
+ holder.registerProblem(
+ holder.manager.createProblemDescriptor(
+ targetQualified,
+ rangeInElement,
+ "Call chain on collection should be converted into 'Sequence'",
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+ isOnTheFly,
+ ConvertCallChainIntoSequenceFix()
+ )
+ )
+ })
+}
+
+private class ConvertCallChainIntoSequenceFix : LocalQuickFix {
+ override fun getName() = "Convert call chain into 'Sequence'"
+
+ override fun getFamilyName() = name
+
+ override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
+ val expression = descriptor.psiElement as? KtQualifiedExpression ?: return
+ val calls = expression.collectCallExpression().reversed()
+ val firstCall = calls.firstOrNull() ?: return
+ val lastCall = calls.lastOrNull() ?: return
+ val first = firstCall.parent as? KtQualifiedExpression ?: return
+ val last = lastCall.parent as? KtQualifiedExpression ?: return
+ val next = last.parent as? KtQualifiedExpression
+ val nextType = next?.getCallableDescriptor()?.returnType
+
+ val psiFactory = KtPsiFactory(expression)
+ val dot = buildString {
+ if (first.receiverExpression.siblings().filterIsInstance().any { it.textContains('\n') }) append("\n")
+ if (first is KtSafeQualifiedExpression) append("?")
+ append(".")
+ }
+
+ val firstCommentSaver = CommentSaver(first)
+ val firstReplaced = first.replaced(
+ psiFactory.buildExpression {
+ appendExpression(first.receiverExpression)
+ appendFixedText(dot)
+ appendExpression(psiFactory.createExpression("asSequence()"))
+ appendFixedText(dot)
+ appendExpression(firstCall)
+ }
+ )
+ firstCommentSaver.restore(firstReplaced)
+
+ val nextDescriptor = next?.getCallableDescriptor()
+ if (nextDescriptor == null
+ || !nextDescriptor.fqNameSafe.asString().startsWith("kotlin.sequences.")
+ || nextDescriptor.returnType != nextType
+ ) {
+ val lastCommentSaver = CommentSaver(last)
+ val lastReplaced = last.replace(
+ psiFactory.buildExpression {
+ appendExpression(last)
+ appendFixedText(dot)
+ appendExpression(psiFactory.createExpression("toList()"))
+ }
+ )
+ lastCommentSaver.restore(lastReplaced)
+ }
+ }
+}
+
+private fun KtQualifiedExpression.findTarget(): Pair? {
+ if (parent is KtQualifiedExpression) return null
+
+ val calls = collectCallExpression()
+ if (calls.isEmpty()) return null
+
+ val qualified = calls.first().parent as? KtQualifiedExpression ?: return null
+ val fqName = qualified.getCallableDescriptor()?.returnType?.constructor?.declarationDescriptor?.fqNameSafe
+ if (fqName != KotlinBuiltIns.FQ_NAMES.list) return null
+ return qualified to calls.last()
+}
+
+private fun KtQualifiedExpression.collectCallExpression(): List {
+ val calls = mutableListOf()
+
+ fun collect(qualified: KtQualifiedExpression) {
+ val call = qualified.callExpression ?: return
+ calls.add(call)
+ val receiver = qualified.receiverExpression
+ if (receiver is KtQualifiedExpression) collect(receiver)
+ }
+ collect(this)
+
+ if (calls.size < 2) return emptyList()
+
+ val transformationCalls = calls
+ .asSequence()
+ .dropWhile { !it.isTransformation() }
+ .takeWhile { it.isTransformation() && !it.hasReturn() }
+ .toList()
+ if (transformationCalls.size < 2) return emptyList()
+
+ return transformationCalls
+}
+
+private fun KtCallExpression.hasReturn(): Boolean = valueArguments.any { arg ->
+ arg.anyDescendantOfType { it.labelQualifier == null }
+}
+
+private fun KtCallExpression.isTransformation(): Boolean {
+ val fqName = transformations[calleeExpression?.text] ?: return false
+ return fqName == getCallableDescriptor()?.fqNameSafe
+}
+
+private val transformations = listOf(
+ "chunked",
+ "distinct",
+ "distinctBy",
+ "drop",
+ "dropWhile",
+ "filter",
+ "filterIndexed",
+ "filterIsInstance",
+ "filterNot",
+ "filterNotNull",
+ "map",
+ "mapIndexed",
+ "mapIndexedNotNull",
+ "mapNotNull",
+ "minus",
+ "minusElement",
+ "onEach",
+ "plus",
+ "plusElement",
+ "requireNoNulls",
+ "sorted",
+ "sortedBy",
+ "sortedByDescending",
+ "sortedDescending",
+ "sortedWith",
+ "take",
+ "takeWhile",
+ "windowed",
+ "zipWithNext"
+).associate { it to FqName("kotlin.collections.$it") }
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/.inspection b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/.inspection
new file mode 100644
index 00000000000..4f43651193e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/all.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/all.kt
new file mode 100644
index 00000000000..82621315f0f
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/all.kt
@@ -0,0 +1,35 @@
+// WITH_RUNTIME
+
+fun test(list: List): List, List>> {
+ return list
+ .chunked(1)
+ .distinct()
+ .distinctBy { it }
+ .drop(1)
+ .dropWhile { true }
+ .filter { true }
+ .filterIndexed { index, list -> true }
+ .filterIsInstance()
+ .filterNot { true }
+ .filterNotNull()
+ .map { it }
+ .mapIndexed { index, i -> i }
+ .mapIndexedNotNull { index, i -> i }
+ .mapNotNull { it }
+ .minus(1)
+ .minusElement(1)
+ .onEach {}
+ .plus(1)
+ .plusElement(1)
+ .requireNoNulls()
+ .sorted()
+ .sortedBy { it }
+ .sortedByDescending { it }
+ .sortedDescending()
+ .sortedWith(Comparator { o1, o2 -> 0 })
+ .take(1)
+ .takeWhile { true }
+ .windowed(1, 1, true)
+ .zipWithNext()
+ .zipWithNext { a, b -> a }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/all.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/all.kt.after
new file mode 100644
index 00000000000..fc6aeb1424e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/all.kt.after
@@ -0,0 +1,37 @@
+// WITH_RUNTIME
+
+fun test(list: List): List, List>> {
+ return list
+ .asSequence()
+ .chunked(1)
+ .distinct()
+ .distinctBy { it }
+ .drop(1)
+ .dropWhile { true }
+ .filter { true }
+ .filterIndexed { index, list -> true }
+ .filterIsInstance()
+ .filterNot { true }
+ .filterNotNull()
+ .map { it }
+ .mapIndexed { index, i -> i }
+ .mapIndexedNotNull { index, i -> i }
+ .mapNotNull { it }
+ .minus(1)
+ .minusElement(1)
+ .onEach {}
+ .plus(1)
+ .plusElement(1)
+ .requireNoNulls()
+ .sorted()
+ .sortedBy { it }
+ .sortedByDescending { it }
+ .sortedDescending()
+ .sortedWith(Comparator { o1, o2 -> 0 })
+ .take(1)
+ .takeWhile { true }
+ .windowed(1, 1, true)
+ .zipWithNext()
+ .zipWithNext { a, b -> a }
+ .toList()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment.kt
new file mode 100644
index 00000000000..6aaf9d981af
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment.kt
@@ -0,0 +1,8 @@
+// WITH_RUNTIME
+
+fun test(list: List): Int {
+ return list // comment1
+ .filter { it > 1 } // comment2
+ .map { it * 2 } // comment3
+ .sum() // comment4
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment.kt.after
new file mode 100644
index 00000000000..28cdd42c077
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment.kt.after
@@ -0,0 +1,9 @@
+// WITH_RUNTIME
+
+fun test(list: List): Int {
+ return list // comment1
+ .asSequence()
+ .filter { it > 1 } // comment2
+ .map { it * 2 } // comment3
+ .sum() // comment4
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment2.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment2.kt
new file mode 100644
index 00000000000..26a49549cbe
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment2.kt
@@ -0,0 +1,7 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list // comment1
+ .filter { it > 1 } // comment2
+ .map { it * 2 } // comment3
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment2.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment2.kt.after
new file mode 100644
index 00000000000..039aa386f1c
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment2.kt.after
@@ -0,0 +1,9 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list // comment1
+ .asSequence()
+ .filter { it > 1 } // comment2
+ .map { it * 2 }
+ .toList() // comment3
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain.kt
new file mode 100644
index 00000000000..069532c93e9
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain.kt
@@ -0,0 +1,6 @@
+// PROBLEM: none
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list.filter { it > 1 }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain2.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain2.kt
new file mode 100644
index 00000000000..8e4f63c0a99
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain2.kt
@@ -0,0 +1,6 @@
+// PROBLEM: none
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list.filter { it > 2 }.dropLast(1).filter { it > 2 }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain3.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain3.kt
new file mode 100644
index 00000000000..6c85c7e8863
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain3.kt
@@ -0,0 +1,11 @@
+// PROBLEM: none
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .reversed()
+ .map { it + 1 }
+ .map { it + 1 }
+ .dropLast(1)
+ .takeLast(2)
+}
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable.kt
new file mode 100644
index 00000000000..1fc731f55c8
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable.kt
@@ -0,0 +1,7 @@
+// WITH_RUNTIME
+
+fun test(list: List?): List? {
+ return list
+ ?.filter { it > 1 }
+ ?.map { it * 2 }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable.kt.after
new file mode 100644
index 00000000000..9110c8ba000
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable.kt.after
@@ -0,0 +1,9 @@
+// WITH_RUNTIME
+
+fun test(list: List?): List? {
+ return list
+ ?.asSequence()
+ ?.filter { it > 1 }
+ ?.map { it * 2 }
+ ?.toList()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable2.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable2.kt
new file mode 100644
index 00000000000..723877c5b30
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable2.kt
@@ -0,0 +1,5 @@
+// WITH_RUNTIME
+
+fun test(list: List?): List? {
+ return list?.filter { it > 1 }!!.filter { it > 2 }.filter { it > 3 }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable2.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable2.kt.after
new file mode 100644
index 00000000000..79d87da12c6
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable2.kt.after
@@ -0,0 +1,5 @@
+// WITH_RUNTIME
+
+fun test(list: List?): List? {
+ return list?.filter { it > 1 }!!.asSequence().filter { it > 2 }.filter { it > 3 }.toList()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/return.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/return.kt
new file mode 100644
index 00000000000..fff6dbbd7df
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/return.kt
@@ -0,0 +1,11 @@
+// PROBLEM: none
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .filter { it > 1 }
+ .mapNotNull {
+ if (it == 2) return emptyList()
+ it * 2
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/returnAtLabels.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/returnAtLabels.kt
new file mode 100644
index 00000000000..d6141e2b2f4
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/returnAtLabels.kt
@@ -0,0 +1,10 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .filter { it > 1 }
+ .mapNotNull {
+ if (it == 2) return@mapNotNull null
+ it * 2
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/returnAtLabels.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/returnAtLabels.kt.after
new file mode 100644
index 00000000000..e1462640ce1
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/returnAtLabels.kt.after
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .asSequence()
+ .filter { it > 1 }
+ .mapNotNull {
+ if (it == 2) return@mapNotNull null
+ it * 2
+ }
+ .toList()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt
new file mode 100644
index 00000000000..1c3e5699f50
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt
@@ -0,0 +1,5 @@
+// WITH_RUNTIME
+
+fun test(): List {
+ return listOf(1, 2, 3).filter { it > 1 }.map { it * 2 }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt.after
new file mode 100644
index 00000000000..5024242557e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt.after
@@ -0,0 +1,5 @@
+// WITH_RUNTIME
+
+fun test(): List {
+ return listOf(1, 2, 3).asSequence().filter { it > 1 }.map { it * 2 }.toList()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt
new file mode 100644
index 00000000000..31504495b28
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt
@@ -0,0 +1,7 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .filter { it > 1 }
+ .map { it * 2 }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt.after
new file mode 100644
index 00000000000..912ad5b95ea
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt.after
@@ -0,0 +1,9 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .asSequence()
+ .filter { it > 1 }
+ .map { it * 2 }
+ .toList()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple3.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple3.kt
new file mode 100644
index 00000000000..5c78c12f695
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple3.kt
@@ -0,0 +1,10 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .reversed()
+ .map { it + 1 }
+ .map { it + 1 }
+ .dropLast(1)
+ .takeLast(2)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple3.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple3.kt.after
new file mode 100644
index 00000000000..11be64e287a
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple3.kt.after
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+
+fun test(list: List): List {
+ return list
+ .reversed()
+ .asSequence()
+ .map { it + 1 }
+ .map { it + 1 }
+ .toList()
+ .dropLast(1)
+ .takeLast(2)
+}
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple4.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple4.kt
new file mode 100644
index 00000000000..0e17f9cb386
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple4.kt
@@ -0,0 +1,11 @@
+// WITH_RUNTIME
+
+fun test(foo: Foo): List {
+ return foo.getList()
+ .filter { it > 1 }
+ .map { it * 2 }
+}
+
+class Foo {
+ fun getList(): List = listOf(1, 2, 3)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple4.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple4.kt.after
new file mode 100644
index 00000000000..aca43ad97b0
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple4.kt.after
@@ -0,0 +1,13 @@
+// WITH_RUNTIME
+
+fun test(foo: Foo): List {
+ return foo.getList()
+ .asSequence()
+ .filter { it > 1 }
+ .map { it * 2 }
+ .toList()
+}
+
+class Foo {
+ fun getList(): List = listOf(1, 2, 3)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination.kt
new file mode 100644
index 00000000000..1bfa7cc3b87
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination.kt
@@ -0,0 +1,8 @@
+// WITH_RUNTIME
+
+fun test(): Int {
+ return listOf(1, 2, 3)
+ .filter { it > 1 }
+ .map { it * 2 }
+ .sum()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination.kt.after
new file mode 100644
index 00000000000..d06c7b7a9fa
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination.kt.after
@@ -0,0 +1,9 @@
+// WITH_RUNTIME
+
+fun test(): Int {
+ return listOf(1, 2, 3)
+ .asSequence()
+ .filter { it > 1 }
+ .map { it * 2 }
+ .sum()
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination2.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination2.kt
new file mode 100644
index 00000000000..29780cae6b9
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination2.kt
@@ -0,0 +1,8 @@
+// WITH_RUNTIME
+
+fun test(): Int {
+ return listOf(1, 2, 3)
+ .filter { it > 1 }
+ .map { it * 2 }
+ .binarySearch(4)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination2.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination2.kt.after
new file mode 100644
index 00000000000..3fa8a1a757e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination2.kt.after
@@ -0,0 +1,10 @@
+// WITH_RUNTIME
+
+fun test(): Int {
+ return listOf(1, 2, 3)
+ .asSequence()
+ .filter { it > 1 }
+ .map { it * 2 }
+ .toList()
+ .binarySearch(4)
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination3.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination3.kt
new file mode 100644
index 00000000000..db506dac515
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination3.kt
@@ -0,0 +1,10 @@
+// WITH_RUNTIME
+
+fun test(): Int {
+ return listOf(1, 2, 3)
+ .filter { it > 1 }
+ .map { it * 2 }
+ .let {
+ it.binarySearch(1)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination3.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination3.kt.after
new file mode 100644
index 00000000000..2634c754f10
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination3.kt.after
@@ -0,0 +1,12 @@
+// WITH_RUNTIME
+
+fun test(): Int {
+ return listOf(1, 2, 3)
+ .asSequence()
+ .filter { it > 1 }
+ .map { it * 2 }
+ .toList()
+ .let {
+ it.binarySearch(1)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination4.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination4.kt
new file mode 100644
index 00000000000..7286d27456e
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination4.kt
@@ -0,0 +1,8 @@
+// WITH_RUNTIME
+
+fun test(list: List>): List {
+ return list
+ .filter { it.count() > 2 }
+ .map { it + it }
+ .flatMap { it + it }
+}
\ No newline at end of file
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination4.kt.after b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination4.kt.after
new file mode 100644
index 00000000000..d722f941e11
--- /dev/null
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination4.kt.after
@@ -0,0 +1,10 @@
+// WITH_RUNTIME
+
+fun test(list: List>): List {
+ return list
+ .asSequence()
+ .filter { it.count() > 2 }
+ .map { it + it }
+ .toList()
+ .flatMap { it + it }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
index e428835171f..c0644e8e21e 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java
@@ -492,6 +492,109 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/collections"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
+ @TestMetadata("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ConvertCallChainIntoSequence extends AbstractLocalInspectionTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
+ }
+
+ @TestMetadata("all.kt")
+ public void testAll() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/all.kt");
+ }
+
+ public void testAllFilesPresentInConvertCallChainIntoSequence() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("comment.kt")
+ public void testComment() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment.kt");
+ }
+
+ @TestMetadata("comment2.kt")
+ public void testComment2() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/comment2.kt");
+ }
+
+ @TestMetadata("noTargetCallChain.kt")
+ public void testNoTargetCallChain() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain.kt");
+ }
+
+ @TestMetadata("noTargetCallChain2.kt")
+ public void testNoTargetCallChain2() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain2.kt");
+ }
+
+ @TestMetadata("noTargetCallChain3.kt")
+ public void testNoTargetCallChain3() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/noTargetCallChain3.kt");
+ }
+
+ @TestMetadata("nullable.kt")
+ public void testNullable() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable.kt");
+ }
+
+ @TestMetadata("nullable2.kt")
+ public void testNullable2() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/nullable2.kt");
+ }
+
+ @TestMetadata("return.kt")
+ public void testReturn() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/return.kt");
+ }
+
+ @TestMetadata("returnAtLabels.kt")
+ public void testReturnAtLabels() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/returnAtLabels.kt");
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt");
+ }
+
+ @TestMetadata("simple2.kt")
+ public void testSimple2() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt");
+ }
+
+ @TestMetadata("simple3.kt")
+ public void testSimple3() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple3.kt");
+ }
+
+ @TestMetadata("simple4.kt")
+ public void testSimple4() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple4.kt");
+ }
+
+ @TestMetadata("termination.kt")
+ public void testTermination() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination.kt");
+ }
+
+ @TestMetadata("termination2.kt")
+ public void testTermination2() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination2.kt");
+ }
+
+ @TestMetadata("termination3.kt")
+ public void testTermination3() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination3.kt");
+ }
+
+ @TestMetadata("termination4.kt")
+ public void testTermination4() throws Exception {
+ runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/termination4.kt");
+ }
+ }
+
@TestMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)