tschuchortdev / kotlin-compile-testing

A library for testing Kotlin and Java annotation processors, compiler plugins and code generation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

KSP does not pick up annotations when triggered by compile testing

brizzbuzz opened this issue Β· comments

Hey, very cool library! I am brand new to KSP, so hopefully this is not me doing something dumb πŸ™

It seems as though when KSP is triggered through this library, annotations that are normally scanned as expected simply do not get scanned.

For example, I have an annotation Table

@Retention(AnnotationRetention.SOURCE)
@Target(AnnotationTarget.CLASS)
annotation class Table(val name: String)

I also have a processor which implements process(...) as follows

override fun process(resolver: Resolver): List<KSAnnotated> {
    val symbols = resolver
      .getSymbolsWithAnnotation(Table::class.qualifiedName!!)
      .filterIsInstance<KSClassDeclaration>()

    // processing continues...

In a source code example that I whipped up, this works as expected. I annotate my interface

@Table("user")
interface UserTableSpec : UserSpec {
  // irrelevant code
}

run ksp processing and see that a file is generated in my build dir

Screen Shot 2021-12-28 at 7 13 46 PM

Unfortunately, when I try to run ksp in this library, no annotations get processed at all :(

I have a simple test class

class ExposedProcessorProviderTest : DescribeSpec({
  describe("Testing Testing 123") {
    it("Can do the things") {
      // arrange
      val sourceFile = SourceFile.kotlin("Demo.kt", """
        package test

        import io.bkbn.stoik.exposed.Column
        import io.bkbn.stoik.exposed.Sensitive
        import io.bkbn.stoik.exposed.Table
        import io.bkbn.stoik.exposed.Unique

        sealed interface UserSpec {
          val firstName: String
          val lastName: String
          val email: String
          val password: String
        }

        @Table("user")
        interface UserTableSpec : UserSpec {
          @Column("first_name")
          override val firstName: String

          @Column("last_name")
          override val lastName: String

          @Unique
          override val email: String

          @Sensitive
          override val password: String
        }
      """.trimIndent())
      val compilation = KotlinCompilation().apply {
        sources = listOf(sourceFile)
        symbolProcessorProviders = listOf(ExposedProcessorProvider())
      }

      // act
      val result = compilation.compile()

      // assert
      result shouldNotBe null
      result.generatedFiles shouldHaveSize 1
    }
  }
})

If everything were working as expected, I would get a result.generatedFiles of 1. However, I get 0. I am aware of this bug #129 but it seems like this is a different issue, as I did a debug of the processor, and can see that the annotation is not being picked up at all :(

Screen Shot 2021-12-28 at 7 19 08 PM

There is a lot going on in this pic, but effectively, you can see that the processor is picking up the correct file Demo.kt that does indeed have the correct annotation @Table, yet when you scan the resolver for the annotation, nothing shows up.

Again, hopefully this isn't some dumb error on my part. Thank you to anyone who read thru all this and hope to find a resolution quickly 🀞

System Specs

Kotlin 1.6
KSP 1.6.0-1.0.2
kotlin-compile-testing-ksp 1.4.7

Can you provide a minimal example to reproduce your issue? We have a test for this kind of thing and I've been playing around with it a bit, but I was unable to reproduce the problem you are describing.

Also, can you break at the end of your test and take a look at the temporary folder to see which files were actually generated? I don't know how KSP works since I don't personally use it, but I know that APT does processing in multiple rounds and it may be possible that you just stopped your debugger in the wrong round and it boils down to #129 after all.

Sure, easiest is probably to just clone the repo if you like https://github.com/bkbnio/stoik

The test is here, and I've put out a pull request uncommenting the line that breaks

bkbnio/lerasium#2

documentation is pretty much non-existent in the repo b/c i'm just fiddling around with stuff at the moment, but if you clone it, it should build with just a simple ./gradlew build

We have a test for this kind of thing

could you point me towards that test?? will look thru it and try to see where the differences are :)

Edit: nevermind, assuming it's this one https://github.com/tschuchortdev/kotlin-compile-testing/blob/master/ksp/src/test/kotlin/com/tschuchort/compiletesting/KspTest.kt#L74

Hmmm I just ran that test locally as well, and I don't see any generated code in there either.

The test is not super convincing either, the only thing it asserts is

assertThat(result.exitCode).isEqualTo(ExitCode.OK)

my understanding is that generated source code would be available in {{working-directory}}/ksp/classes, but as you can see from inspecting the temp dir, there are no files generated at all really, all I can see is the original SourceFile AppCode.kt

Screen Shot 2021-12-29 at 3 23 59 PM

oh ho... nevermind, i broke the test, but now I'm really confused... so I had commented out this line

val annotation = SourceFile.kotlin(
            "TestAnnotation.kt", """
            package foo.bar
            annotation class TestAnnotation
        """.trimIndent()
        )

under the impression that just having the source file with the annotation would suffice.

Does this mean that I need to include the actual source code files in the test in order for it to work? Meaning, if I have an actual file in my source code Table that contains the annotation definition, do I need to manually include that in my test "sources"?

Yep, that did the trick... if I copy paste my annotation file into my test a la

val annotationFile = SourceFile.kotlin("Table.kt", """
        package io.bkbn.stoik.exposed

        @Retention(AnnotationRetention.SOURCE)
        @Target(AnnotationTarget.CLASS)
        annotation class Table(val name: String)
      """.trimIndent())

and include that, then the annotation gets processed correctly.

But... there has to be a way around this right? is there a way that I can get the library to pick up the available sources on the classpath? would not be feasible to copy paste every source file for every processor.

The test that I worked with is this one.

I'm afraid I can't really follow your comments. Are you saying that you declared the annotation class in your regular project code (outside tests) and then want to reference it in a KotlinCompilation TestFile? If you set compilation.inheritClassPath to true it should work as you expected.

compilation.inheritClassPath

Aha yep, that is exactly what I need. Thanks so much for your time! It did indeed turn out that I was just missing something :)