From 416d33fc92817963806a783fbf453aa5f9b9baf7 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Mon, 10 Sep 2018 14:02:43 +0300 Subject: [PATCH] Refactoring: extract KtCallExpression.isCall(FqName) function --- .../collections/AbstractCallChainChecker.kt | 12 ++++-------- .../ConvertCallChainIntoSequenceInspection.kt | 6 +++--- .../ConvertFlatMapToFlattenInspection.kt | 4 +--- .../inspections/collections/FunctionUtils.kt | 17 +++++++++++++++++ 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/AbstractCallChainChecker.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/AbstractCallChainChecker.kt index ed8aafbf95f..da97c79fba2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/AbstractCallChainChecker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/AbstractCallChainChecker.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.inspections.collections import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtQualifiedExpression @@ -36,9 +37,7 @@ abstract class AbstractCallChainChecker : AbstractKotlinInspection() { val context = expression.analyze() val firstResolvedCall = firstExpression.getResolvedCall(context) ?: return null - val conversion = actualConversions.firstOrNull { - firstResolvedCall.resultingDescriptor.fqNameOrNull()?.asString() == it.firstFqName - } ?: return null + val conversion = actualConversions.firstOrNull { firstResolvedCall.isCalling(FqName(it.firstFqName)) } ?: return null val secondResolvedCall = expression.getResolvedCall(context) ?: return null if (!additionalCallCheck(conversion, firstResolvedCall, secondResolvedCall, context)) return null @@ -47,8 +46,7 @@ abstract class AbstractCallChainChecker : AbstractKotlinInspection() { val lambdaArgument = firstCallExpression.lambdaArguments.firstOrNull() if (lambdaArgument?.anyDescendantOfType() == true) return null - val secondResultingDescriptor = secondResolvedCall.resultingDescriptor - if (secondResultingDescriptor.fqNameOrNull()?.asString() != conversion.secondFqName) return null + if (!secondResolvedCall.isCalling(FqName(conversion.secondFqName))) return null if (secondResolvedCall.valueArguments.any { (parameter, resolvedArgument) -> parameter.type.isFunctionOfAnyKind() && resolvedArgument !is DefaultValueArgument @@ -84,8 +82,6 @@ abstract class AbstractCallChainChecker : AbstractKotlinInspection() { fun getCallExpression(firstExpression: KtExpression) = (firstExpression as? KtQualifiedExpression)?.selectorExpression as? KtCallExpression - ?: firstExpression as? KtCallExpression - - + ?: firstExpression as? KtCallExpression } } \ No newline at end of file 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 dec965d68a5..e240d618633 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertCallChainIntoSequenceInspection.kt @@ -199,17 +199,17 @@ private fun KtCallExpression.hasReturn(): Boolean = valueArguments.any { arg -> private fun KtCallExpression.isTransformationOrTermination(context: BindingContext): Boolean { val fqName = transformationAndTerminations[calleeExpression?.text] ?: return false - return fqName == getResolvedCall(context)?.resultingDescriptor?.fqNameSafe + return isCalling(fqName, context) } private fun KtCallExpression.isTermination(context: BindingContext): Boolean { val fqName = terminations[calleeExpression?.text] ?: return false - return fqName == getResolvedCall(context)?.resultingDescriptor?.fqNameSafe + return isCalling(fqName, context) } private fun KtCallExpression.isLazyTermination(context: BindingContext): Boolean { val fqName = lazyTerminations[calleeExpression?.text] ?: return false - return fqName == getResolvedCall(context)?.resultingDescriptor?.fqNameSafe + return isCalling(fqName, context) } private val transformations = listOf( diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertFlatMapToFlattenInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertFlatMapToFlattenInspection.kt index e847681fdf5..acc0addeca1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertFlatMapToFlattenInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/ConvertFlatMapToFlattenInspection.kt @@ -23,9 +23,7 @@ class ConvertFlatMapToFlattenInspection : AbstractKotlinInspection() { qualifiedExpressionVisitor(fun(expression) { val callExpression = expression.selectorExpression as? KtCallExpression ?: return val calleeExpression = callExpression.calleeExpression ?: return - if (calleeExpression.text != "flatMap") return - val context = expression.analyze(BodyResolveMode.PARTIAL) - if (FqName("kotlin.collections.flatMap") != callExpression.getResolvedCall(context)?.resultingDescriptor?.fqNameSafe) return + if (!callExpression.isCalling(FqName("kotlin.collections.flatMap"))) return val argument = callExpression.valueArguments.singleOrNull() ?: return val lambdaExpression = (argument as? KtLambdaArgument)?.getLambdaExpression() diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/FunctionUtils.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/FunctionUtils.kt index 58bf0ac744a..441a0112ead 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/collections/FunctionUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/collections/FunctionUtils.kt @@ -18,11 +18,18 @@ package org.jetbrains.kotlin.idea.inspections.collections import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.getFunctionalClassKind +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtCallExpression 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.model.ResolvedCall +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 fun KotlinType.isFunctionOfAnyKind() = constructor.declarationDescriptor?.getFunctionalClassKind() != null @@ -32,6 +39,16 @@ fun KotlinType?.isMap(builtIns: KotlinBuiltIns): Boolean { return classDescriptor.name.asString().endsWith("Map") && classDescriptor.isSubclassOf(builtIns.map) } +fun KtCallExpression.isCalling(fqName: FqName, context: BindingContext = analyze(BodyResolveMode.PARTIAL)): Boolean { + val function = fqName.asString().takeLastWhile { it != '.' } + if (calleeExpression?.text != function) return false + return getResolvedCall(context)?.isCalling(fqName) == true +} + +fun ResolvedCall.isCalling(fqName: FqName): Boolean { + return resultingDescriptor.fqNameSafe == fqName +} + fun ResolvedCall<*>.hasLastFunctionalParameterWithResult(context: BindingContext, predicate: (KotlinType) -> Boolean): Boolean { val lastParameter = resultingDescriptor.valueParameters.lastOrNull() ?: return false val lastArgument = valueArguments[lastParameter]?.arguments?.singleOrNull() ?: return false