[FIR] KT-53371, KT-53519: Fix annotations arguments mapping

See: compiler/testData/asJava/lightClasses/
AnnotatedParameterInInnerClassConstructor.kt

The muted tests don't work with the (KT-53371, KT-53519)-related
changes. During this test happens an attempt to access unresolved
annotations via CustomAnnotationTypeAttribute.
Discussion: KTIJ-23547
This commit is contained in:
Nikolay Lunyak
2022-09-30 19:06:16 +03:00
parent 6653f654ec
commit 89f8821d0a
50 changed files with 670 additions and 186 deletions
@@ -20,13 +20,9 @@ import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtCallElement
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
/**
* Returns `true` if the symbol is for a function named `invoke`.
@@ -72,7 +68,7 @@ internal fun FirAnnotation.toKtAnnotationApplication(useSiteSession: FirSession)
psi as? KtCallElement,
useSiteTarget,
FirAnnotationValueConverter.toNamedConstantValue(
mapAnnotationParameters(this, useSiteSession),
mapAnnotationParameters(this),
useSiteSession,
)
)
@@ -51,7 +51,7 @@ internal class KtFirAnnotationListForDeclaration private constructor(
useSiteSession: FirSession,
token: KtLifetimeToken,
): KtAnnotationsList {
return if (firSymbol.annotations.isEmpty()) {
return if (firSymbol.resolvedAnnotationsWithArguments.isEmpty()) {
KtEmptyAnnotationsList(token)
} else {
KtFirAnnotationListForDeclaration(firSymbol, useSiteSession, token)
@@ -5,88 +5,11 @@
package org.jetbrains.kotlin.analysis.api.fir.annotations
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny
import org.jetbrains.kotlin.fir.declarations.resolved
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildVarargArgumentsExpression
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
internal fun mapAnnotationParameters(annotation: FirAnnotation, session: FirSession): Map<Name, FirExpression> {
// TODO: Alas, argument mapping for annotations on [FirValueParameter] is not properly built, even after BODY_RESOLVE ensured.
// Once fixed, manual building of argument mapping below is redundant. I.e., this util can be as simple as:
// return if (annotation.resolved)
// annotation.argumentMapping.mapping.mapKeys { (name, _) -> name }
// else
// emptyMap()
if (annotation.resolved) return annotation.argumentMapping.mapping.mapKeys { (name, _) -> name }
if (annotation !is FirAnnotationCall) return emptyMap()
val annotationCone = (annotation.annotationTypeRef.coneType as? ConeClassLikeType)?.fullyExpandedType(session)
?: return emptyMap()
val annotationPrimaryCtor = (annotationCone.lookupTag.toSymbol(session)?.fir as? FirRegularClass)?.primaryConstructorIfAny(session)?.fir
val valueParameters = annotationPrimaryCtor?.valueParameters
val (varargValueParameters, nonVarargValueParameters) = valueParameters?.partition { it.isVararg }
?: (emptyList<FirValueParameter>() to emptyList())
val annotationCtorParameterNames = nonVarargValueParameters.map { it.name }
val resultMap = mutableMapOf<Name, FirExpression>()
val namesSequence = annotationCtorParameterNames.asSequence().iterator()
for (argument in annotation.argumentList.arguments.filterIsInstance<FirNamedArgumentExpression>()) {
resultMap[argument.name] = argument.expression
}
val argumentSequence = annotation.argumentList.arguments.asSequence().iterator()
while (namesSequence.hasNext()) {
val name = namesSequence.next()
if (name in resultMap) continue
while (argumentSequence.hasNext()) {
val argument = argumentSequence.next()
if (argument is FirNamedArgumentExpression) continue
resultMap[name] = argument
break
}
}
if (varargValueParameters.isNotEmpty() && argumentSequence.hasNext()) {
val varargValueParameter = varargValueParameters.single()
val arguments = buildList {
while (argumentSequence.hasNext()) {
val argument = argumentSequence.next()
if (argument is FirNamedArgumentExpression) continue
add(argument)
}
}
if (arguments.isNotEmpty()) {
val exp = buildVarargArgumentsExpression {
this.arguments.addAll(arguments)
val firstArgument = arguments.first()
firstArgument.source?.let { source = it.fakeElement(KtFakeSourceElementKind.VarargArgument) }
(varargValueParameter.returnTypeRef as? FirResolvedTypeRef)?.coneType?.varargElementType()?.let {
varargElementType = buildResolvedTypeRef {
source = varargValueParameter.returnTypeRef.source
type = it
}
} ?: firstArgument.typeRef.let {
varargElementType = it
}
}
resultMap[varargValueParameter.name] = exp
}
}
return resultMap
internal fun mapAnnotationParameters(annotation: FirAnnotation): Map<Name, FirExpression> {
assert(annotation.resolved) { "By now the annotations argument mapping should have been resolved" }
return annotation.argumentMapping.mapping.mapKeys { (name, _) -> name }
}