diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 36a66193669..5cecca86a93 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2987,11 +2987,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
/>
diff --git a/idea/src/META-INF/plugin.xml.173 b/idea/src/META-INF/plugin.xml.173
index c5f3a12a417..a86ba7ef641 100644
--- a/idea/src/META-INF/plugin.xml.173
+++ b/idea/src/META-INF/plugin.xml.173
@@ -2985,11 +2985,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
/>
diff --git a/idea/src/META-INF/plugin.xml.181 b/idea/src/META-INF/plugin.xml.181
index 7b3ef30d99a..83d330eb29e 100644
--- a/idea/src/META-INF/plugin.xml.181
+++ b/idea/src/META-INF/plugin.xml.181
@@ -2986,11 +2986,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
/>
diff --git a/idea/src/META-INF/plugin.xml.183 b/idea/src/META-INF/plugin.xml.183
index 590bd56aeda..a2e0c197d45 100644
--- a/idea/src/META-INF/plugin.xml.183
+++ b/idea/src/META-INF/plugin.xml.183
@@ -2987,11 +2987,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
/>
diff --git a/idea/src/META-INF/plugin.xml.as31 b/idea/src/META-INF/plugin.xml.as31
index a6dc1c5f98e..1294f43b022 100644
--- a/idea/src/META-INF/plugin.xml.as31
+++ b/idea/src/META-INF/plugin.xml.as31
@@ -2985,11 +2985,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
/>
diff --git a/idea/src/META-INF/plugin.xml.as32 b/idea/src/META-INF/plugin.xml.as32
index e998f2fe741..9df6bef5460 100644
--- a/idea/src/META-INF/plugin.xml.as32
+++ b/idea/src/META-INF/plugin.xml.as32
@@ -2985,11 +2985,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
/>
diff --git a/idea/src/META-INF/plugin.xml.as33 b/idea/src/META-INF/plugin.xml.as33
index b5f9d144c23..6e68ec36404 100644
--- a/idea/src/META-INF/plugin.xml.as33
+++ b/idea/src/META-INF/plugin.xml.as33
@@ -2987,11 +2987,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
/>
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt
index 8e37f039a5f..0b801625da7 100644
--- a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt
@@ -9,8 +9,12 @@ import com.intellij.codeInspection.LocalQuickFix
import com.intellij.codeInspection.ProblemDescriptor
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.openapi.editor.event.DocumentEvent
+import com.intellij.openapi.editor.event.DocumentListener
import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.LabeledComponent
import com.intellij.psi.PsiWhiteSpace
+import com.intellij.ui.EditorTextField
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
@@ -30,23 +34,56 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
+import java.awt.BorderLayout
+import javax.swing.JPanel
class ConvertCallChainIntoSequenceInspection : AbstractKotlinInspection() {
+
+ private val defaultCallChainLength = 5
+
+ private var callChainLength = defaultCallChainLength
+
+ var callChainLengthText = defaultCallChainLength.toString()
+ set(value) {
+ field = value
+ callChainLength = value.toIntOrNull() ?: defaultCallChainLength
+ }
+
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
+ val (qualified, firstCall, callChainLength) = expression.findCallChain() ?: return
+ val rangeInElement = firstCall.calleeExpression?.textRange?.shiftRight(-qualified.startOffset) ?: return
+ val highlightType = if (callChainLength >= this.callChainLength)
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING
+ else
+ ProblemHighlightType.INFORMATION
holder.registerProblem(
holder.manager.createProblemDescriptor(
- targetQualified,
+ qualified,
rangeInElement,
- "Call chain on collection should be converted into 'Sequence'",
- ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+ "Call chain on collection could be converted into 'Sequence' to increase performance",
+ highlightType,
isOnTheFly,
ConvertCallChainIntoSequenceFix()
)
)
})
+
+ override fun createOptionsPanel() = OptionsPanel(this)
+
+ class OptionsPanel internal constructor(owner: ConvertCallChainIntoSequenceInspection) : JPanel() {
+ init {
+ layout = BorderLayout()
+ val regexField = EditorTextField(owner.callChainLengthText).apply { setOneLineMode(true) }
+ regexField.document.addDocumentListener(object : DocumentListener {
+ override fun documentChanged(e: DocumentEvent) {
+ owner.callChainLengthText = regexField.text
+ }
+ })
+ val labeledComponent = LabeledComponent.create(regexField, "Call chain length to transform:", BorderLayout.WEST)
+ add(labeledComponent, BorderLayout.NORTH)
+ }
+ }
}
private class ConvertCallChainIntoSequenceFix : LocalQuickFix {
@@ -97,7 +134,13 @@ private class ConvertCallChainIntoSequenceFix : LocalQuickFix {
}
}
-private fun KtQualifiedExpression.findTarget(): Pair? {
+private data class CallChain(
+ val qualified: KtQualifiedExpression,
+ val firstCall: KtCallExpression,
+ val callChainLength: Int
+)
+
+private fun KtQualifiedExpression.findCallChain(): CallChain? {
if (parent is KtQualifiedExpression) return null
val context = analyze(BodyResolveMode.PARTIAL)
@@ -109,7 +152,7 @@ private fun KtQualifiedExpression.findTarget(): Pair {
diff --git a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt
index 1c3e5699f50..881cbcaab37 100644
--- a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt
@@ -1,5 +1,7 @@
+// PROBLEM: Call chain on collection could be converted into 'Sequence' to increase performance
+// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
// WITH_RUNTIME
fun test(): List {
- return listOf(1, 2, 3).filter { it > 1 }.map { it * 2 }
+ return listOf(1, 2, 3).filter { it > 1 }.map { it * 2 }.map { it * 3 }.map { it * 4 }.map { it * 5 }
}
\ 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
index 5024242557e..443132163f6 100644
--- a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt.after
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple.kt.after
@@ -1,5 +1,7 @@
+// PROBLEM: Call chain on collection could be converted into 'Sequence' to increase performance
+// HIGHLIGHT: GENERIC_ERROR_OR_WARNING
// WITH_RUNTIME
fun test(): List {
- return listOf(1, 2, 3).asSequence().filter { it > 1 }.map { it * 2 }.toList()
+ return listOf(1, 2, 3).asSequence().filter { it > 1 }.map { it * 2 }.map { it * 3 }.map { it * 4 }.map { it * 5 }.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
index 31504495b28..84447bb341a 100644
--- a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt
@@ -1,7 +1,10 @@
+// HIGHLIGHT: INFORMATION
// WITH_RUNTIME
fun test(list: List): List {
return list
.filter { it > 1 }
.map { it * 2 }
+ .map { it * 3 }
+ .map { it * 4 }
}
\ 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
index 912ad5b95ea..a1c432607ba 100644
--- a/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt.after
+++ b/idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/simple2.kt.after
@@ -1,3 +1,4 @@
+// HIGHLIGHT: INFORMATION
// WITH_RUNTIME
fun test(list: List): List {
@@ -5,5 +6,7 @@ fun test(list: List): List {
.asSequence()
.filter { it > 1 }
.map { it * 2 }
+ .map { it * 3 }
+ .map { it * 4 }
.toList()
}
\ No newline at end of file