fix "Can be replaced with comparison" false positive if extension method called 'equals' is used
Fixes #KT-13480
This commit is contained in:
+9
-3
@@ -32,6 +32,8 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
|
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
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.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -107,16 +109,20 @@ class ReplaceCallWithBinaryOperatorIntention : SelfTargetingRangeIntention<KtDot
|
|||||||
|
|
||||||
private fun operation(calleeExpression: KtSimpleNameExpression): KtSingleValueToken? {
|
private fun operation(calleeExpression: KtSimpleNameExpression): KtSingleValueToken? {
|
||||||
val identifier = calleeExpression.getReferencedNameAsName()
|
val identifier = calleeExpression.getReferencedNameAsName()
|
||||||
|
val dotQualified = calleeExpression.parent?.parent as? KtDotQualifiedExpression ?: return null
|
||||||
return when (identifier) {
|
return when (identifier) {
|
||||||
OperatorNameConventions.EQUALS -> {
|
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
|
if (prefixExpression != null && prefixExpression.operationToken == KtTokens.EXCL) KtTokens.EXCLEQ
|
||||||
else KtTokens.EQEQ
|
else KtTokens.EQEQ
|
||||||
}
|
}
|
||||||
OperatorNameConventions.COMPARE_TO -> {
|
OperatorNameConventions.COMPARE_TO -> {
|
||||||
// callee -> call -> DotQualified -> Binary
|
// 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 {
|
val notZero = when {
|
||||||
binaryParent.right?.text == "0" -> binaryParent.left
|
binaryParent.right?.text == "0" -> binaryParent.left
|
||||||
binaryParent.left?.text == "0" -> binaryParent.right
|
binaryParent.left?.text == "0" -> binaryParent.right
|
||||||
|
|||||||
+11
@@ -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);
|
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")
|
@TestMetadata("extensionFunction.kt")
|
||||||
public void testExtensionFunction() throws Exception {
|
public void testExtensionFunction() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/conventionNameCalls/replaceCallWithBinaryOperator/extensionFunction.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/conventionNameCalls/replaceCallWithBinaryOperator/extensionFunction.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user