[FIR] Properly create FirAnnotation and FirAnnotationCall in all places

This commit is contained in:
Dmitriy Novozhilov
2021-09-07 13:03:11 +03:00
committed by teamcityserver
parent 31a7d8d5a4
commit 2e7564a21e
8 changed files with 92 additions and 94 deletions
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.resolve.bindSymbolToLookupTag
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols
@@ -101,18 +100,21 @@ private val JAVA_TARGETS_TO_KOTLIN = mapOf(
"TYPE_USE" to EnumSet.of(AnnotationTarget.TYPE)
)
private fun List<JavaAnnotationArgument>.mapJavaTargetArguments(session: FirSession): FirExpression? =
buildArrayOfCall {
argumentList = buildArgumentList {
val resultSet = EnumSet.noneOf(AnnotationTarget::class.java)
for (target in this@mapJavaTargetArguments) {
if (target !is JavaEnumValueAnnotationArgument) return null
resultSet.addAll(JAVA_TARGETS_TO_KOTLIN[target.entryName?.asString()] ?: continue)
}
val classId = ClassId.topLevel(StandardNames.FqNames.annotationTarget)
resultSet.mapTo(arguments) { buildEnumCall(session, classId, Name.identifier(it.name)) }
private val TARGET_ALLOWED_TARGETS_NAME = Name.identifier("allowedTargets")
private val RETENTION_VALUE_NAME = Name.identifier("value")
private val DEPRECATED_MESSAGE_NAME = Name.identifier("message")
private fun List<JavaAnnotationArgument>.mapJavaTargetArguments(session: FirSession): FirExpression? {
return buildVarargArgumentsExpression {
val resultSet = EnumSet.noneOf(AnnotationTarget::class.java)
for (target in this@mapJavaTargetArguments) {
if (target !is JavaEnumValueAnnotationArgument) return null
resultSet.addAll(JAVA_TARGETS_TO_KOTLIN[target.entryName?.asString()] ?: continue)
}
val classId = ClassId.topLevel(StandardNames.FqNames.annotationTarget)
resultSet.mapTo(arguments) { buildEnumCall(session, classId, Name.identifier(it.name)) }
}
}
private val JAVA_RETENTION_TO_KOTLIN = mapOf(
"RUNTIME" to AnnotationRetention.RUNTIME,
@@ -125,26 +127,24 @@ private fun JavaAnnotationArgument.mapJavaRetentionArgument(session: FirSession)
buildEnumCall(session, ClassId.topLevel(StandardNames.FqNames.annotationRetention), Name.identifier(it.name))
}
private fun buildArgumentMapping(
private fun fillAnnotationArgumentMapping(
session: FirSession,
javaTypeParameterStack: JavaTypeParameterStack,
lookupTag: ConeClassLikeLookupTagImpl,
annotationArguments: Collection<JavaAnnotationArgument>
): FirArgumentList? {
if (annotationArguments.none { it.name != null }) {
return null
}
annotationArguments: Collection<JavaAnnotationArgument>,
destination: MutableMap<Name, FirExpression>
) {
if (annotationArguments.none { it.name != null }) return
val annotationClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(lookupTag.classId).also {
lookupTag.bindSymbolToLookupTag(session, it)
} ?: return null
} ?: return
val annotationConstructor =
(annotationClassSymbol.fir as FirRegularClass).declarations.filterIsInstance<FirConstructor>().first()
val mapping = annotationArguments.associateTo(linkedMapOf()) { argument ->
val parameter = annotationConstructor.valueParameters.find { it.name == (argument.name ?: JavaSymbolProvider.VALUE_METHOD_NAME) }
?: return null
argument.toFirExpression(session, javaTypeParameterStack, parameter.returnTypeRef) to parameter
annotationArguments.associateTo(destination) { argument ->
val name = argument.name ?: JavaSymbolProvider.VALUE_METHOD_NAME
val parameter = annotationConstructor.valueParameters.find { it.name == name }
name to argument.toFirExpression(session, javaTypeParameterStack, parameter?.returnTypeRef)
}
return buildResolvedArgumentList(mapping)
}
internal fun Iterable<JavaAnnotation>.convertAnnotationsToFir(
@@ -181,23 +181,36 @@ private fun JavaAnnotation.toFirAnnotationCall(
} else {
buildErrorTypeRef { diagnostic = ConeUnresolvedReferenceError() }
}
argumentList = when (classId) {
JAVA_TARGET_CLASS_ID -> when (val argument = arguments.singleOrNull()) {
is JavaArrayAnnotationArgument -> argument.getElements().mapJavaTargetArguments(session)?.let(::buildUnaryArgumentList)
is JavaEnumValueAnnotationArgument -> listOf(argument).mapJavaTargetArguments(session)?.let(::buildUnaryArgumentList)
else -> null
}
JAVA_RETENTION_CLASS_ID -> arguments.singleOrNull()?.mapJavaRetentionArgument(session)?.let(::buildUnaryArgumentList)
JAVA_DEPRECATED_CLASS_ID ->
buildUnaryArgumentList(buildConstExpression(null, ConstantValueKind.String, "Deprecated in Java").setProperType(session))
null -> null
else -> buildArgumentMapping(session, javaTypeParameterStack, lookupTag!!, arguments)
} ?: buildArgumentList {
this@toFirAnnotationCall.arguments.mapTo(arguments) {
it.toFirExpression(session, javaTypeParameterStack, null)
argumentMapping = buildAnnotationArgumentMapping {
when (classId) {
JAVA_TARGET_CLASS_ID -> {
when (val argument = arguments.firstOrNull()) {
is JavaArrayAnnotationArgument -> argument.getElements().mapJavaTargetArguments(session)
is JavaEnumValueAnnotationArgument -> listOf(argument).mapJavaTargetArguments(session)
else -> null
}?.let {
mapping[TARGET_ALLOWED_TARGETS_NAME] = it
}
}
JAVA_RETENTION_CLASS_ID -> {
arguments.firstOrNull()?.mapJavaRetentionArgument(session)?.let {
mapping[RETENTION_VALUE_NAME] = it
}
}
JAVA_DEPRECATED_CLASS_ID -> {
mapping[DEPRECATED_MESSAGE_NAME] = buildConstExpression(
source = null,
ConstantValueKind.String,
"Deprecated in Java"
).setProperType(session)
}
null -> {}
else -> {
fillAnnotationArgumentMapping(session, javaTypeParameterStack, lookupTag!!, arguments, mapping)
}
}
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
}
}
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.java.createConstantOrError
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.resolve.providers.getClassDeclaredPropertySymbols
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
@@ -110,7 +109,7 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
)
}
override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor {
val list = mutableListOf<FirAnnotation>()
val visitor = loadAnnotation(classId, list)
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor {
@@ -150,16 +149,9 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
result += buildAnnotation {
annotationTypeRef = lookupTag.toDefaultResolvedTypeRef()
argumentList = buildArgumentList {
for ((name, expression) in argumentMap) {
arguments += buildNamedArgumentExpression {
this.expression = expression
this.name = name
isSpread = false
}
}
argumentMapping = buildAnnotationArgumentMapping {
mapping.putAll(argumentMap)
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
}
}
@@ -93,9 +93,8 @@ class JvmBinaryAnnotationDeserializer(
).map {
buildAnnotation {
annotationTypeRef = it.annotationTypeRef
argumentList = it.argumentList
argumentMapping = it.argumentMapping
useSiteTarget = AnnotationUseSiteTarget.PROPERTY
calleeReference = it.calleeReference
}
}
}
@@ -116,9 +115,8 @@ class JvmBinaryAnnotationDeserializer(
return findJvmBinaryClassAndLoadMemberAnnotations(signature).map {
buildAnnotation {
annotationTypeRef = it.annotationTypeRef
argumentList = it.argumentList
argumentMapping = it.argumentMapping
useSiteTarget = AnnotationUseSiteTarget.FIELD
calleeReference = it.calleeReference
}
}
}
@@ -136,9 +134,8 @@ class JvmBinaryAnnotationDeserializer(
return findJvmBinaryClassAndLoadMemberAnnotations(signature).map {
buildAnnotation {
annotationTypeRef = it.annotationTypeRef
argumentList = it.argumentList
argumentMapping = it.argumentMapping
useSiteTarget = AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
calleeReference = it.calleeReference
}
}
}