Call chain into sequence: fix false negative on Iterable
#KT-26650 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
2e5ee242c7
commit
9a725b99b2
+1
-9
@@ -154,7 +154,7 @@ private fun KtQualifiedExpression.findCallChain(): CallChain? {
|
||||
val receiverType =
|
||||
(lastCall.getQualifiedExpressionForSelector())?.receiverExpression?.getResolvedCall(context)?.resultingDescriptor?.returnType
|
||||
?: lastCall.implicitReceiver(context)?.type
|
||||
if (receiverType?.isCollection() != true) return null
|
||||
if (receiverType?.isMap(DefaultBuiltIns.Instance) == true) return null
|
||||
|
||||
val firstCall = calls.first()
|
||||
val qualified = firstCall.getQualifiedExpressionForSelector() ?: firstCall.getQualifiedExpressionForReceiver() ?: return null
|
||||
@@ -193,14 +193,6 @@ private fun KtExpression.implicitReceiver(context: BindingContext): ImplicitRece
|
||||
return getResolvedCall(context)?.getImplicitReceiverValue()
|
||||
}
|
||||
|
||||
private fun KotlinType.isCollection(): Boolean {
|
||||
val classDescriptor = constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
val className = classDescriptor.name.asString()
|
||||
val builtIns = DefaultBuiltIns.Instance
|
||||
return className.endsWith("List") && classDescriptor.isSubclassOf(builtIns.list)
|
||||
|| className.endsWith("Set") && classDescriptor.isSubclassOf(builtIns.set)
|
||||
}
|
||||
|
||||
private fun KtCallExpression.hasReturn(): Boolean = valueArguments.any { arg ->
|
||||
arg.anyDescendantOfType<KtReturnExpression> { it.labelQualifier == null }
|
||||
}
|
||||
|
||||
@@ -16,14 +16,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.inspections.collections
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
fun KotlinType.isFunctionOfAnyKind() = constructor.declarationDescriptor?.getFunctionalClassKind() != null
|
||||
|
||||
fun KotlinType?.isMap(builtIns: KotlinBuiltIns): Boolean {
|
||||
val classDescriptor = this?.constructor?.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
return classDescriptor.name.asString().endsWith("Map") && classDescriptor.isSubclassOf(builtIns.map)
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.hasLastFunctionalParameterWithResult(context: BindingContext, predicate: (KotlinType) -> Boolean): Boolean {
|
||||
val lastParameter = resultingDescriptor.valueParameters.lastOrNull() ?: return false
|
||||
val lastArgument = valueArguments[lastParameter]?.arguments?.singleOrNull() ?: return false
|
||||
|
||||
+1
-6
@@ -82,9 +82,4 @@ class SimplifiableCallChainInspection : AbstractCallChainChecker() {
|
||||
Conversion("kotlin.collections.listOf", "kotlin.collections.filterNotNull", "listOfNotNull")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType?.isMap(builtIns: KotlinBuiltIns): Boolean {
|
||||
val classDescriptor = this?.constructor?.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
return classDescriptor.name.asString().endsWith("Map") && classDescriptor.isSubclassOf(builtIns.map)
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun test(i: Iterable<Int>): List<Int> {
|
||||
return i.<caret>filter { it > 1 }.map { it * 2 }
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun test(i: Iterable<Int>): List<Int> {
|
||||
return i.asSequence().filter { it > 1 }.map { it * 2 }.toList()
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
class A<T>(private val list: List<T>) : Iterable<T> {
|
||||
override fun iterator(): Iterator<T> = list.iterator()
|
||||
}
|
||||
|
||||
fun test(i: A<Int>): List<Int> {
|
||||
return i.<caret>filter { it > 1 }.map { it * 2 }
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
class A<T>(private val list: List<T>) : Iterable<T> {
|
||||
override fun iterator(): Iterator<T> = list.iterator()
|
||||
}
|
||||
|
||||
fun test(i: A<Int>): List<Int> {
|
||||
return i.asSequence().filter { it > 1 }.map { it * 2 }.toList()
|
||||
}
|
||||
+10
@@ -574,6 +574,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/implicitReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("iterable.kt")
|
||||
public void testIterable() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/iterable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("iterable2.kt")
|
||||
public void testIterable2() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/iterable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("mutableList.kt")
|
||||
public void testMutableList() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/convertCallChainIntoSequence/mutableList.kt");
|
||||
|
||||
Reference in New Issue
Block a user