diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ieee754.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ieee754.kt index 77d4cc83ad2..a8c62ba5701 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ieee754.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ieee754.kt @@ -10,13 +10,12 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl +import org.jetbrains.kotlin.resolve.calls.smartcasts.getKotlinTypeForComparison +import org.jetbrains.kotlin.resolve.calls.smartcasts.getKotlinTypeWithPossibleSmartCastToFP import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.org.objectweb.asm.Type class TypeAndNullability(@JvmField val type: Type, @JvmField val isNullable: Boolean) @@ -35,60 +34,31 @@ fun calcProperTypeForIeee754ArithmeticIfNeeded( return TypeAndNullability(asmType, isNullable) } -private fun KotlinType.isFloatingPointOrNullable() = - KotlinBuiltIns.isDoubleOrNullableDouble(this) || KotlinBuiltIns.isFloatOrNullableFloat(this) - -fun KtExpression.getKotlinTypeForComparison(bindingContext: BindingContext): KotlinType? = - when { - this is KtProperty -> bindingContext[BindingContext.VARIABLE, this]?.type - else -> kotlinType(bindingContext) - } - fun legacyCalcTypeForIeee754ArithmeticIfNeeded( expression: KtExpression?, bindingContext: BindingContext, descriptor: DeclarationDescriptor, languageVersionSettings: LanguageVersionSettings ): TypeAndNullability? { - val ktType = expression?.getKotlinTypeForComparison(bindingContext) ?: return null - - if (KotlinBuiltIns.isDoubleOrNullableDouble(ktType)) { - return TypeAndNullability( - Type.DOUBLE_TYPE, - TypeUtils.isNullableType(ktType) - ) - } - - if (KotlinBuiltIns.isFloatOrNullableFloat(ktType)) { - return TypeAndNullability( - Type.FLOAT_TYPE, - TypeUtils.isNullableType(ktType) - ) - } - - // NB. Using DataFlowValueFactoryImpl is a hack, but it is ok for 'legacy' - val dataFlow = DataFlowValueFactoryImpl(languageVersionSettings).createDataFlowValue( - expression, - ktType, - bindingContext, - descriptor + val ktType = expression.getKotlinTypeWithPossibleSmartCastToFP( + // NB. Using DataFlowValueFactoryImpl is a hack, but it is ok for 'legacy' + bindingContext, descriptor, languageVersionSettings, DataFlowValueFactoryImpl(languageVersionSettings) ) - val stableTypes = bindingContext.getDataFlowInfoBefore(expression).getStableTypes(dataFlow, languageVersionSettings) - return stableTypes.firstNotNullResult { - when { - KotlinBuiltIns.isDoubleOrNullableDouble(it) -> TypeAndNullability( + + if (ktType != null) { + if (KotlinBuiltIns.isDoubleOrNullableDouble(ktType)) { + return TypeAndNullability( Type.DOUBLE_TYPE, - TypeUtils.isNullableType( - it - ) + TypeUtils.isNullableType(ktType) ) - KotlinBuiltIns.isFloatOrNullableFloat(it) -> TypeAndNullability( + } + + if (KotlinBuiltIns.isFloatOrNullableFloat(ktType)) { + return TypeAndNullability( Type.FLOAT_TYPE, - TypeUtils.isNullableType( - it - ) + TypeUtils.isNullableType(ktType) ) - else -> null } } + return null } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowUtils.kt new file mode 100644 index 00000000000..a38c2ab9245 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowUtils.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls.smartcasts + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult + +fun KtExpression.getKotlinTypeForComparison(bindingContext: BindingContext): KotlinType? = + when { + this is KtProperty -> bindingContext[BindingContext.VARIABLE, this]?.type + else -> bindingContext.getType(this) + } + +fun KtExpression?.getKotlinTypeWithPossibleSmartCastToFP( + bindingContext: BindingContext, + descriptor: DeclarationDescriptor?, + languageVersionSettings: LanguageVersionSettings, + dataFlowValueFactory: DataFlowValueFactory +): KotlinType? { + val givenType = this?.getKotlinTypeForComparison(bindingContext) ?: return null + + if (KotlinBuiltIns.isDoubleOrNullableDouble(givenType)) { + return givenType + } + + if (KotlinBuiltIns.isFloatOrNullableFloat(givenType)) { + return givenType + } + + if (descriptor != null) { + val dataFlow = dataFlowValueFactory.createDataFlowValue(this, givenType, bindingContext, descriptor) + val stableTypes = bindingContext.getDataFlowInfoBefore(this).getStableTypes(dataFlow, languageVersionSettings) + stableTypes.firstNotNullResult { + when { + KotlinBuiltIns.isDoubleOrNullableDouble(it) -> it + KotlinBuiltIns.isFloatOrNullableFloat(it) -> it + else -> null + } + }?.let { return it } + } + return givenType +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceCallWithBinaryOperatorInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceCallWithBinaryOperatorInspection.kt index 36f1e2ec0ee..a1ab0573ed8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceCallWithBinaryOperatorInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/conventionNameCalls/ReplaceCallWithBinaryOperatorInspection.kt @@ -21,10 +21,7 @@ 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.builtins.KotlinBuiltIns import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode -import org.jetbrains.kotlin.codegen.getKotlinTypeForComparison -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall @@ -38,19 +35,17 @@ 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.BindingContext -import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore 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.calls.smartcasts.DataFlowValueFactory +import org.jetbrains.kotlin.resolve.calls.smartcasts.getKotlinTypeWithPossibleSmartCastToFP 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 -import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspection( KtDotQualifiedExpression::class.java @@ -172,46 +167,17 @@ class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspec private fun KtDotQualifiedExpression.isFloatingPointNumberEquals(): Boolean { val resolvedCall = resolveToCall() ?: return false val context = analyze(BodyResolveMode.PARTIAL) - val calcDescriptor = { - this.containingDeclarationForPseudocode?.resolveToDescriptorIfAny() - } + val dataFlowValueFactory = getResolutionFacade().getFrontendService(DataFlowValueFactory::class.java) val receiverType = resolvedCall.getReceiverExpression()?.getKotlinTypeWithPossibleSmartCastToFP( - context, calcDescriptor + context, containingDeclarationForPseudocode?.resolveToDescriptorIfAny(), languageVersionSettings, dataFlowValueFactory ) ?: return false val argumentType = resolvedCall.getFirstArgumentExpression()?.getKotlinTypeWithPossibleSmartCastToFP( - context, calcDescriptor + context, containingDeclarationForPseudocode?.resolveToDescriptorIfAny(), languageVersionSettings, dataFlowValueFactory ) ?: return false return receiverType.isFpType() && argumentType.isNumericType() || argumentType.isFpType() && receiverType.isNumericType() } - private fun KtExpression.getKotlinTypeWithPossibleSmartCastToFP( - context: BindingContext, - calcDescriptor: () -> DeclarationDescriptor? - ): KotlinType? { - val givenType = getKotlinTypeForComparison(context) ?: return null - - if (KotlinBuiltIns.isDoubleOrNullableDouble(givenType) || KotlinBuiltIns.isFloatOrNullableFloat(givenType)) { - return givenType - } - - val dataFlowValueFactory = getResolutionFacade().getFrontendService(DataFlowValueFactory::class.java) - val dataFlow = dataFlowValueFactory.createDataFlowValue( - this, - givenType, - context, - calcDescriptor() ?: return givenType - ) - val stableTypes = context.getDataFlowInfoBefore(this).getStableTypes(dataFlow, languageVersionSettings) - return stableTypes.firstNotNullResult { - when { - KotlinBuiltIns.isDoubleOrNullableDouble(it) -> it - KotlinBuiltIns.isFloatOrNullableFloat(it) -> it - else -> null - } - } ?: givenType - } - private fun KtSimpleNameExpression.isFloatingPointNumberEquals(): Boolean { val dotQualified = parent.parent as? KtDotQualifiedExpression ?: return false return dotQualified.isFloatingPointNumberEquals()