From c1feea092dd18a5f4102e61613d0fc977d9148ef Mon Sep 17 00:00:00 2001 From: Jiaxiang Chen Date: Fri, 4 Nov 2022 10:37:11 -0700 Subject: [PATCH] AA: support java annotation argument evaluation --- .../impl/symbol/java/KSAnnotationJavaImpl.kt | 180 ++++++++++++++++++ .../symbol/java/KSValueArgumentLiteImpl.kt | 36 ++++ .../kotlin/AbstractKSDeclarationImpl.kt | 10 +- .../impl/symbol/kotlin/KSAnnotationImpl.kt | 68 +++---- .../kotlin/KSFunctionDeclarationImpl.kt | 8 + .../impl/symbol/kotlin/KSValueArgumentImpl.kt | 9 +- .../devtools/ksp/impl/symbol/kotlin/util.kt | 73 +++++++ .../devtools/ksp/impl/test/KSPAATest.kt | 1 - 8 files changed, 346 insertions(+), 39 deletions(-) create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt create mode 100644 kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSValueArgumentLiteImpl.kt diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt new file mode 100644 index 0000000000..d45733a270 --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSAnnotationJavaImpl.kt @@ -0,0 +1,180 @@ +package com.google.devtools.ksp.impl.symbol.java + +import com.google.devtools.ksp.KSObjectCache +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.impl.ResolverAAImpl +import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeImpl +import com.google.devtools.ksp.impl.symbol.kotlin.KSTypeReferenceImpl +import com.google.devtools.ksp.impl.symbol.kotlin.KSValueArgumentImpl +import com.google.devtools.ksp.impl.symbol.kotlin.analyze +import com.google.devtools.ksp.impl.symbol.kotlin.classifierSymbol +import com.google.devtools.ksp.impl.symbol.kotlin.getDefaultValue +import com.google.devtools.ksp.impl.symbol.kotlin.toKSDeclaration +import com.google.devtools.ksp.impl.symbol.kotlin.toKtClassSymbol +import com.google.devtools.ksp.impl.symbol.kotlin.toLocation +import com.google.devtools.ksp.processing.impl.KSNameImpl +import com.google.devtools.ksp.symbol.AnnotationUseSiteTarget +import com.google.devtools.ksp.symbol.ClassKind +import com.google.devtools.ksp.symbol.KSAnnotation +import com.google.devtools.ksp.symbol.KSClassDeclaration +import com.google.devtools.ksp.symbol.KSName +import com.google.devtools.ksp.symbol.KSNode +import com.google.devtools.ksp.symbol.KSTypeReference +import com.google.devtools.ksp.symbol.KSValueArgument +import com.google.devtools.ksp.symbol.KSVisitor +import com.google.devtools.ksp.symbol.Location +import com.google.devtools.ksp.symbol.Origin +import com.intellij.lang.jvm.JvmClassKind +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiAnnotationMemberValue +import com.intellij.psi.PsiArrayInitializerMemberValue +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiField +import com.intellij.psi.PsiLiteralValue +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiType +import com.intellij.psi.impl.source.PsiAnnotationMethodImpl +import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue +import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin +import org.jetbrains.kotlin.analysis.api.types.KtType +import org.jetbrains.kotlin.name.ClassId + +class KSAnnotationJavaImpl private constructor(private val psi: PsiAnnotation) : KSAnnotation { + companion object : KSObjectCache() { + fun getCached(psi: PsiAnnotation) = + KSAnnotationJavaImpl.cache.getOrPut(psi) { KSAnnotationJavaImpl(psi) } + } + + private val type: KtType by lazy { + (ResolverAAImpl.instance.getClassDeclarationByName(psi.qualifiedName!!)!!.asStarProjectedType() as KSTypeImpl) + .type + } + + override val annotationType: KSTypeReference by lazy { + KSTypeReferenceImpl.getCached(type, this) + } + + override val arguments: List by lazy { + val annotationConstructor = analyze { + (type.classifierSymbol() as KtClassOrObjectSymbol).getMemberScope().getConstructors().singleOrNull() + } + val presentArgs = psi.parameterList.attributes.mapIndexed { index, it -> + val name = it.name ?: annotationConstructor?.valueParameters?.getOrNull(index)?.name?.asString() + val value = it.value + val calculatedValue: Any? = if (value is PsiArrayInitializerMemberValue) { + value.initializers.map { + calcValue(it) + } + } else { + calcValue(it.value) + } + KSValueArgumentLiteImpl.getCached( + name?.let { KSNameImpl.getCached(it) }, + calculatedValue, + Origin.JAVA + ) + } + val presentValueArgumentNames = presentArgs.map { it.name?.asString() ?: "" } + presentArgs + defaultArguments.filter { it.name?.asString() !in presentValueArgumentNames } + } + + override val defaultArguments: List by lazy { + analyze { + (type.classifierSymbol() as KtClassOrObjectSymbol).getMemberScope().getConstructors().singleOrNull() + ?.let { symbol -> + if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) { + (symbol.psi as PsiClass).allMethods.filterIsInstance() + .mapNotNull { annoMethod -> + annoMethod.defaultValue?.let { + KSValueArgumentLiteImpl.getCached( + KSNameImpl.getCached(annoMethod.name), + calcValue(it), + Origin.SYNTHETIC + ) + } + } + } else { + symbol.valueParameters.mapNotNull { valueParameterSymbol -> + valueParameterSymbol.getDefaultValue()?.let { constantValue -> + KSValueArgumentImpl.getCached( + KtNamedAnnotationValue( + valueParameterSymbol.name, constantValue, + ), + Origin.SYNTHETIC + ) + } + } + } + } + } ?: emptyList() + } + + override val shortName: KSName by lazy { + KSNameImpl.getCached(psi.qualifiedName!!.split(".").last()) + } + + override val useSiteTarget: AnnotationUseSiteTarget? = null + + override val origin: Origin = Origin.JAVA + + override val location: Location + get() = psi.toLocation() + + override val parent: KSNode? + get() = TODO("Not yet implemented") + + override fun accept(visitor: KSVisitor, data: D): R { + return visitor.visitAnnotation(this, data) + } + + override fun toString(): String { + return "@${shortName.asString()}" + } +} + +fun calcValue(value: PsiAnnotationMemberValue?): Any? { + if (value is PsiAnnotation) { + return KSAnnotationJavaImpl.getCached(value) + } + val result = when (value) { + is PsiReference -> value.resolve()?.let { resolved -> + JavaPsiFacade.getInstance(value.project).constantEvaluationHelper.computeConstantExpression(value) + ?: resolved + } + else -> value?.let { + JavaPsiFacade.getInstance(value.project).constantEvaluationHelper.computeConstantExpression(value) + } + } + return when (result) { + is PsiType -> { + analyze { + (ClassId.fromString(result.canonicalText).toKtClassSymbol()?.toKSDeclaration() as? KSClassDeclaration) + ?.asStarProjectedType() + } + } + is PsiLiteralValue -> { + result.value + } + is PsiField -> { + // manually handle enums as constant expression evaluator does not seem to be resolving them. + val containingClass = result.containingClass + if (containingClass?.classKind == JvmClassKind.ENUM) { + // this is an enum entry + containingClass.qualifiedName?.let { + ResolverAAImpl.instance!!.getClassDeclarationByName(it) + }?.declarations?.find { + it is KSClassDeclaration && it.classKind == ClassKind.ENUM_ENTRY && + it.simpleName.asString() == result.name + }?.let { (it as KSClassDeclaration).asStarProjectedType() } + ?.let { + return it + } + } else { + null + } + } + else -> result + } +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSValueArgumentLiteImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSValueArgumentLiteImpl.kt new file mode 100644 index 0000000000..cb952a5a8c --- /dev/null +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/java/KSValueArgumentLiteImpl.kt @@ -0,0 +1,36 @@ +package com.google.devtools.ksp.impl.symbol.java + +import com.google.devtools.ksp.IdKeyPair +import com.google.devtools.ksp.KSObjectCache +import com.google.devtools.ksp.symbol.KSAnnotation +import com.google.devtools.ksp.symbol.KSName +import com.google.devtools.ksp.symbol.KSNode +import com.google.devtools.ksp.symbol.KSValueArgument +import com.google.devtools.ksp.symbol.KSVisitor +import com.google.devtools.ksp.symbol.Location +import com.google.devtools.ksp.symbol.Origin + +class KSValueArgumentLiteImpl private constructor( + override val name: KSName?, + override val value: Any?, + override val origin: Origin +) : KSValueArgument { + companion object : KSObjectCache, KSValueArgumentLiteImpl>() { + fun getCached(name: KSName?, value: Any?, origin: Origin) = + KSValueArgumentLiteImpl.cache + .getOrPut(IdKeyPair(name, value)) { KSValueArgumentLiteImpl(name, value, origin) } + } + override val isSpread: Boolean = false + + override val annotations: Sequence = emptySequence() + + override val location: Location + get() = TODO("Not yet implemented") + + override val parent: KSNode? + get() = TODO("Not yet implemented") + + override fun accept(visitor: KSVisitor, data: D): R { + return visitor.visitValueArgument(this, data) + } +} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt index 023a9b782b..3ad1ad035c 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/AbstractKSDeclarationImpl.kt @@ -16,6 +16,7 @@ */ package com.google.devtools.ksp.impl.symbol.kotlin +import com.google.devtools.ksp.impl.symbol.java.KSAnnotationJavaImpl import com.google.devtools.ksp.processing.impl.KSNameImpl import com.google.devtools.ksp.symbol.KSAnnotation import com.google.devtools.ksp.symbol.KSDeclaration @@ -27,12 +28,14 @@ import com.google.devtools.ksp.symbol.Location import com.google.devtools.ksp.symbol.Modifier import com.google.devtools.ksp.symbol.Origin import com.google.devtools.ksp.toKSModifiers +import com.intellij.psi.PsiJvmModifiersOwner import com.intellij.psi.PsiModifierListOwner import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol +import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtModifierListOwner abstract class AbstractKSDeclarationImpl(val ktDeclarationSymbol: KtDeclarationSymbol) : KSDeclaration { @@ -98,5 +101,10 @@ abstract class AbstractKSDeclarationImpl(val ktDeclarationSymbol: KtDeclarationS override val docString: String? get() = ktDeclarationSymbol.toDocString() - internal val originalAnnotations = ktDeclarationSymbol.annotations(this) + internal val originalAnnotations = if (ktDeclarationSymbol.psi is KtElement || ktDeclarationSymbol.psi == null) { + ktDeclarationSymbol.annotations(this) + } else { + (ktDeclarationSymbol.psi as PsiJvmModifiersOwner) + .annotations.map { KSAnnotationJavaImpl.getCached(it) }.asSequence() + } } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt index b7468870d0..4fb30e4a4a 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSAnnotationImpl.kt @@ -19,17 +19,17 @@ package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.IdKeyPair import com.google.devtools.ksp.KSObjectCache +import com.google.devtools.ksp.impl.symbol.java.KSValueArgumentLiteImpl +import com.google.devtools.ksp.impl.symbol.java.calcValue import com.google.devtools.ksp.processing.impl.KSNameImpl import com.google.devtools.ksp.symbol.* +import com.intellij.psi.PsiClass +import com.intellij.psi.impl.source.PsiAnnotationMethodImpl import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationApplicationWithArgumentsInfo -import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue -import org.jetbrains.kotlin.analysis.api.base.KtConstantValue -import org.jetbrains.kotlin.analysis.api.components.KtConstantEvaluationMode import org.jetbrains.kotlin.analysis.api.components.buildClassType -import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.* -import org.jetbrains.kotlin.psi.KtParameter class KSAnnotationImpl private constructor( private val annotationApplication: KtAnnotationApplicationWithArgumentsInfo, @@ -47,31 +47,46 @@ class KSAnnotationImpl private constructor( } override val arguments: List by lazy { - val presentArgs = annotationApplication.arguments.map { KSValueArgumentImpl.getCached(it) } + val presentArgs = annotationApplication.arguments.map { KSValueArgumentImpl.getCached(it, Origin.KOTLIN) } val presentNames = presentArgs.mapNotNull { it.name?.asString() } - val absentArgs = analyze { + val absentArgs = defaultArguments.filter { + it.name?.asString() !in presentNames + } + presentArgs + absentArgs + } + + override val defaultArguments: List by lazy { + analyze { annotationApplication.classId?.toKtClassSymbol()?.let { symbol -> - symbol.getMemberScope().getConstructors().singleOrNull()?.let { - it.valueParameters.filter { valueParameter -> - valueParameter.name.asString() !in presentNames - }.mapNotNull { valueParameterSymbol -> - valueParameterSymbol.getDefaultValue()?.let { constantValue -> - KSValueArgumentImpl.getCached( - KtNamedAnnotationValue( - valueParameterSymbol.name, KtConstantAnnotationValue(constantValue) + if (symbol.origin == KtSymbolOrigin.JAVA && symbol.psi != null) { + (symbol.psi as PsiClass).allMethods.filterIsInstance() + .mapNotNull { annoMethod -> + annoMethod.defaultValue?.let { + KSValueArgumentLiteImpl.getCached( + KSNameImpl.getCached(annoMethod.name), + calcValue(it), + Origin.SYNTHETIC + ) + } + } + } else { + symbol.getMemberScope().getConstructors().singleOrNull()?.let { + it.valueParameters.mapNotNull { valueParameterSymbol -> + valueParameterSymbol.getDefaultValue()?.let { constantValue -> + KSValueArgumentImpl.getCached( + KtNamedAnnotationValue( + valueParameterSymbol.name, constantValue, + ), + Origin.SYNTHETIC ) - ) + } } } } - } ?: emptyList() + } ?: emptyList() } - presentArgs + absentArgs } - override val defaultArguments: List - get() = TODO("Not yet implemented") - override val shortName: KSName by lazy { KSNameImpl.getCached(annotationApplication.classId!!.shortClassName.asString()) } @@ -105,14 +120,3 @@ class KSAnnotationImpl private constructor( return "@${shortName.asString()}" } } - -internal fun KtValueParameterSymbol.getDefaultValue(): KtConstantValue? { - return this.psi?.let { - when (it) { - is KtParameter -> analyze { - it.defaultValue?.evaluate(KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION) - } - else -> throw IllegalStateException("Unhandled default value type ${it.javaClass}") - } - } -} diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt index 2ea5eace19..76fe8b1981 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSFunctionDeclarationImpl.kt @@ -119,6 +119,14 @@ class KSFunctionDeclarationImpl private constructor(internal val ktFunctionSymbo (origin == Origin.JAVA && ktFunctionSymbol.psi == null || ktFunctionSymbol.psi is PsiClass) } + override val annotations: Sequence by lazy { + if (isSyntheticConstructor()) { + emptySequence() + } else { + super.annotations + } + } + override fun toString(): String { // TODO: fix origin for implicit Java constructor in AA // TODO: should we change the toString() behavior for synthetic constructors? diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt index 719e181218..301606d50a 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/KSValueArgumentImpl.kt @@ -30,11 +30,12 @@ import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue class KSValueArgumentImpl private constructor( - private val namedAnnotationValue: KtNamedAnnotationValue + private val namedAnnotationValue: KtNamedAnnotationValue, + override val origin: Origin ) : KSValueArgument { companion object : KSObjectCache() { - fun getCached(namedAnnotationValue: KtNamedAnnotationValue) = - cache.getOrPut(namedAnnotationValue) { KSValueArgumentImpl(namedAnnotationValue) } + fun getCached(namedAnnotationValue: KtNamedAnnotationValue, origin: Origin) = + cache.getOrPut(namedAnnotationValue) { KSValueArgumentImpl(namedAnnotationValue, origin) } } override val name: KSName? by lazy { @@ -47,8 +48,6 @@ class KSValueArgumentImpl private constructor( override val annotations: Sequence = emptySequence() - override val origin: Origin = Origin.KOTLIN - override val location: Location by lazy { namedAnnotationValue.expression.sourcePsi?.toLocation() ?: NonExistLocation } diff --git a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt index f818359ced..80dd044a91 100644 --- a/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt +++ b/kotlin-analysis-api/src/main/kotlin/com/google/devtools/ksp/impl/symbol/kotlin/util.kt @@ -15,6 +15,7 @@ * limitations under the License. */ +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") package com.google.devtools.ksp.impl.symbol.kotlin import com.google.devtools.ksp.ExceptionMessage @@ -31,16 +32,32 @@ import org.jetbrains.kotlin.analysis.api.KtTypeArgumentWithVariance import org.jetbrains.kotlin.analysis.api.KtTypeProjection import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.annotations.* +import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter +import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirValueParameterSymbol import org.jetbrains.kotlin.analysis.api.lifetime.KtAlwaysAccessibleLifetimeToken import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers import org.jetbrains.kotlin.analysis.api.types.* import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack +import org.jetbrains.kotlin.fir.java.toFirExpression +import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument +import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaAnnotationVisitor +import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments +import org.jetbrains.org.objectweb.asm.AnnotationVisitor +import org.jetbrains.org.objectweb.asm.ClassReader +import org.jetbrains.org.objectweb.asm.ClassVisitor +import org.jetbrains.org.objectweb.asm.MethodVisitor +import org.jetbrains.org.objectweb.asm.Opcodes internal val ktSymbolOriginToOrigin = mapOf( KtSymbolOrigin.JAVA to Origin.JAVA, @@ -373,3 +390,59 @@ internal inline fun KSNode.findParentOfType(): KSNode? { } return result } + +@OptIn(SymbolInternals::class) +internal fun KtValueParameterSymbol.getDefaultValue(): KtAnnotationValue? { + return this.psi.let { + when (it) { + is KtParameter -> analyze { + it.defaultValue?.evaluateAsAnnotationValue() + } + null -> { + val fileManager = ResolverAAImpl.instance.javaFileManager + val parentClass = this.getContainingKSSymbol()!!.findParentOfType() + val classId = (parentClass as KSClassDeclarationImpl).ktClassOrObjectSymbol.classIdIfNonLocal!! + val file = analyze { + (fileManager.findClass(classId, analysisScope) as JavaClassImpl).virtualFile!!.contentsToByteArray() + } + var defaultValue: JavaAnnotationArgument? = null + ClassReader(file).accept( + object : ClassVisitor(Opcodes.API_VERSION) { + override fun visitMethod( + access: Int, + name: String?, + desc: String?, + signature: String?, + exceptions: Array? + ): MethodVisitor { + return if (name == this@getDefaultValue.name.asString()) { + object : MethodVisitor(Opcodes.API_VERSION) { + override fun visitAnnotationDefault(): AnnotationVisitor = + BinaryJavaAnnotationVisitor( + ClassifierResolutionContext { null }, + BinaryClassSignatureParser() + ) { + defaultValue = it + } + } + } else { + object : MethodVisitor(Opcodes.API_VERSION) {} + } + } + }, + ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES + ) + (this as? KtFirValueParameterSymbol)?.let { + val firSession = it.firSymbol.fir.moduleData.session + val expectedTypeRef = it.firSymbol.fir.returnTypeRef + val expression = defaultValue + ?.toFirExpression(firSession, JavaTypeParameterStack.EMPTY, expectedTypeRef) + expression?.let { + FirAnnotationValueConverter.toConstantValue(expression, firSession) + } + } + } + else -> throw IllegalStateException("Unhandled default value type ${it.javaClass}") + } + } +} diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt index fa579872c1..3ffc834f8f 100644 --- a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/impl/test/KSPAATest.kt @@ -29,7 +29,6 @@ import org.junit.jupiter.api.parallel.ExecutionMode @DisabledOnOs(OS.WINDOWS) class KSPAATest : AbstractKSPAATest() { - @Disabled @TestMetadata("annotatedUtil.kt") @Test fun testAnnotatedUtil() {