Annotation Processor Function Suspend Modifier?


I’ve been trying to figure out how I can tell if a function I’m processing in my annotation processor has the suspend keyword attached to it or not. I’ve mostly seen posts about looking at Metadata but it seems like that’s only attached to class definitions. I was hoping someone could point me the right direction or an actual example of figuring this out.

  1. Get kotlinx-metadata-jvm library.
  2. Read class functions via functions.
  3. Find the descritptor by JVM method signature.

Just to get the taste of madness, this is fragment from our private codebase:

fun TypeMirror.jvmDescriptor(env: ProcessingContext): String = env.removeProjection(this).let {
    when (this.kind) {
        TypeKind.BOOLEAN -> "Z"
        TypeKind.BYTE -> "B"
        TypeKind.SHORT -> "S"
        TypeKind.INT -> "I"
        TypeKind.LONG -> "J"
        TypeKind.CHAR -> "C"
        TypeKind.FLOAT -> "F"
        TypeKind.DOUBLE -> "D"
        TypeKind.VOID -> "V"
        TypeKind.ARRAY -> "[" + toArrayType().componentType.jvmDescriptor(env)
        TypeKind.DECLARED -> {
            val element = toDeclaredType().asElement() as TypeElement
            val className = ClassName.get(element).jvmName()
        TypeKind.TYPEVAR -> "Ljava/lang/Object;"
        else -> error("kind: ${this.kind} type: $this")

This allows to get jvm func signature by its corresponding TypeMirror

1 Like

Totally agree with the madness part. Annotation processing can get quite complicated. It’s been a while for me but I found that kotlinpoet hase some nice utilities for working with kotlinx-metadata.

1 Like

Ah, thank you for pointing me in the right direction. Yes, annotation processors do get complicated. This is roughly what I did to make the distinction of a function having suspend or not

    import com.squareup.kotlinpoet.metadata.toImmutableKmClass

    private val metadata: Metadata = element.getAnnotation(
    val kmClass = metadata.toImmutableKmClass()
    kmClass.functions.forEach {
                if (Flag.Function.IS_SUSPEND(it.flags)) {
                    println("It has suspend!")