Call chain --> Sequence: introduce "call chain length" parameter
#KT-26571 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
a43be4cbe8
commit
920c200693
@@ -2987,11 +2987,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection"
|
||||
displayName="Call chain on collection should be converted into 'Sequence'"
|
||||
displayName="Call chain on collection could be converted into 'Sequence' to increase performance"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
level="INFORMATION"
|
||||
level="INFO"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
|
||||
@@ -2985,11 +2985,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection"
|
||||
displayName="Call chain on collection should be converted into 'Sequence'"
|
||||
displayName="Call chain on collection could be converted into 'Sequence' to increase performance"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
level="INFORMATION"
|
||||
level="INFO"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
|
||||
@@ -2986,11 +2986,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection"
|
||||
displayName="Call chain on collection should be converted into 'Sequence'"
|
||||
displayName="Call chain on collection could be converted into 'Sequence' to increase performance"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
level="INFORMATION"
|
||||
level="INFO"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
|
||||
@@ -2987,11 +2987,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection"
|
||||
displayName="Call chain on collection should be converted into 'Sequence'"
|
||||
displayName="Call chain on collection could be converted into 'Sequence' to increase performance"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
level="INFORMATION"
|
||||
level="INFO"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
|
||||
@@ -2985,11 +2985,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection"
|
||||
displayName="Call chain on collection should be converted into 'Sequence'"
|
||||
displayName="Call chain on collection could be converted into 'Sequence' to increase performance"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
level="INFORMATION"
|
||||
level="INFO"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
|
||||
@@ -2985,11 +2985,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection"
|
||||
displayName="Call chain on collection should be converted into 'Sequence'"
|
||||
displayName="Call chain on collection could be converted into 'Sequence' to increase performance"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
level="INFORMATION"
|
||||
level="INFO"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
|
||||
@@ -2987,11 +2987,11 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.collections.ConvertCallChainIntoSequenceInspection"
|
||||
displayName="Call chain on collection should be converted into 'Sequence'"
|
||||
displayName="Call chain on collection could be converted into 'Sequence' to increase performance"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
level="INFORMATION"
|
||||
level="INFO"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
|
||||
+50
-7
@@ -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<KtQualifiedExpression, KtCallExpression>? {
|
||||
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<KtQualifiedExpression, KtCa
|
||||
if (receiverType?.isCollection() != true) return null
|
||||
|
||||
val qualified = calls.first().getQualifiedExpressionForSelector() ?: return null
|
||||
return qualified to calls.last()
|
||||
return CallChain(qualified, calls.last(), calls.size)
|
||||
}
|
||||
|
||||
private fun KtQualifiedExpression.collectCallExpression(context: BindingContext): List<KtCallExpression> {
|
||||
|
||||
+3
-1
@@ -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<Int> {
|
||||
return listOf(1, 2, 3).<caret>filter { it > 1 }.map { it * 2 }
|
||||
return listOf(1, 2, 3).<caret>filter { it > 1 }.map { it * 2 }.map { it * 3 }.map { it * 4 }.map { it * 5 }
|
||||
}
|
||||
+3
-1
@@ -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<Int> {
|
||||
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()
|
||||
}
|
||||
+3
@@ -1,7 +1,10 @@
|
||||
// HIGHLIGHT: INFORMATION
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun test(list: List<Int>): List<Int> {
|
||||
return list
|
||||
.filter<caret> { it > 1 }
|
||||
.map { it * 2 }
|
||||
.map { it * 3 }
|
||||
.map { it * 4 }
|
||||
}
|
||||
+3
@@ -1,3 +1,4 @@
|
||||
// HIGHLIGHT: INFORMATION
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun test(list: List<Int>): List<Int> {
|
||||
@@ -5,5 +6,7 @@ fun test(list: List<Int>): List<Int> {
|
||||
.asSequence()
|
||||
.filter { it > 1 }
|
||||
.map { it * 2 }
|
||||
.map { it * 3 }
|
||||
.map { it * 4 }
|
||||
.toList()
|
||||
}
|
||||
Reference in New Issue
Block a user