Search code examples
kotlinannotation-processingannotation-processor

Annotation Processor: How to know if a Kotlin class is marked with “internal” visibility modifier from Element


I'm using Auto Service to process some annotations but I'm unable to identify if a Kotlin class has the "internal" visibility modifier from the Annotation Processor API.

I'm using KAPT and Kotlin in the processor. Dependencies:

    implementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: "1.3.0-rc-190"
    implementation files("${System.properties['java.home']}/../lib/tools.jar")
    implementation 'com.squareup:kotlinpoet:1.0.0-RC2'
    implementation "com.google.auto.service:auto-service:1.0-rc4"
    kapt "com.google.auto.service:auto-service:1.0-rc4"

Sample Class:

@MyAnnotation
internal class Car

I got the TypeElement of this inside the process method

override fun process(annotations: MutableSet<out TypeElement>, roundEnv: RoundEnvironment): Boolean {
        roundEnv.getElementsAnnotatedWith(MyAnnotation::class.java).forEach { classElement ->
            if (classElement.kind != ElementKind.CLASS) {
                error(...)
                return true
            }
            classElement as TypeElement

But I don't know how to detect if the class has the "internal" modifier.

If I do: classElement.modifiers I get this: enter image description here

Any idea on how to detect the "internal" modifier?


Solution

  • When your Kotlin code converted to the .class form there is no internal modifier. But when you decompile your .class files of your Kotlin code you see that there is a @Metadata annotation.

    This metadata annotation gives you some information about Kotlin declarations in the binary form. You can use Kotlinx-metadata to read and modify metadata of .class files.

    So, what you need is to get @Metadata annotation from classElement and then use Flags from kotlinx-metadata to find out if it has internal modifier or not:

    for example:

    override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? {
        if (Flag.IS_INTERNAL(flags)) {
            println("function $name is internal")
        }
        ...
    }