[AA FIR] fix contract violation for Target annotation

^KT-57849
This commit is contained in:
Dmitrii Gridin
2023-04-11 18:13:21 +02:00
committed by Space Team
parent d66b919c12
commit 0caaca45ae
8 changed files with 195 additions and 13 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.api.fir
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationInfo
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
import org.jetbrains.kotlin.analysis.api.fir.annotations.mapAnnotationParameters
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
@@ -71,14 +72,15 @@ internal fun ConeDiagnostic.getCandidateSymbols(): Collection<FirBasedSymbol<*>>
internal fun FirAnnotation.toKtAnnotationApplication(
useSiteSession: FirSession,
index: Int,
arguments: List<KtNamedAnnotationValue> = FirAnnotationValueConverter.toNamedConstantValue(
mapAnnotationParameters(this),
useSiteSession,
)
): KtAnnotationApplicationWithArgumentsInfo = KtAnnotationApplicationWithArgumentsInfo(
classId = toAnnotationClassId(useSiteSession),
psi = psi as? KtCallElement,
useSiteTarget = useSiteTarget,
arguments = FirAnnotationValueConverter.toNamedConstantValue(
mapAnnotationParameters(this),
useSiteSession,
),
arguments = arguments,
index = index,
)
@@ -8,13 +8,18 @@ package org.jetbrains.kotlin.analysis.api.fir.annotations
import org.jetbrains.kotlin.analysis.api.annotations.AnnotationUseSiteTargetFilter
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationInfo
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo
import org.jetbrains.kotlin.analysis.api.annotations.KtArrayAnnotationValue
import org.jetbrains.kotlin.analysis.api.annotations.KtEnumEntryAnnotationValue
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
import org.jetbrains.kotlin.analysis.api.fir.toKtAnnotationApplication
import org.jetbrains.kotlin.analysis.api.fir.toKtAnnotationInfo
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withFirEntry
import org.jetbrains.kotlin.analysis.utils.errors.checkWithAttachmentBuilder
import org.jetbrains.kotlin.analysis.utils.errors.withClassEntry
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.resolved
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
@@ -31,6 +36,13 @@ import org.jetbrains.kotlin.fir.symbols.resolvedCompilerRequiredAnnotations
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.fir.declarations.resolvePhase
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.unwrapAndFlattenArgument
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
internal fun mapAnnotationParameters(annotation: FirAnnotation): Map<Name, FirExpression> {
if (annotation is FirAnnotationCall && annotation.arguments.isEmpty()) return emptyMap()
@@ -50,13 +62,72 @@ internal fun annotationsByClassId(
useSiteTargetFilter: AnnotationUseSiteTargetFilter,
useSiteSession: FirSession,
annotationContainer: FirAnnotationContainer = firSymbol.fir,
): List<KtAnnotationApplicationWithArgumentsInfo> {
return annotationContainer.resolvedAnnotationsWithArguments(firSymbol).mapIndexedNotNull { index, annotation ->
if (!useSiteTargetFilter.isAllowed(annotation.useSiteTarget) || annotation.toAnnotationClassId(useSiteSession) != classId) {
return@mapIndexedNotNull null
}
): List<KtAnnotationApplicationWithArgumentsInfo> =
if (classId == StandardClassIds.Annotations.Target && firSymbol.fir.resolvePhase < FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING) {
annotationContainer.resolvedAnnotationsWithClassIds(firSymbol)
.mapIndexedToAnnotationApplication(useSiteTargetFilter, useSiteSession, classId) { index, annotation ->
annotation.asKtAnnotationApplicationForTargetAnnotation(useSiteSession, index)
}
} else {
annotationContainer.resolvedAnnotationsWithArguments(firSymbol)
.mapIndexedToAnnotationApplication(useSiteTargetFilter, useSiteSession, classId) { index, annotation ->
annotation.toKtAnnotationApplication(useSiteSession, index)
}
}
annotation.toKtAnnotationApplication(useSiteSession, index)
private inline fun List<FirAnnotation>.mapIndexedToAnnotationApplication(
useSiteTargetFilter: AnnotationUseSiteTargetFilter,
useSiteSession: FirSession,
classId: ClassId,
transformer: (index: Int, annotation: FirAnnotation) -> KtAnnotationApplicationWithArgumentsInfo?,
): List<KtAnnotationApplicationWithArgumentsInfo> = mapIndexedNotNull { index, annotation ->
if (!useSiteTargetFilter.isAllowed(annotation.useSiteTarget) || annotation.toAnnotationClassId(useSiteSession) != classId) {
return@mapIndexedNotNull null
}
transformer(index, annotation)
}
private fun FirAnnotation.asKtAnnotationApplicationForTargetAnnotation(
useSiteSession: FirSession,
index: Int,
): KtAnnotationApplicationWithArgumentsInfo {
val arguments = findAllowedTargets().ifNotEmpty {
listOf(
KtNamedAnnotationValue(
name = StandardClassIds.Annotations.ParameterNames.targetAllowedTargets,
expression = KtArrayAnnotationValue(
values = map {
KtEnumEntryAnnotationValue(
callableId = CallableId(
classId = StandardClassIds.AnnotationTarget,
callableName = Name.identifier(it.name),
),
sourcePsi = null,
)
},
sourcePsi = null,
)
)
)
}.orEmpty()
return toKtAnnotationApplication(useSiteSession, index, arguments)
}
private fun FirAnnotation.findAllowedTargets(): Set<KotlinTarget> = buildSet {
fun addIfMatching(arg: FirExpression) {
if (arg !is FirQualifiedAccessExpression) return
val callableSymbol = arg.calleeReference.toResolvedCallableSymbol() ?: return
if (callableSymbol.containingClassLookupTag()?.classId != StandardClassIds.AnnotationTarget) return
val identifier = callableSymbol.callableId.callableName.identifier
KotlinTarget.values().firstOrNull { identifier == it.name }?.let(::add)
}
if (this@findAllowedTargets is FirAnnotationCall) {
for (arg in argumentList.arguments) {
arg.unwrapAndFlattenArgument().forEach(::addIfMatching)
}
}
}