Suggest quick-fixes for SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED

#KT-27590 Fixed
This commit is contained in:
Mikhail Glukhikh
2018-12-18 19:59:37 +03:00
parent 9289a2c573
commit d7ce79cc76
6 changed files with 56 additions and 8 deletions
@@ -138,6 +138,20 @@ class IntegerValueTypeConstant(
return IntegerValueTypeConstant(value, module, newParameters, convertedFromSigned = true)
}
fun IntegerValueTypeConstant.convertToSignedConstant(module: ModuleDescriptor): IntegerValueTypeConstant {
val newParameters = CompileTimeConstant.Parameters(
parameters.canBeUsedInAnnotation,
parameters.isPure,
isUnsignedNumberLiteral = false,
isUnsignedLongNumberLiteral = parameters.isUnsignedLongNumberLiteral,
usesVariableAsConstant = parameters.usesVariableAsConstant,
usesNonConstValAsConstant = parameters.usesNonConstValAsConstant,
isConvertableConstVal = parameters.isConvertableConstVal
)
return IntegerValueTypeConstant(value, module, newParameters, convertedFromSigned = true)
}
}
private val typeConstructor = IntegerValueTypeConstructor(value.toLong(), module, parameters)
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.util.approximateWithResolvableType
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction
import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
@@ -41,10 +43,12 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.KotlinTypeFactory
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE
import org.jetbrains.kotlin.types.typeUtil.*
import java.util.*
@@ -90,16 +94,28 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
val diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic)
expectedType = diagnosticWithParameters.b
expressionType = context.getType(diagnosticElement)
if (expressionType == null) {
LOG.error("No type inferred: " + diagnosticElement.text)
return emptyList()
}
}
Errors.SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED -> {
val constantValue = context[BindingContext.COMPILE_TIME_VALUE, diagnosticElement]
if (constantValue is IntegerValueTypeConstant) {
// Here we have unsigned type (despite really constant is signed)
expectedType = constantValue.getType(NO_EXPECTED_TYPE)
val signedConstantValue = with(IntegerValueTypeConstant) {
constantValue.convertToSignedConstant(diagnosticElement.findModuleDescriptor())
}
// And here we have signed type
expressionType = signedConstantValue.getType(NO_EXPECTED_TYPE)
} else return emptyList()
}
else -> {
LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic))
return emptyList()
}
}
if (expressionType == null) {
LOG.error("No type inferred: " + diagnosticElement.text)
return emptyList()
}
if (expressionType.isPrimitiveNumberType() && expectedType.isPrimitiveNumberType()) {
var wrongPrimitiveLiteralFix: WrongPrimitiveLiteralFix? = null
@@ -240,10 +256,10 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
val correspondingParameterDescriptor = resolvedCall.getParameterForArgument(valueArgument)
val correspondingParameter = QuickFixUtil.safeGetDeclaration(correspondingParameterDescriptor) as? KtParameter
val expressionFromArgument = valueArgument.getArgumentExpression()
val valueArgumentType = if (diagnostic.factory === Errors.NULL_FOR_NONNULL_TYPE)
expressionType
else
expressionFromArgument?.let { context.getType(it) }
val valueArgumentType = when (diagnostic.factory) {
Errors.NULL_FOR_NONNULL_TYPE, Errors.SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED -> expressionType
else -> expressionFromArgument?.let { context.getType(it) }
}
if (valueArgumentType != null) {
if (correspondingParameter != null) {
val callable = PsiTreeUtil.getParentOfType(correspondingParameter, KtCallableDeclaration::class.java, true)
@@ -370,6 +370,7 @@ class QuickFixRegistrar : QuickFixContributor {
NULL_FOR_NONNULL_TYPE.registerFactory(factoryForTypeMismatchError)
CONSTANT_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH.registerFactory(factoryForTypeMismatchError)
SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED.registerFactory(factoryForTypeMismatchError)
SMARTCAST_IMPOSSIBLE.registerFactory(SmartCastImpossibleExclExclFixFactory)
SMARTCAST_IMPOSSIBLE.registerFactory(CastExpressionFix.SmartCastImpossibleFactory)
@@ -0,0 +1,6 @@
// "Change parameter 'u' type of function 'takeUInt' to 'Int'" "true"
// WITH_RUNTIME
fun takeUInt(u: UInt) = 0
val b = takeUInt(<caret>1)
@@ -0,0 +1,6 @@
// "Change parameter 'u' type of function 'takeUInt' to 'Int'" "true"
// WITH_RUNTIME
fun takeUInt(u: Int) = 0
val b = takeUInt(1)
@@ -12531,6 +12531,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
public void testMultiFakeOverride() throws Exception {
runTest("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/multiFakeOverride.kt");
}
@TestMetadata("unsigned.kt")
public void testUnsigned() throws Exception {
runTest("idea/testData/quickfix/typeMismatch/parameterTypeMismatch/unsigned.kt");
}
}
@TestMetadata("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression")