From 920c20069321198b4ad893a7e94c35245e8cc721 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Thu, 27 Sep 2018 10:40:44 +0300 Subject: [PATCH] Call chain --> Sequence: introduce "call chain length" parameter #KT-26571 Fixed --- idea/src/META-INF/plugin.xml | 4 +- idea/src/META-INF/plugin.xml.173 | 4 +- idea/src/META-INF/plugin.xml.181 | 4 +- idea/src/META-INF/plugin.xml.183 | 4 +- idea/src/META-INF/plugin.xml.as31 | 4 +- idea/src/META-INF/plugin.xml.as32 | 4 +- idea/src/META-INF/plugin.xml.as33 | 4 +- .../ConvertCallChainIntoSequenceInspection.kt | 57 ++++++++++++++++--- .../convertCallChainIntoSequence/simple.kt | 4 +- .../simple.kt.after | 4 +- .../convertCallChainIntoSequence/simple2.kt | 3 + .../simple2.kt.after | 3 + 12 files changed, 76 insertions(+), 23 deletions(-) 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