Analysis API: fix invalid constant value kind for unsigned numbers

This commit is contained in:
Ilya Kirillov
2021-11-24 12:38:31 +01:00
parent 673459580c
commit e608f8d8dc
@@ -34,14 +34,26 @@ internal object FirCompileTimeConstantEvaluator {
// TODO: Handle boolean operators, const property loading, class reference, array, annotation values, etc. // TODO: Handle boolean operators, const property loading, class reference, array, annotation values, etc.
fun evaluate(expression: FirExpression): FirConstExpression<*>? = fun evaluate(expression: FirExpression): FirConstExpression<*>? =
when (expression) { when (expression) {
is FirConstExpression<*> -> expression is FirConstExpression<*> -> expression.adaptToConstKind()
is FirFunctionCall -> evaluate(expression) is FirFunctionCall -> evaluate(expression)
else -> null else -> null
} }
fun evaluateAsKtConstantExpression(expression: FirExpression): KtConstantValue? { fun evaluateAsKtConstantExpression(expression: FirExpression): KtConstantValue? {
val evaluated = evaluate(expression) ?: return null val evaluated = evaluate(expression) ?: return null
return KtConstantValueFactory.createConstantValue(evaluated.value, evaluated.psi as? KtElement)
val ktConstantValue = KtConstantValueFactory.createConstantValue(evaluated.value, evaluated.psi as? KtElement) ?: return null
check(ktConstantValue.constantValueKind == evaluated.kind) {
"Expected ${evaluated.kind} for created KtConstantValue but ${ktConstantValue.constantValueKind} found"
}
return ktConstantValue
}
private fun FirConstExpression<*>.adaptToConstKind(): FirConstExpression<*> {
return kind.toConstExpression(
source,
kind.convertToNumber(value as? Number) ?: value
)
} }
// TODO: Rework to handle nested expressions // TODO: Rework to handle nested expressions
@@ -81,7 +93,7 @@ internal object FirCompileTimeConstantEvaluator {
// Lastly, we should preserve the resolved type of the original function call. // Lastly, we should preserve the resolved type of the original function call.
return expression.apply { return expression.apply {
replaceTypeRef(expectedType) replaceTypeRef(expectedType)
} ?: this }
} }
private fun <T> ConstantValueKind<T>.toCompileTimeType(): CompileTimeType { private fun <T> ConstantValueKind<T>.toCompileTimeType(): CompileTimeType {
@@ -195,7 +207,7 @@ internal object FirCompileTimeConstantEvaluator {
else -> error("Unknown constant value") else -> error("Unknown constant value")
} }
private fun ConstantValueKind<*>.convertToNumber(value: Number?): Number? { private fun ConstantValueKind<*>.convertToNumber(value: Number?): Any? {
if (value == null) { if (value == null) {
return null return null
} }
@@ -206,14 +218,17 @@ internal object FirCompileTimeConstantEvaluator {
this == ConstantValueKind.Int -> value.toInt() this == ConstantValueKind.Int -> value.toInt()
this == ConstantValueKind.Long -> value.toLong() this == ConstantValueKind.Long -> value.toLong()
this == ConstantValueKind.Short -> value.toShort() this == ConstantValueKind.Short -> value.toShort()
this == ConstantValueKind.UnsignedByte -> value.toLong().toUByte()
this == ConstantValueKind.UnsignedShort -> value.toLong().toUShort()
this == ConstantValueKind.UnsignedInt -> value.toLong().toUInt()
this == ConstantValueKind.UnsignedLong -> value.toLong().toULong()
else -> null else -> null
} }
} }
private fun <T> ConstantValueKind<T>?.toConstExpression(source: KtSourceElement?, value: Any): FirConstExpression<T>? = private fun <T> ConstantValueKind<T>.toConstExpression(source: KtSourceElement?, value: Any?): FirConstExpression<T> =
if (this == null) null else @Suppress("UNCHECKED_CAST")
@Suppress("UNCHECKED_CAST") buildConstExpression(source, this, value as T)
buildConstExpression(source, this, value as T)
private fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration? { private fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration? {
val symbol: FirBasedSymbol<*>? = when (val reference = calleeReference) { val symbol: FirBasedSymbol<*>? = when (val reference = calleeReference) {