https://kotlinlang.org logo
s

Sasha Shpota

01/04/2021, 9:41 AM
Hi all! I need help. I am creating a compiler plugin in which I adjust property declarations if they are annotated with a specific annotation. Problem: I need to filter properties by annotations. At the moment, I have access to
org.jetbrains.kotlin.psi.KtProperty
, form which I need to get annotations. So far, I found a way to do it like this:
Copy code
property.annotationEntries.any {
        it.typeReference
            ?.typeElement
            ?.safeAs<KtUserType>()
            ?.referencedName == "MyAnnotation"
    }
But
referencedName
doesn't return a fully qualified name (
MyAnnotation
instead off
com.example.MyAnnotation
) Question: How to check if a
KtProperty
is annotated with a particular annotation?
👀 2
i

Ilmir Usmanov [JB]

01/12/2021, 10:49 AM
PSI is unresolved parse tree which contains only textual information. If you need type information, use descriptors instead. For example:
Copy code
fun KtProperty.hasMyAnnotation(bindingContext: BindingContext): Boolean {
    val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? PropertyDescriptor ?: return false
    return descriptor.annotations.hasAnnotation(FqName("com.example.MyAnnotation"))
}
s

Sasha Shpota

01/12/2021, 12:33 PM
Thank you @Ilmir Usmanov [JB]. That's pretty much how I solved the issue. At the moment, I override
SyntheticResolveExtension.generateSyntheticProperties
and there, I can iterate over property descriptors. The only issue I have with this, is that it doesn't count annotations declared on properties of data classes. For those, I have to check annotations on constructor parameters.
By the way, could you please suggest me a way to change an annotation definition on a property (I want to change how the annotation was declared)?
i

Ilmir Usmanov [JB]

01/12/2021, 6:26 PM
@Sasha Shpota there is no simple way to change something in descriptors, once they are created. For example, for coroutines we use two versions of `FunctionDescritptor`s - front-end and back-end ones, and store a map from one the the other one in the binding context. So, you should store you changes in either the binding context or somewhere inside your extension during resolve and use it to generate code during codegen. The codegen extension interfaces are ExpressionCodegenExtension, ClassBuilderInterceptorExtension and IrGenerationExtension.
s

Sasha Shpota

01/12/2021, 6:36 PM
Thank you @Ilmir Usmanov [JB]! I will try it out. But I would certainly need some time to process this as the concepts you mention are new to me :)
13 Views