[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
@@ -12,14 +12,10 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.utils.collectEnumEntries
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.buildUnaryArgumentList
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
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.ScopeSession
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.scope
@@ -35,6 +31,7 @@ import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value.Type.*
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
@@ -178,9 +175,24 @@ abstract class AbstractAnnotationDeserializer(
useSiteTarget: AnnotationUseSiteTarget? = null
): FirAnnotation {
val classId = nameResolver.getClassId(proto.id)
var arguments = emptyList<FirExpression>()
return buildAnnotation {
annotationTypeRef = buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(classId).constructClassType(emptyArray(), isNullable = false)
}
this.argumentMapping = createArgumentMapping(proto, classId, nameResolver)
useSiteTarget?.let {
this.useSiteTarget = it
}
}
}
if (proto.argumentCount != 0) {
private fun createArgumentMapping(
proto: ProtoBuf.Annotation,
classId: ClassId,
nameResolver: NameResolver
): FirAnnotationArgumentMapping {
return buildAnnotationArgumentMapping build@{
if (proto.argumentCount == 0) return@build
// Used only for annotation parameters of array types
// Avoid triggering it in other cases, since it's quite expensive
val parameterByName: Map<Name, FirValueParameter>? by lazy(LazyThreadSafetyMode.NONE) {
@@ -188,8 +200,9 @@ abstract class AbstractAnnotationDeserializer(
val symbol = lookupTag.toSymbol(session)
val firAnnotationClass = (symbol as? FirRegularClassSymbol)?.fir ?: return@lazy null
val classScope = firAnnotationClass.defaultType().scope(session, ScopeSession(), FakeOverrideTypeCalculator.DoNothing)
?: error("Null scope for $classId")
val classScope =
firAnnotationClass.defaultType().scope(session, ScopeSession(), FakeOverrideTypeCalculator.DoNothing)
?: error("Null scope for $classId")
val constructor =
classScope.getDeclaredConstructors().singleOrNull()?.fir ?: error("No single constructor found for $classId")
@@ -197,28 +210,11 @@ abstract class AbstractAnnotationDeserializer(
constructor.valueParameters.associateBy { it.name }
}
arguments = proto.argumentList.mapNotNull {
proto.argumentList.mapNotNull {
val name = nameResolver.getName(it.nameId)
val value = resolveValue(it.value, nameResolver) { parameterByName?.get(name)?.returnTypeRef?.coneType }
buildNamedArgumentExpression {
expression = value
isSpread = false
this.name = name
}
}
}
return buildAnnotation {
annotationTypeRef = buildResolvedTypeRef {
type = ConeClassLikeLookupTagImpl(classId).constructClassType(emptyArray(), isNullable = false)
}
argumentList = buildArgumentList {
this.arguments += arguments
}
useSiteTarget?.let {
this.useSiteTarget = it
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
name to value
}.toMap(mapping)
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.varargElementType
@@ -715,12 +716,12 @@ class FirElementSerializer private constructor(
if (existingAnnotations?.any { it.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.classId == classId } != true) {
extension.serializeTypeAnnotation(
buildAnnotation {
calleeReference = FirReferencePlaceholderForResolvedAnnotations
annotationTypeRef = buildResolvedTypeRef {
this.type = CompilerConeAttributes.ExtensionFunctionType.ANNOTATION_CLASS_ID.constructClassLikeType(
emptyArray(), isNullable = false
)
}
argumentMapping = FirEmptyAnnotationArgumentMapping
}, builder
)
}
@@ -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
}
}
}
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
import org.jetbrains.kotlin.fir.lightTree.fir.*
@@ -348,7 +349,7 @@ class DeclarationsConverter(
}
}
val name = (constructorCalleePair.first as? FirUserTypeRef)?.qualifier?.last()?.name ?: Name.special("<no-annotation-name>")
return buildAnnotation {
return buildAnnotationCall {
source = unescapedAnnotation.toFirSourceElement()
useSiteTarget = annotationUseSiteTarget ?: defaultAnnotationUseSiteTarget
annotationTypeRef = constructorCalleePair.first
@@ -2124,7 +2125,7 @@ class DeclarationsConverter(
false
)
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
argumentMapping = FirEmptyAnnotationArgumentMapping
}
private fun <T> fillDanglingConstraintsTo(
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.references.builder.*
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
@@ -1689,7 +1690,7 @@ open class RawFirBuilder(
}
override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry, data: Unit): FirElement {
return buildAnnotation {
return buildAnnotationCall {
source = annotationEntry.toFirSourceElement()
useSiteTarget = annotationEntry.useSiteTarget?.getAnnotationUseSiteTarget()
annotationTypeRef = annotationEntry.typeReference.toFirOrErrorType()
@@ -2426,10 +2427,7 @@ open class RawFirBuilder(
isNullable = false
)
}
// TODO: actually we know where to resolve, but we don't have any symbol providers at this point
calleeReference = buildSimpleNamedReference {
name = Name.identifier("ExtensionFunctionType")
}
argumentMapping = FirEmptyAnnotationArgumentMapping
}
}
@@ -14,12 +14,12 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.has
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.plugin.fqn
import org.jetbrains.kotlin.fir.references.impl.FirReferencePlaceholderForResolvedAnnotations
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.GeneratedClass
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -56,7 +56,7 @@ class AllOpenRecursiveNestedClassGenerator(session: FirSession) : FirDeclaration
isNullable = false
)
}
calleeReference = FirReferencePlaceholderForResolvedAnnotations
argumentMapping = FirEmptyAnnotationArgumentMapping
}
}
return listOf(GeneratedDeclaration(newClass, owner))