Refactor getKotlinTypeWithPossibleSmartCastToFP and related parts
This commit is contained in:
@@ -10,13 +10,12 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
|||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.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.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
class TypeAndNullability(@JvmField val type: Type, @JvmField val isNullable: Boolean)
|
class TypeAndNullability(@JvmField val type: Type, @JvmField val isNullable: Boolean)
|
||||||
@@ -35,60 +34,31 @@ fun calcProperTypeForIeee754ArithmeticIfNeeded(
|
|||||||
return TypeAndNullability(asmType, isNullable)
|
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(
|
fun legacyCalcTypeForIeee754ArithmeticIfNeeded(
|
||||||
expression: KtExpression?,
|
expression: KtExpression?,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): TypeAndNullability? {
|
): TypeAndNullability? {
|
||||||
val ktType = expression?.getKotlinTypeForComparison(bindingContext) ?: return null
|
val ktType = expression.getKotlinTypeWithPossibleSmartCastToFP(
|
||||||
|
// NB. Using DataFlowValueFactoryImpl is a hack, but it is ok for 'legacy'
|
||||||
if (KotlinBuiltIns.isDoubleOrNullableDouble(ktType)) {
|
bindingContext, descriptor, languageVersionSettings, DataFlowValueFactoryImpl(languageVersionSettings)
|
||||||
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 stableTypes = bindingContext.getDataFlowInfoBefore(expression).getStableTypes(dataFlow, languageVersionSettings)
|
|
||||||
return stableTypes.firstNotNullResult {
|
if (ktType != null) {
|
||||||
when {
|
if (KotlinBuiltIns.isDoubleOrNullableDouble(ktType)) {
|
||||||
KotlinBuiltIns.isDoubleOrNullableDouble(it) -> TypeAndNullability(
|
return TypeAndNullability(
|
||||||
Type.DOUBLE_TYPE,
|
Type.DOUBLE_TYPE,
|
||||||
TypeUtils.isNullableType(
|
TypeUtils.isNullableType(ktType)
|
||||||
it
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
KotlinBuiltIns.isFloatOrNullableFloat(it) -> TypeAndNullability(
|
}
|
||||||
|
|
||||||
|
if (KotlinBuiltIns.isFloatOrNullableFloat(ktType)) {
|
||||||
|
return TypeAndNullability(
|
||||||
Type.FLOAT_TYPE,
|
Type.FLOAT_TYPE,
|
||||||
TypeUtils.isNullableType(
|
TypeUtils.isNullableType(ktType)
|
||||||
it
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
else -> null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
+4
-38
@@ -21,10 +21,7 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.tree.IElementType
|
import com.intellij.psi.tree.IElementType
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode
|
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.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
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.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
|
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
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.getFirstArgumentExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getReceiverExpression
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getReceiverExpression
|
||||||
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.calls.smartcasts.DataFlowValueFactory
|
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.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import org.jetbrains.kotlin.types.typeUtil.*
|
import org.jetbrains.kotlin.types.typeUtil.*
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
|
||||||
|
|
||||||
class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
|
class ReplaceCallWithBinaryOperatorInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
|
||||||
KtDotQualifiedExpression::class.java
|
KtDotQualifiedExpression::class.java
|
||||||
@@ -172,46 +167,17 @@ 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 calcDescriptor = {
|
val dataFlowValueFactory = getResolutionFacade().getFrontendService(DataFlowValueFactory::class.java)
|
||||||
this.containingDeclarationForPseudocode?.resolveToDescriptorIfAny()
|
|
||||||
}
|
|
||||||
val receiverType = resolvedCall.getReceiverExpression()?.getKotlinTypeWithPossibleSmartCastToFP(
|
val receiverType = resolvedCall.getReceiverExpression()?.getKotlinTypeWithPossibleSmartCastToFP(
|
||||||
context, calcDescriptor
|
context, containingDeclarationForPseudocode?.resolveToDescriptorIfAny(), languageVersionSettings, dataFlowValueFactory
|
||||||
) ?: return false
|
) ?: return false
|
||||||
val argumentType = resolvedCall.getFirstArgumentExpression()?.getKotlinTypeWithPossibleSmartCastToFP(
|
val argumentType = resolvedCall.getFirstArgumentExpression()?.getKotlinTypeWithPossibleSmartCastToFP(
|
||||||
context, calcDescriptor
|
context, containingDeclarationForPseudocode?.resolveToDescriptorIfAny(), languageVersionSettings, dataFlowValueFactory
|
||||||
) ?: return false
|
) ?: return false
|
||||||
return receiverType.isFpType() && argumentType.isNumericType() ||
|
return receiverType.isFpType() && argumentType.isNumericType() ||
|
||||||
argumentType.isFpType() && receiverType.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 {
|
private fun KtSimpleNameExpression.isFloatingPointNumberEquals(): Boolean {
|
||||||
val dotQualified = parent.parent as? KtDotQualifiedExpression ?: return false
|
val dotQualified = parent.parent as? KtDotQualifiedExpression ?: return false
|
||||||
return dotQualified.isFloatingPointNumberEquals()
|
return dotQualified.isFloatingPointNumberEquals()
|
||||||
|
|||||||
Reference in New Issue
Block a user