Do not highlight replacement of equals involving floating-point types
Two tests with smart casts do not work yet Part of KT-25933
This commit is contained in:
committed by
Mikhail Glukhikh
parent
8c6337f3f6
commit
1aa9d5673b
+40
-8
@@ -21,20 +21,25 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.codegen.kotlinType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractApplicabilityBasedInspection
|
||||
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||
import org.jetbrains.kotlin.idea.intentions.*
|
||||
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.isAnyEquals
|
||||
import org.jetbrains.kotlin.idea.intentions.isReceiverExpressionWithValue
|
||||
import org.jetbrains.kotlin.idea.intentions.toResolvedCall
|
||||
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getFirstArgumentExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getReceiverExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
|
||||
@@ -69,10 +74,13 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec
|
||||
override fun inspectionHighlightType(element: KtDotQualifiedExpression): ProblemHighlightType {
|
||||
val calleeExpression = element.callExpression?.calleeExpression as? KtSimpleNameExpression
|
||||
val identifier = calleeExpression?.getReferencedNameAsName()
|
||||
return if (identifier == OperatorNameConventions.EQUALS || identifier == OperatorNameConventions.COMPARE_TO) {
|
||||
val isFloatingPointNumberEquals = calleeExpression?.isFloatingPointNumberEquals() ?: false
|
||||
|
||||
return if (isFloatingPointNumberEquals) {
|
||||
ProblemHighlightType.INFORMATION
|
||||
} else if (identifier == OperatorNameConventions.EQUALS || identifier == OperatorNameConventions.COMPARE_TO) {
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ProblemHighlightType.INFORMATION
|
||||
}
|
||||
}
|
||||
@@ -84,6 +92,10 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec
|
||||
|
||||
override fun fixText(element: KtDotQualifiedExpression): String {
|
||||
val calleeExpression = element.callExpression?.calleeExpression as? KtSimpleNameExpression ?: return defaultFixText
|
||||
if (calleeExpression.isFloatingPointNumberEquals()) {
|
||||
return "Replace total order equality with IEEE 754 equality"
|
||||
}
|
||||
|
||||
val operation = operation(calleeExpression) ?: return defaultFixText
|
||||
return "Replace with '${operation.value}'"
|
||||
}
|
||||
@@ -123,7 +135,6 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec
|
||||
return when (identifier) {
|
||||
OperatorNameConventions.EQUALS -> {
|
||||
if (!dotQualified.isAnyEquals()) return null
|
||||
|
||||
val prefixExpression = dotQualified.getWrappingPrefixExpressionIfAny()
|
||||
if (prefixExpression != null && prefixExpression.operationToken == KtTokens.EXCL) KtTokens.EXCLEQ
|
||||
else KtTokens.EQEQ
|
||||
@@ -148,4 +159,25 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec
|
||||
else -> OperatorConventions.BINARY_OPERATION_NAMES.inverse()[identifier]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtDotQualifiedExpression.isFloatingPointNumberEquals(): Boolean {
|
||||
val resolvedCall = resolveToCall() ?: return false
|
||||
val context = analyze(BodyResolveMode.PARTIAL)
|
||||
val receiverType = resolvedCall.getReceiverExpression().kotlinType(context) ?: return false
|
||||
val argumentType = resolvedCall.getFirstArgumentExpression().kotlinType(context) ?: return false
|
||||
return (receiverType.isFpType() && argumentType.isNumericType()) || (argumentType.isFpType() && receiverType.isNumericType())
|
||||
}
|
||||
|
||||
private fun KtSimpleNameExpression.isFloatingPointNumberEquals(): Boolean {
|
||||
val dotQualified = parent.parent as? KtDotQualifiedExpression ?: return false
|
||||
return dotQualified.isFloatingPointNumberEquals()
|
||||
}
|
||||
|
||||
private fun KotlinType.isFpType(): Boolean {
|
||||
return isFloat() || isDouble()
|
||||
}
|
||||
|
||||
private fun KotlinType.isNumericType(): Boolean {
|
||||
return isFpType() || isByte() || isShort() || isInt() || isLong()
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun test(a: Any, b: Any) =
|
||||
a is Double && b is Double && a.<caret>equals(b)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun test(a: Any, b: Any) =
|
||||
a is Double && b is Double && a == b
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun test(a: Any, b: Any) =
|
||||
a is Float && b is Float && a.<caret>equals(b)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun test(a: Any, b: Any) =
|
||||
a is Float && b is Float && a == b
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun checkPi(x: Double) = x.<caret>equals(3.14)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun checkPi(x: Double) = x == 3.14
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun checkPi(x: Double) = 3.14.<caret>equals(x)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun checkPi(x: Double) = 3.14 == x
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun test(a: Double, b: Double) = a.<caret>equals(b)
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// FIX: Replace total order equality with IEEE 754 equality
|
||||
|
||||
fun test(a: Double, b: Double) = a == b
|
||||
+25
@@ -1526,11 +1526,36 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsCompareTo.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("equalsDoubleSmartCast.kt")
|
||||
public void testEqualsDoubleSmartCast() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsDoubleSmartCast.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("equalsExtensionFunction.kt")
|
||||
public void testEqualsExtensionFunction() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsExtensionFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("equalsFloatSmartCast.kt")
|
||||
public void testEqualsFloatSmartCast() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsFloatSmartCast.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("equalsFloatingPointLiteral1.kt")
|
||||
public void testEqualsFloatingPointLiteral1() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsFloatingPointLiteral1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("equalsFloatingPointLiteral2.kt")
|
||||
public void testEqualsFloatingPointLiteral2() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsFloatingPointLiteral2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("equalsFloatingPointType.kt")
|
||||
public void testEqualsFloatingPointType() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsFloatingPointType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("extensionFunction.kt")
|
||||
public void testExtensionFunction() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/extensionFunction.kt");
|
||||
|
||||
Reference in New Issue
Block a user