Can be replaced with binary operator: do not suggest when receiver or argument is floating point type

#KT-28596 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-02-08 15:10:05 +09:00
committed by Mikhail Glukhikh
parent 48619a49ed
commit d583c1be58
7 changed files with 34 additions and 5 deletions
@@ -25,7 +25,8 @@ fun KtExpression?.getKotlinTypeWithPossibleSmartCastToFP(
bindingContext: BindingContext, bindingContext: BindingContext,
descriptor: DeclarationDescriptor?, descriptor: DeclarationDescriptor?,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory dataFlowValueFactory: DataFlowValueFactory,
defaultType: (KotlinType, Set<KotlinType>) -> KotlinType = { givenType, _ -> givenType }
): KotlinType? { ): KotlinType? {
val givenType = this?.getKotlinTypeForComparison(bindingContext) ?: return null val givenType = this?.getKotlinTypeForComparison(bindingContext) ?: return null
@@ -40,13 +41,13 @@ fun KtExpression?.getKotlinTypeWithPossibleSmartCastToFP(
if (descriptor != null) { if (descriptor != null) {
val dataFlow = dataFlowValueFactory.createDataFlowValue(this, givenType, bindingContext, descriptor) val dataFlow = dataFlowValueFactory.createDataFlowValue(this, givenType, bindingContext, descriptor)
val stableTypes = bindingContext.getDataFlowInfoBefore(this).getStableTypes(dataFlow, languageVersionSettings) val stableTypes = bindingContext.getDataFlowInfoBefore(this).getStableTypes(dataFlow, languageVersionSettings)
stableTypes.firstNotNullResult { return stableTypes.firstNotNullResult {
when { when {
KotlinBuiltIns.isDoubleOrNullableDouble(it) -> it KotlinBuiltIns.isDoubleOrNullableDouble(it) -> it
KotlinBuiltIns.isFloatOrNullableFloat(it) -> it KotlinBuiltIns.isFloatOrNullableFloat(it) -> it
else -> null else -> null
} }
}?.let { return it } } ?: defaultType(givenType, stableTypes)
} }
return givenType return givenType
} }
@@ -187,12 +187,14 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec
private fun KtDotQualifiedExpression.isFloatingPointNumberEquals(): Boolean { private fun KtDotQualifiedExpression.isFloatingPointNumberEquals(): Boolean {
val resolvedCall = resolveToCall() ?: return false val resolvedCall = resolveToCall() ?: return false
val context = analyze(BodyResolveMode.PARTIAL) val context = analyze(BodyResolveMode.PARTIAL)
val declarationDescriptor = containingDeclarationForPseudocode?.resolveToDescriptorIfAny()
val dataFlowValueFactory = getResolutionFacade().getFrontendService(DataFlowValueFactory::class.java) val dataFlowValueFactory = getResolutionFacade().getFrontendService(DataFlowValueFactory::class.java)
val defaultType: (KotlinType, Set<KotlinType>) -> KotlinType = { givenType, stableTypes -> stableTypes.firstOrNull() ?: givenType }
val receiverType = resolvedCall.getReceiverExpression()?.getKotlinTypeWithPossibleSmartCastToFP( val receiverType = resolvedCall.getReceiverExpression()?.getKotlinTypeWithPossibleSmartCastToFP(
context, containingDeclarationForPseudocode?.resolveToDescriptorIfAny(), languageVersionSettings, dataFlowValueFactory context, declarationDescriptor, languageVersionSettings, dataFlowValueFactory, defaultType
) ?: return false ) ?: return false
val argumentType = resolvedCall.getFirstArgumentExpression()?.getKotlinTypeWithPossibleSmartCastToFP( val argumentType = resolvedCall.getFirstArgumentExpression()?.getKotlinTypeWithPossibleSmartCastToFP(
context, containingDeclarationForPseudocode?.resolveToDescriptorIfAny(), languageVersionSettings, dataFlowValueFactory context, declarationDescriptor, languageVersionSettings, dataFlowValueFactory, defaultType
) ?: return false ) ?: return false
return receiverType.isFpType() && argumentType.isNumericType() || return receiverType.isFpType() && argumentType.isNumericType() ||
argumentType.isFpType() && receiverType.isNumericType() argumentType.isFpType() && receiverType.isNumericType()
@@ -0,0 +1,4 @@
// FIX: Replace total order equality with IEEE 754 equality
fun test(a: Any, b: Any) =
a is Double && b is Int && a.<caret>equals(b)
@@ -0,0 +1,4 @@
// FIX: Replace total order equality with IEEE 754 equality
fun test(a: Any, b: Any) =
a is Double && b is Int && a == b
@@ -0,0 +1,4 @@
// FIX: Replace total order equality with IEEE 754 equality
fun test(a: Any, b: Any) =
a is Int && b is Double && a.<caret>equals(b)
@@ -0,0 +1,4 @@
// FIX: Replace total order equality with IEEE 754 equality
fun test(a: Any, b: Any) =
a is Int && b is Double && a == b
@@ -1679,6 +1679,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsDoubleSmartCast.kt"); runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsDoubleSmartCast.kt");
} }
@TestMetadata("equalsDoubleSmartCast2.kt")
public void testEqualsDoubleSmartCast2() throws Exception {
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsDoubleSmartCast2.kt");
}
@TestMetadata("equalsDoubleSmartCast3.kt")
public void testEqualsDoubleSmartCast3() throws Exception {
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsDoubleSmartCast3.kt");
}
@TestMetadata("equalsDoubleSmartCastFromGeneric.kt") @TestMetadata("equalsDoubleSmartCastFromGeneric.kt")
public void testEqualsDoubleSmartCastFromGeneric() throws Exception { public void testEqualsDoubleSmartCastFromGeneric() throws Exception {
runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsDoubleSmartCastFromGeneric.kt"); runTest("idea/testData/inspectionsLocal/conventionNameCalls/replaceCallWithBinaryOperator/equalsDoubleSmartCastFromGeneric.kt");