https://kotlinlang.org logo
Title
s

Stylianos Gakis

08/04/2022, 4:17 PM
I’m having an annotation that looks like this:
annotation class ComposeRenderer(
  val forComponent: KClass<out Component>,
)
I can’t figure out if it’s be possible to get in some way what the KClass would be to get it’s name, package and if it has any generics, and I am having a hard time looking into the documentation myself in order to help myself basically. And the questions existing online on SOF or whatever are quite sparse for KSP. Is there some place where people tend to go when they have KSP questions that I should be aware of?
m

Matthias Geisler

08/04/2022, 4:23 PM
Yeah the docs have certainly space for improvements. What is your overall goal?
j

jw

08/04/2022, 4:25 PM
In general, everything that can be placed inside an annotation can be read at compile-time.
d

David Rawson

08/04/2022, 9:11 PM
If you can get the
KSAnnotation
then something like the following would work:
val ksType = ksAnnotation.arguments.first { it.name.asString() == "forComponent" }.value as KSType
val declaration = ksType.declaration
val simpleName = declaration.simpleName.asString() // Bar
val packageName = declaration.packageName.asString() // com.example
val typeParameters = declaration.typeParameters // [T]
Note the cast in the first line. If you are willing to use experimental APIs then you could do:
var ksType: KSType? = null
try {
    ksAnnotated.getAnnotationsByType(ComposeRenderer::class).single().forComponent
} catch (e: KSTypeNotPresentException) {
    ksType = e.ksType
}
val declaration = ksType!!.declaration
val simpleName = declaration.simpleName.asString() // Bar etc.
s

Stylianos Gakis

08/05/2022, 6:20 AM
My use case was that initially I was annotating using two annotations one for a “Renderer” and one for a “Component” in order to generate some code which would make use of those. I then figured maybe this can be one annotation and have the renderer simply tell by itself which component it’s about, without relying on naming them similarish in order to hook them together. I saw that all I needed from the Component in my codegen was a
KSClassDeclaration
which I used in order to get exactly the
simpleName
,
packageName
and
typeParameters
. Which I got using a
KSEmptyVisitor<Unit, KSClassDeclaration?>()
. So the
as KSType
did in fact work as it lets me do what I was doing before too. And in fact I don’t need this Visitor either to extract the KSClassDeclaration since I can use KSDeclaration directly. I do feel like I would’ve never figured out I can just do
as KSType
there, but feels like it’s a safe cast in my use case? The message “In general, everything that can be placed inside an annotation can be read at compile-time.” does tell me that in general I should be able to do most of this kind of stuff, just need to search/ask around enough 😅 Thank you a lot for your help, I appreciate it a ton!