[FIR] Fix mapping of java annotation arguments when parameter is array

#KT-65933 Fixed
This commit is contained in:
Kirill Rakhman
2024-02-22 17:49:17 +01:00
committed by Space Team
parent 6479b15e46
commit 4780bb90e7
5 changed files with 26 additions and 537 deletions
@@ -58,15 +58,14 @@ val JavaClass.classKind: ClassKind
fun JavaClass.hasMetadataAnnotation(): Boolean =
annotations.any { it.isResolvedTo(JvmAnnotationNames.METADATA_FQ_NAME) }
internal fun Any?.createConstantOrError(session: FirSession, expectedTypeRef: FirTypeRef? = null): FirExpression {
val coneType = expectedTypeRef?.coneTypeOrNull
val value = if (this is Int && coneType != null) {
internal fun Any?.createConstantOrError(session: FirSession, expectedConeType: ConeKotlinType? = null): FirExpression {
val value = if (this is Int && expectedConeType != null) {
// special case for Java literals in annotation default values:
// literal value is always integer, but an expected parameter type can be any other number type
when {
coneType.isByte -> this.toByte()
coneType.isShort -> this.toShort()
coneType.isLong -> this.toLong()
expectedConeType.isByte -> this.toByte()
expectedConeType.isShort -> this.toShort()
expectedConeType.isLong -> this.toLong()
else -> this
}
} else this
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.toKtPsiSourceElement
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import java.util.*
import kotlin.math.exp
internal fun Iterable<JavaAnnotation>.convertAnnotationsToFir(
session: FirSession,
@@ -103,21 +104,18 @@ internal fun JavaValueParameter.toFirValueParameter(
internal fun JavaAnnotationArgument.toFirExpression(
session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, expectedTypeRef: FirTypeRef?
): FirExpression {
return when (this) {
val expectedConeType = expectedTypeRef?.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack)
val expectedArrayElementTypeIfArray = expectedConeType?.lowerBoundIfFlexible()?.arrayElementType() ?: expectedConeType
val argument = when (this) {
is JavaLiteralAnnotationArgument -> value.createConstantOrError(
session,
expectedTypeRef?.resolveIfJavaType(session, javaTypeParameterStack)
expectedArrayElementTypeIfArray
)
is JavaArrayAnnotationArgument -> buildArrayLiteral {
val argumentTypeRef = expectedTypeRef?.let {
val type = if (it is FirJavaTypeRef) {
it.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack)
} else {
it.coneType
}
coneTypeOrNull = type
val argumentTypeRef = expectedConeType?.let {
coneTypeOrNull = it
buildResolvedTypeRef {
this.type = type.lowerBoundIfFlexible().arrayElementType()
this.type = it.lowerBoundIfFlexible().arrayElementType()
?: ConeErrorType(ConeSimpleDiagnostic("expected type is not array type"))
}
}
@@ -131,7 +129,7 @@ internal fun JavaAnnotationArgument.toFirExpression(
// a static import. In this case, the parameter default initializer will not have its type set, which isn't usually an
// issue except in edge cases like KT-47702 where we do need to evaluate the default values of annotations.
// As a fallback, we use the expected type which should be the type of the enum.
classId = requireNotNull(enumClassId ?: expectedTypeRef?.coneTypeOrNull?.lowerBoundIfFlexible()?.classId),
classId = requireNotNull(enumClassId ?: expectedArrayElementTypeIfArray?.lowerBoundIfFlexible()?.classId),
entryName = entryName
)
is JavaClassObjectAnnotationArgument -> buildGetClassCall {
@@ -152,6 +150,17 @@ internal fun JavaAnnotationArgument.toFirExpression(
diagnostic = ConeSimpleDiagnostic("Unknown JavaAnnotationArgument: ${this::class.java}", DiagnosticKind.Java)
}
}
return if (expectedConeType?.lowerBoundIfFlexible()?.isArrayOrPrimitiveArray == true && argument !is FirArrayLiteral) {
buildArrayLiteral {
coneTypeOrNull = expectedConeType
argumentList = buildArgumentList {
arguments += argument
}
}
} else {
argument
}
}
private val JAVA_RETENTION_TO_KOTLIN: Map<String, AnnotationRetention> = mapOf(