Simplifiable call inspection: add filter -> filterIsInstance replacement
#KT-30501 Fixed
This commit is contained in:
+26
-18
@@ -26,13 +26,13 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
||||
val calleeExpression = callExpression.calleeExpression ?: return
|
||||
val (conversion, resolvedCall) = callExpression.findConversionAndResolvedCall() ?: return
|
||||
if (!conversion.callChecker(resolvedCall)) return
|
||||
val conversionSuffix = conversion.analyzer(callExpression) ?: return
|
||||
val replacement = conversion.analyzer(callExpression) ?: return
|
||||
|
||||
holder.registerProblem(
|
||||
calleeExpression,
|
||||
"${conversion.fqName.shortName()} call could be simplified to ${conversion.replacement}$conversionSuffix",
|
||||
"${conversion.fqName.shortName()} call could be simplified to $replacement",
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||
SimplifyCallFix(conversion, conversionSuffix)
|
||||
SimplifyCallFix(conversion, replacement)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -50,7 +50,6 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
||||
|
||||
private data class Conversion(
|
||||
val callFqName: String,
|
||||
val replacement: String,
|
||||
val analyzer: (KtCallExpression) -> String?,
|
||||
val callChecker: (ResolvedCall<*>) -> Boolean = { true }
|
||||
) {
|
||||
@@ -79,25 +78,34 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
||||
this is KtConstantExpression && this.node.elementType == KtNodeTypes.NULL
|
||||
|
||||
private val conversions = listOf(
|
||||
Conversion("kotlin.collections.flatMap", "flatten", fun(callExpression: KtCallExpression): String? {
|
||||
Conversion("kotlin.collections.flatMap", fun(callExpression: KtCallExpression): String? {
|
||||
val lambdaExpression = callExpression.singleLambdaExpression() ?: return null
|
||||
val reference = lambdaExpression.singleStatement() ?: return null
|
||||
val lambdaParameterName = lambdaExpression.singleLambdaParameterName() ?: return null
|
||||
if (!reference.isNameReferenceTo(lambdaParameterName)) return null
|
||||
return "()"
|
||||
return "flatten()"
|
||||
}),
|
||||
|
||||
Conversion("kotlin.collections.filter", "filterNotNull", analyzer = fun(callExpression: KtCallExpression): String? {
|
||||
Conversion("kotlin.collections.filter", analyzer = fun(callExpression: KtCallExpression): String? {
|
||||
val lambdaExpression = callExpression.singleLambdaExpression() ?: return null
|
||||
val statement = lambdaExpression.singleStatement() as? KtBinaryExpression ?: return null
|
||||
val lambdaParameterName = lambdaExpression.singleLambdaParameterName() ?: return null
|
||||
if (statement.operationToken != KtTokens.EXCLEQ && statement.operationToken != KtTokens.EXCLEQEQEQ) return null
|
||||
val left = statement.left ?: return null
|
||||
val right = statement.right ?: return null
|
||||
if (left.isNameReferenceTo(lambdaParameterName) && right.isNull()) {
|
||||
return "()"
|
||||
} else if (right.isNameReferenceTo(lambdaParameterName) && left.isNull()) {
|
||||
return "()"
|
||||
when (val statement = lambdaExpression.singleStatement() ?: return null) {
|
||||
is KtBinaryExpression -> {
|
||||
if (statement.operationToken != KtTokens.EXCLEQ && statement.operationToken != KtTokens.EXCLEQEQEQ) return null
|
||||
val left = statement.left ?: return null
|
||||
val right = statement.right ?: return null
|
||||
if (left.isNameReferenceTo(lambdaParameterName) && right.isNull()) {
|
||||
return "filterNotNull()"
|
||||
} else if (right.isNameReferenceTo(lambdaParameterName) && left.isNull()) {
|
||||
return "filterNotNull()"
|
||||
}
|
||||
}
|
||||
is KtIsExpression -> {
|
||||
if (statement.isNegated) return null
|
||||
if (!statement.leftHandSide.isNameReferenceTo(lambdaParameterName)) return null
|
||||
val rightTypeReference = statement.typeReference ?: return null
|
||||
return "filterIsInstance<${rightTypeReference.text}>()"
|
||||
}
|
||||
}
|
||||
return null
|
||||
}, callChecker = fun(resolvedCall: ResolvedCall<*>): Boolean {
|
||||
@@ -107,14 +115,14 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
||||
)
|
||||
}
|
||||
|
||||
private class SimplifyCallFix(val conversion: Conversion, val conversionSuffix: String) : LocalQuickFix {
|
||||
override fun getName() = "Convert '${conversion.fqName.shortName()}' call to '${conversion.replacement}$conversionSuffix'"
|
||||
private class SimplifyCallFix(val conversion: Conversion, val replacement: String) : LocalQuickFix {
|
||||
override fun getName() = "Convert '${conversion.fqName.shortName()}' call to '$replacement'"
|
||||
|
||||
override fun getFamilyName() = name
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val callExpression = descriptor.psiElement.parent as? KtCallExpression ?: return
|
||||
callExpression.replace(KtPsiFactory(callExpression).createExpression("${conversion.replacement}$conversionSuffix"))
|
||||
callExpression.replace(KtPsiFactory(callExpression).createExpression(replacement))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<Any>) {
|
||||
list.<caret>filter { it is String }
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test(list: List<Any>) {
|
||||
list.filterIsInstance<String>()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
// PROBLEM: none
|
||||
fun test(list: List<Any>) {
|
||||
list.<caret>filter { it !is String }
|
||||
}
|
||||
+10
@@ -1108,6 +1108,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/explicitLambdaParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("filterIsInstanceSimple.kt")
|
||||
public void testFilterIsInstanceSimple() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsInstanceSimple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("filterIsNotInstance.kt")
|
||||
public void testFilterIsNotInstance() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsNotInstance.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("filterNotNullBrackets.kt")
|
||||
public void testFilterNotNullBrackets() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterNotNullBrackets.kt");
|
||||
|
||||
Reference in New Issue
Block a user