diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt index 9a2941e78bf..9d87c53eda3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RecursiveEqualsCallInspection.kt @@ -26,6 +26,7 @@ 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.getNonStrictParentOfType +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver @@ -35,16 +36,19 @@ class RecursiveEqualsCallInspection : AbstractKotlinInspection() { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { return object : KtVisitorVoid() { - private fun KtExpression.isRecursiveEquals(): Boolean { + private fun KtExpression.isRecursiveEquals(argumentExpr: KtExpression?): Boolean { + if (argumentExpr !is KtNameReferenceExpression) return false val context = analyze(BodyResolveMode.PARTIAL) val resolvedCall = getResolvedCall(context) val dispatchReceiver = resolvedCall?.dispatchReceiver as? ThisClassReceiver ?: return false + val argumentDescriptor = context[BindingContext.REFERENCE_TARGET, argumentExpr] ?: return false val calledFunctionDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor if (calledFunctionDescriptor?.isAnyEquals() != true) return false val containingFunctionDescriptor = getNonStrictParentOfType()?.descriptor as? FunctionDescriptor return calledFunctionDescriptor == containingFunctionDescriptor && - dispatchReceiver.classDescriptor == containingFunctionDescriptor.containingDeclaration + dispatchReceiver.classDescriptor == containingFunctionDescriptor.containingDeclaration && + argumentDescriptor == containingFunctionDescriptor.valueParameters.singleOrNull() } private fun KtExpression.reportRecursiveEquals() { @@ -58,7 +62,7 @@ class RecursiveEqualsCallInspection : AbstractKotlinInspection() { super.visitBinaryExpression(expr) if (expr.operationToken != KtTokens.EQEQ) return - if (!expr.isRecursiveEquals()) return + if (!expr.isRecursiveEquals(expr.right)) return expr.reportRecursiveEquals() } @@ -68,7 +72,7 @@ class RecursiveEqualsCallInspection : AbstractKotlinInspection() { if (calleeExpression.getReferencedNameAsName() != OperatorNameConventions.EQUALS) return if (expr.parent is KtSafeQualifiedExpression) return - if (!expr.isRecursiveEquals()) return + if (!expr.isRecursiveEquals(expr.valueArguments.singleOrNull()?.getArgumentExpression())) return expr.reportRecursiveEquals() } } diff --git a/idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFakeNoOther.kt b/idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFakeNoOther.kt new file mode 100644 index 00000000000..6b1a822122c --- /dev/null +++ b/idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFakeNoOther.kt @@ -0,0 +1,9 @@ +// PROBLEM: none + +class Test { + override fun equals(other: Any?): Boolean { + val s = Test() + if (this == s) 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 bc23e6d2dd5..e9eed83d265 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1532,6 +1532,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { doTest(fileName); } + @TestMetadata("recursiveFakeNoOther.kt") + public void testRecursiveFakeNoOther() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveFakeNoOther.kt"); + doTest(fileName); + } + @TestMetadata("recursiveImplicit.kt") public void testRecursiveImplicit() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/recursiveEqualsCall/recursiveImplicit.kt");