diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt index fefcbc5ab77..823bf98a673 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt @@ -21,16 +21,14 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiElementVisitor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.isAnyEquals import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.types.typeUtil.isBoolean -import org.jetbrains.kotlin.types.typeUtil.isNullableAny +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver class RecursiveEqualsCallInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { @@ -38,18 +36,17 @@ class RecursiveEqualsCallInspection : AbstractKotlinInspection() { override fun visitBinaryExpression(expr: KtBinaryExpression) { super.visitBinaryExpression(expr) - if (expr.operationToken != KtTokens.EQEQ) return - val classDescriptor = expr.containingClass()?.descriptor ?: return val context = expr.analyze(BodyResolveMode.PARTIAL) - if (classDescriptor != expr.getResolvedCall(context)?.dispatchReceiver?.type?.constructor?.declarationDescriptor) return + val resolvedCall = expr.getResolvedCall(context) + val dispatchReceiver = resolvedCall?.dispatchReceiver as? ThisClassReceiver ?: return + val calledFunctionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor + if (calledFunctionDescriptor?.isAnyEquals() != true) return - val functionDescriptor = expr.getNonStrictParentOfType()?.descriptor as? FunctionDescriptor ?: return - if (functionDescriptor.name.asString() != "equals" || - !DescriptorUtils.isOverride(functionDescriptor) || - functionDescriptor.valueParameters.singleOrNull()?.type?.isNullableAny() == false || - functionDescriptor.returnType?.isBoolean() == false) return + val containingFunctionDescriptor = expr.getNonStrictParentOfType()?.descriptor as? FunctionDescriptor + if (calledFunctionDescriptor != containingFunctionDescriptor) return + if (dispatchReceiver.classDescriptor != containingFunctionDescriptor.containingDeclaration) return holder.registerProblem(expr, "Recursive equals call", diff --git a/idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFake.kt b/idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFake.kt new file mode 100644 index 00000000000..5be4415014e --- /dev/null +++ b/idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFake.kt @@ -0,0 +1,9 @@ +// PROBLEM: none + +class Test { + override fun equals(other: Any?): Boolean { + val another = Test() + if (another == other) return true + return false + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 2742b1d97fc..8601b5109d3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1513,6 +1513,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/recursiveEqualsCall/recursive.kt"); doTest(fileName); } + + @TestMetadata("recursiveFake.kt") + public void testRecursiveFake() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFake.kt"); + doTest(fileName); + } } @TestMetadata("idea/testData/inspectionsLocal/redundantExplicitType")