square / anvil

A Kotlin compiler plugin to make dependency injection with Dagger 2 easier.
Apache License 2.0
1.32k stars 82 forks source link

Support Dagger KSP in Anvil #704

Open ZacSweers opened 1 year ago

ZacSweers commented 1 year ago

Filing an issue for posterity/tracking. I'm planning to take a stab at this.

Pasting what I wrote in kotlin-lang here: https://kotlinlang.slack.com/archives/C013BA8EQSE/p1669155272374909


With Dagger’s upcoming support for KSP, we should make Anvil work with this new pattern

It’s a bit tricky, as it has always worked up to this point by running a special IR plugin during kapt stub generation to modify/add annotations to certain classes for Dagger’s use in kapt. Obviously that won’t work in a KSP world since it’s all one task.

What I’m thinking currently is something clever like this: Anvil exposes its own delegating SymbolProcessor that handles running Dagger’s. It would then decorate KSP’s Resolver APIs to intercept them and add this metadata (annotations, etc) to the KSP types on their way through.

So for example, this type

@MergeComponent(...)
interface AppComponent

This processor would then intercept that and construct a new KSClassDeclaration that almost entirely mirrors the previous except that it adds the merged @Component annotation that anvil synthesizes instead.

Lastly, when resolving annotated elements, it would intercept searches for Component types and forward the request as a @MergeComponent request instead.

Same patterns would be used for merged modules.

While weird and obviously not something KSP could officially support, I do think this could work more or less entirely within the bounds of KSP’s public API.

ZacSweers commented 1 year ago

I think an initial start to this may require limiting Anvil to only running in a separate compilation. Anvil supports generating more sources and incurring subsequent rounds, but it's not totally clear if that will be possible while running under KSP, because this information would need to be conveyed to KSP and delay the component processing to a later round.

galex commented 5 months ago

I think an initial start to this may require limiting Anvil to only running in a separate compilation. Anvil supports generating more sources and incurring subsequent rounds, but it's not totally clear if that will be possible while running under KSP, because this information would need to be conveyed to KSP and delay the component processing to a later round.

Wouldn't this break the compiler-api whole idea of generating code? 😨

ZacSweers commented 5 months ago

Yes and no. A lot of this boils down to "are you doing component merging in this round". If you are, that ordering requirement comes into play. I'm not really sure if/how dagger handles this in javac either. In factory/contributor generation only though, then it doesn't really matter. The "API" in this case is to just use KSP itself.