This may be a duplicate of #1684 but I wanted to provide a reproducible example just in case, since that issue seems to have gone stale (and was not reproducible at the time). The sample can be found here: https://github.com/damianw/HiltIncrementality
The sample consists of two Gradle modules:
:app: The application, which is just a single activity with a TextView which toString's theMainActivity.kt.:library: A library which provides multiple implementations of CoffeeMaker using multi-Coffee.kt.The issue has something to do with failing to regenerate code after making changes in library. To
start, build the app from clean:
./gradlew :app:assembleDebug
This should build successfully. Then, uncomment the val water: Water lines from Coffee.kt, and
build :app:assembleDebug again. The expected behavior is that this builds successfully. Instead,
the build will fail with:
/Users/damian/Development/HiltIncrementality/app/build/generated/source/kapt/debug/com/example/hiltincrementality/DaggerApp_HiltComponents_SingletonC.java:61: error: constructor DripCoffeeMaker in class DripCoffeeMaker cannot be applied to given types;
local = new DripCoffeeMaker();
^
required: Water
found: no arguments
reason: actual and formal argument lists differ in length
/Users/damian/Development/HiltIncrementality/app/build/generated/source/kapt/debug/com/example/hiltincrementality/DaggerApp_HiltComponents_SingletonC.java:75: error: constructor PourOverCoffeeMaker in class PourOverCoffeeMaker cannot be applied to given types;
local = new PourOverCoffeeMaker();
^
required: Water
found: no arguments
reason: actual and formal argument lists differ in length
/Users/damian/Development/HiltIncrementality/app/build/generated/source/kapt/debug/com/example/hiltincrementality/DaggerApp_HiltComponents_SingletonC.java:89: error: constructor EspressoCoffeeMaker in class EspressoCoffeeMaker cannot be applied to given types;
local = new EspressoCoffeeMaker();
^
required: Water
found: no arguments
reason: actual and formal argument lists differ in length
Cleaning (either which Gradle or rm -rf app/build) will fix the problem (allowing the app to build
again) at the loss of incrementality. The same problem now exists in reverse, if you were to re-
comment the val water: Water line .
Thanks for the repro sample Damian!
I've enabled kapt verbose and some of javac's processing logs, here is an output of both the first build (successful clean-build.log) and second incremental build (failure incremental-build.log).
The most interesting part here is that kapt in the app recognizes that compiled classes in its dependencies changed (in the library Gradle module), this can be seen in the logs as:
[incremental apt] Changed classpath names: com/example/library/PourOverCoffeeMaker, com/example/library/DripCoffeeMaker_Factory, com/example/library/EspressoCoffeeMaker, com/example/library/DripCoffeeMaker, com/example/library/PourOverCoffeeMaker_Factory, com/example/library/EspressoCoffeeMaker_Factory, com/example/library/DripCoffeeMaker_Factory$InstanceHolder, com/example/library/EspressoCoffeeMaker_Factory$InstanceHolder, com/example/library/PourOverCoffeeMaker_Factory$InstanceHolder, com/example/library/CoffeeMakerModule
However no processor actually runs (seen a few lines later) even though they are found in the compile classpath:
[INFO] Need to discovery annotation processors in the AP classpath
[INFO] Annotation processors: dagger.hilt.processor.internal.root.RootProcessor, dagger.hilt.android.processor.internal.uninstallmodules.UninstallModulesProcessor, dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor, dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor, dagger.hilt.android.processor.internal.bindvalue.BindValueProcessor, dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor, dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor, dagger.hilt.processor.internal.aliasof.AliasOfProcessor, dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor, dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor, dagger.internal.codegen.ComponentProcessor
[INFO] Processing java sources with annotation processors:
warning: The following options were not recognized by any processor: '[dagger.fastInit, dagger.hilt.android.internal.disableAndroidSuperclassValidation, kapt.kotlin.generated]'Round 1:
input files: {}
annotations: []
last round: false
Round 2:
input files: {}
annotations: []
last round: true
Which is weird because because Hilt's root processor is aggregating and based on Gradle's doc of incremental processor, it should always reprocess, and if it does (like its suppose to, I think) then it would generate the Dagger component interface (annotated with @Component) that the Dagger's ComponentProcessor would then pick-up and eventually determine the signature changes in the compiled classes being used as bindings and ultimately generate the correct Dagger component implementation.
@gavra0, can you please confirm my assumption in the last paragraph? That is, should an aggregating processor reprocess even though changes were only observed in compiled classes that are part of the Gradle module's dependencies?
An update: I've created the same project in Java (HiltIncrementalityJava.zip) and was not able to reproduce the issue, which is making kapt very suspicious as the possible culprit of this issue. 馃
In incremental KAPT it is possible to have classpath changes and not to run annotation processing. E.g:
X in classpath changesX i.e X is not a superclass, method return type, method param etc.In this case no sources are processed. In case there is at least 1 source to process, we'll add all sources annotated with annotations processed by aggregating annotation processors.
Does this explain the behaviour you are seeing?
Thanks Ivan! That sort of explains it. My follow up question is if this same logic applies to already generated sources?
The sample project in this issue has the following setup:
:app depends on :libraryX in :library is changedGeneratedSrc in :app that was created by an annotation processor depends on X (in various ways but one of them being its the return type of a method)GeneratedSrc was generated in :app because :app has sources with the aggregating annotationIf incremental KAPT looks only at the 'normal source set' (app/src/main/java), i.e. it does not considers generated sources in app/build/generated/source/kapt/ when determining if a classpath changes affects the module's sources, then that would explain what we are seeing here. But if it does considers them, then it might be something else.
That is correct, if classpath changes only impact the generated sources, KAPT will not launch annotation processing. We can address this on the KAPT side, but please keep in mind that we are unable to analyze Kotlin sources i.e only generated Java sources can be analyzed when calculating the impact of the classpath changes.
Hilt & Dagger only generate Java sources, so that's fine by us, it's a bit hard limitation but better than the current situation. Let me know if I should file a YouTrack issue to help get this resolved.
Until KSP comes in, only Java sources are supported sadly. Can you please file an issue on YouTrack about this?
Done, created an issue with a more minimal sample project: https://youtrack.jetbrains.com/issue/KT-42182
Most helpful comment
Done, created an issue with a more minimal sample project: https://youtrack.jetbrains.com/issue/KT-42182