Skip to content

Commit

Permalink
fix annotation default value parsing for arrays and class literals.
Browse files Browse the repository at this point in the history
  • Loading branch information
neetopia committed May 7, 2024
1 parent f690aea commit e625afc
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 12 deletions.
Expand Up @@ -96,9 +96,17 @@ class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation, o
(symbol.psi as PsiClass).allMethods.filterIsInstance<PsiAnnotationMethodImpl>()
.mapNotNull { annoMethod ->
annoMethod.defaultValue?.let {
val value = it
val calculatedValue: Any? = if (value is PsiArrayInitializerMemberValue) {
value.initializers.map {
calcValue(it)
}
} else {
calcValue(it)
}
KSValueArgumentLiteImpl.getCached(
KSNameImpl.getCached(annoMethod.name),
calcValue(it),
calculatedValue,
Origin.SYNTHETIC
)
}
Expand Down
Expand Up @@ -26,6 +26,7 @@ import com.google.devtools.ksp.impl.symbol.java.calcValue
import com.google.devtools.ksp.impl.symbol.kotlin.resolved.KSTypeReferenceResolvedImpl
import com.google.devtools.ksp.symbol.*
import com.intellij.psi.PsiAnnotationMethod
import com.intellij.psi.PsiArrayInitializerMemberValue
import com.intellij.psi.PsiClass
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
Expand Down Expand Up @@ -76,10 +77,17 @@ class KSAnnotationImpl private constructor(
if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) {
(symbol.psi as PsiClass).allMethods.filterIsInstance<PsiAnnotationMethod>()
.mapNotNull { annoMethod ->
annoMethod.defaultValue?.let {
annoMethod.defaultValue?.let { value ->
val calculatedValue: Any? = if (value is PsiArrayInitializerMemberValue) {
value.initializers.map {
calcValue(it)
}
} else {
calcValue(value)
}
KSValueArgumentLiteImpl.getCached(
KSNameImpl.getCached(annoMethod.name),
calcValue(it),
calculatedValue,
Origin.SYNTHETIC
)
}
Expand All @@ -92,7 +100,7 @@ class KSAnnotationImpl private constructor(
KtNamedAnnotationValue(
valueParameterSymbol.name,
constantValue,
KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project!!)
KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project)
),
Origin.SYNTHETIC
)
Expand Down
Expand Up @@ -78,9 +78,7 @@ class KSValueArgumentImpl private constructor(
} ?: KSErrorType
// TODO: handle local classes.
is KtKClassAnnotationValue -> {
val classDeclaration =
(this@toValue.classId?.toKtClassSymbol())?.let { KSClassDeclarationImpl.getCached(it) }
classDeclaration?.asStarProjectedType() ?: KSErrorType
KSTypeImpl.getCached(this@toValue.type)
}
is KtConstantAnnotationValue -> this.constantValue.value
is KtUnsupportedAnnotationValue -> null
Expand Down
Expand Up @@ -16,6 +16,8 @@
*/

@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@file:OptIn(KtAnalysisApiInternals::class, KtAnalysisApiInternals::class)

package com.google.devtools.ksp.impl.symbol.kotlin

import com.google.devtools.ksp.ExceptionMessage
Expand All @@ -29,6 +31,7 @@ import com.google.devtools.ksp.impl.symbol.util.getDocString
import com.google.devtools.ksp.symbol.*
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiJavaFile
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance
Expand All @@ -38,6 +41,7 @@ import org.jetbrains.kotlin.analysis.api.annotations.*
import org.jetbrains.kotlin.analysis.api.components.KtSubstitutorBuilder
import org.jetbrains.kotlin.analysis.api.components.buildClassType
import org.jetbrains.kotlin.analysis.api.components.buildTypeParameterType
import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirValueParameterSymbol
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
Expand All @@ -50,9 +54,20 @@ import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
import org.jetbrains.kotlin.fir.declarations.getTargetType
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirArrayLiteral
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.toFirExpression
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.isAny
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
Expand Down Expand Up @@ -416,6 +431,43 @@ internal inline fun <reified T : KSNode> KSNode.findParentOfType(): KSNode? {

@OptIn(SymbolInternals::class)
internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? {
fun FirExpression.toValue(builder: KtSymbolByFirBuilder): KtAnnotationValue? {
if (this is FirAnnotation) {
return KtAnnotationApplicationValue(
KtAnnotationApplicationWithArgumentsInfo(
ClassId.fromString((annotationTypeRef.coneType as? ConeLookupTagBasedType)?.lookupTag.toString()),
null,
null,
emptyList(),
0,
null,
KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project)
),
KtAlwaysAccessibleLifetimeToken(ResolverAAImpl.ktModule.project)
)
}
if (this is FirArrayLiteral) {
return KtArrayAnnotationValue(argumentList.arguments.mapNotNull { it.toValue(builder) }, null, token)
}
return if (this is FirGetClassCall) {
var coneType = this.getTargetType()?.fullyExpandedType(builder.rootSession)
// FirAnnotationValueConverter expects fir type, while the type parsed from libraries are modeled
// as flexible type, for it to be used in argument of KClass values, it needs to be unwrapped.
if (coneType is ConeFlexibleType) {
coneType = coneType.lowerBound
}

if (coneType is ConeClassLikeType && coneType !is ConeErrorType) {
val classId = coneType.lookupTag.classId
val type = builder.typeBuilder.buildKtType(coneType)
KtKClassAnnotationValue(type, classId, null, token)
} else {
null
}
} else {
FirAnnotationValueConverter.toConstantValue(this, builder)
}
}
return this.psi.let {
when (it) {
is KtParameter -> analyze {
Expand Down Expand Up @@ -461,9 +513,7 @@ internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? {
val expectedTypeRef = it.firSymbol.fir.returnTypeRef
val expression = defaultValue
?.toFirExpression(firSession, JavaTypeParameterStack.EMPTY, expectedTypeRef, null)
expression?.let {
FirAnnotationValueConverter.toConstantValue(expression, symbolBuilder)
}
expression?.toValue(symbolBuilder)
}
}
else -> throw IllegalStateException("Unhandled default value type ${it.javaClass}")
Expand Down
Expand Up @@ -65,7 +65,6 @@ class KSPAATest : AbstractKSPAATest() {
runTest("../kotlin-analysis-api/testData/allFunctions_kt_inherits_java.kt")
}

@Disabled
@TestMetadata("annotationInDependencies.kt")
@Test
fun testAnnotationsInDependencies() {
Expand All @@ -78,7 +77,6 @@ class KSPAATest : AbstractKSPAATest() {
runTest("../test-utils/testData/api/annotationOnConstructorParameter.kt")
}

@Disabled
@TestMetadata("annotationWithArbitraryClassValue.kt")
@Test
fun testAnnotationWithArbitraryClassValue() {
Expand Down

0 comments on commit e625afc

Please sign in to comment.