fix "Can be replaced with comparison" false positive if extension method called 'equals' is used

Fixes #KT-13480
This commit is contained in:
Kirill Rakhman
2016-08-20 14:11:57 +02:00
parent 45b5157ecf
commit e6e46809de
3 changed files with 26 additions and 3 deletions
@@ -32,6 +32,8 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.findOriginalTopMostOverriddenDescriptors
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -107,16 +109,20 @@ class ReplaceCallWithBinaryOperatorIntention : SelfTargetingRangeIntention<KtDot
private fun operation(calleeExpression: KtSimpleNameExpression): KtSingleValueToken? {
val identifier = calleeExpression.getReferencedNameAsName()
val dotQualified = calleeExpression.parent?.parent as? KtDotQualifiedExpression ?: return null
return when (identifier) {
OperatorNameConventions.EQUALS -> {
val prefixExpression = calleeExpression.parent?.parent?.getWrappingPrefixExpressionIfAny()
val resolvedCall = dotQualified.toResolvedCall(BodyResolveMode.PARTIAL) ?: return null
val overriddenDescriptors = resolvedCall.resultingDescriptor.findOriginalTopMostOverriddenDescriptors()
if (overriddenDescriptors.none { it.fqNameUnsafe.asString() == "kotlin.Any.equals" }) return null
val prefixExpression = dotQualified.getWrappingPrefixExpressionIfAny()
if (prefixExpression != null && prefixExpression.operationToken == KtTokens.EXCL) KtTokens.EXCLEQ
else KtTokens.EQEQ
}
OperatorNameConventions.COMPARE_TO -> {
// callee -> call -> DotQualified -> Binary
val dotQualified = calleeExpression.parent?.parent
val binaryParent = dotQualified?.parent as? KtBinaryExpression ?: return null
val binaryParent = dotQualified.parent as? KtBinaryExpression ?: return null
val notZero = when {
binaryParent.right?.text == "0" -> binaryParent.left
binaryParent.left?.text == "0" -> binaryParent.right
@@ -0,0 +1,11 @@
// IS_APPLICABLE: false
class Foo
fun Foo?.equals(other: Foo?) = true
fun bar(f1: Foo?, f2: Foo?) {
if (f1.equals<caret>(f2)) {
}
}
@@ -2807,6 +2807,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("equalsExtensionFunction.kt")
public void testEqualsExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/conventionNameCalls/replaceCallWithBinaryOperator/equalsExtensionFunction.kt");
doTest(fileName);
}
@TestMetadata("extensionFunction.kt")
public void testExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/conventionNameCalls/replaceCallWithBinaryOperator/extensionFunction.kt");