UselessCallOnCollectionInspection: fix false positive when lambda last statement is function call that returns generic type

#KT-38267 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-04-24 14:58:22 +09:00
committed by igoriakovlev
parent 3c8ef5749f
commit 148f49d54a
5 changed files with 60 additions and 1 deletions
@@ -27,12 +27,14 @@ import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor
import org.jetbrains.kotlin.resolve.calls.model.ReceiverKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaAtom
import org.jetbrains.kotlin.resolve.calls.model.unwrap
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.tower.SubKotlinCallArgumentImpl
import org.jetbrains.kotlin.resolve.calls.tower.receiverValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
@@ -78,7 +80,13 @@ fun ResolvedCall<*>.hasLastFunctionalParameterWithResult(context: BindingContext
// TODO: looks like hack
resolvedCallAtom.subResolvedAtoms?.firstOrNull { it is ResolvedLambdaAtom }.safeAs<ResolvedLambdaAtom>()?.let { lambdaAtom ->
return lambdaAtom.unwrap().resultArgumentsInfo!!.nonErrorArguments.filterIsInstance<ReceiverKotlinCallArgument>().all {
val type = it.receiverValue?.type ?: return@all false
val type = it.receiverValue?.type?.let { type ->
if (type.constructor is TypeVariableTypeConstructor) {
it.safeAs<SubKotlinCallArgumentImpl>()?.valueArgument?.getArgumentExpression()?.getType(context) ?: type
} else {
type
}
} ?: return@all false
predicate(type)
}
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// FIX: Change call to 'map'
fun test(): List<String> {
return listOf(1, 2, 3).<caret>mapNotNull { i ->
foo {
bar(i)
}
}
}
fun <T> foo(f: () -> T): T = f()
fun bar(i: Int): String = ""
@@ -0,0 +1,14 @@
// WITH_RUNTIME
// FIX: Change call to 'map'
fun test(): List<String> {
return listOf(1, 2, 3).map { i ->
foo {
bar(i)
}
}
}
fun <T> foo(f: () -> T): T = f()
fun bar(i: Int): String = ""
@@ -0,0 +1,13 @@
// PROBLEM: none
// WITH_RUNTIME
fun test(): List<String> {
return listOf(1, 2, 3).<caret>mapNotNull { i ->
foo {
bar(i)
}
}
}
fun <T> foo(f: () -> T): T = f()
fun bar(i: Int): String? = null
@@ -2058,11 +2058,21 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/collections/uselessCallOnCollection/MapNotNullWithLambda4.kt");
}
@TestMetadata("MapNotNullWithLambda5.kt")
public void testMapNotNullWithLambda5() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/uselessCallOnCollection/MapNotNullWithLambda5.kt");
}
@TestMetadata("MapNotNullWithLambdaFake.kt")
public void testMapNotNullWithLambdaFake() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/uselessCallOnCollection/MapNotNullWithLambdaFake.kt");
}
@TestMetadata("MapNotNullWithLambdaFake2.kt")
public void testMapNotNullWithLambdaFake2() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/uselessCallOnCollection/MapNotNullWithLambdaFake2.kt");
}
@TestMetadata("MapNotNullWithReference.kt")
public void testMapNotNullWithReference() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/uselessCallOnCollection/MapNotNullWithReference.kt");