google / dagger

A fast dependency injector for Android and Java.
https://dagger.dev
Apache License 2.0
17.42k stars 2.01k forks source link

Potential cache bug - "error: cannot find symbol" on injected element visibility change #3381

Open freszu opened 2 years ago

freszu commented 2 years ago

When changing visibility of injected element dagger compilation crashes with

DaggerVisibilityChangeBug/build/generated/source/kapt/main/DaggerA.java:38: error: cannot find symbol
    SomeActivity_MembersInjector.injectStringConsumer(instance, stringConsumer());
    ^
  symbol:   variable SomeActivity_MembersInjector
  location: class DaggerA

this can be resolved by cleaning the build cache after which compilation goes just fine.

I can reproduce the issue with my sample in dagger 2.41, 2.40 didn't check further but i think we faced this issue for some time in our Android App as well.

The minimal reproduction showing this issue with change visibility comment:

@Component
interface A {

    @Component.Factory
    interface Factory {
        fun create(@BindsInstance string: String): A
    }

    fun inject(someActivity: SomeActivity)
}

data class StringConsumer @Inject constructor(
    // change visibility here to crash compilation private<->public - comment uncomment next line
    private
    val string: String
)

class SomeActivity {
    @Inject
    lateinit var stringConsumer: StringConsumer
}

fun main() {
    val component = DaggerA.factory().create("hello")

    val activity = SomeActivity()

    component.inject(activity)

    println("trackerUser: ${activity.stringConsumer}")
}

The full ready to run project can be found here: https://github.com/freszu/DaggerVisibilityChangeBug

bcorso commented 2 years ago

I think this is an issue you will have to file with Gradle or maybe kapt. Dagger just registers its processor and relies on Gradle to run it whenever a source needs to be reprocessed. In this case, it seems like Gradle/kapt isn't doing that properly, and unfortunately I don't think there's anything we can do on our side to fix that.

danysantiago commented 2 years ago

You can try investigating if KAPT is reporting the source changes and running the processors by adding a few debug options to the build scripts:

 // in gradle.properties
kapt.verbose=true

// in build.gradle were kapt plugin is applied
kapt {
    javacOptions {
        option("-XprintProcessorInfo")
        option("-XprintRounds")
    }
}
freszu commented 2 years ago

I did run the sample with these flags, but i am not sure i can make proper conclusions out of it

Output for the failing build after public-> private val string ``` 13:56:47: Executing ':classes'... > Task :wrapper BUILD SUCCESSFUL in 274ms 1 actionable task: 1 executed > Task :processResources NO-SOURCE > Task :kaptGenerateStubsKotlin 'compileJava' task (current target is 15) and 'kaptGenerateStubsKotlin' task (current target is 1.8) jvm target compatibility should be set to the same Java version. > Task :kaptKotlin [INFO] Computing sources to reprocess took 2[ms]. [INFO] All Javac options: {-Akapt.kotlin.generated=/Documents/Projects/DaggerVisibilityChangeBug/build/generated/source/kaptKotlin/main=-Akapt.kotlin.generated=/Documents/Projects/DaggerVisibilityChangeBug/build/generated/source/kaptKotlin/main, -XprintProcessorInfo=-XprintProcessorInfo, -XprintRounds=-XprintRounds, --source=15, -proc:=only, accessInternalAPI=true, --class-path=/.sdkman/candidates/java/15.0.1.hs-adpt/lib/jrt-fs.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.6.21/eeb4d60d75e9ea9c11200d52974e522793b14fba/kotlin-stdlib-jdk8-1.6.21.jar:/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger/2.42/e0c9267991f4c4e167fc612947a948ffd27f3017/dagger-2.42.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.6.21/568c1b78a8e17a4f35b31f0a74e2916095ed74c2/kotlin-stdlib-jdk7-1.6.21.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.6.21/11ef67f1900634fd951bad28c53ec957fabbe5b8/kotlin-stdlib-1.6.21.jar:/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.6.21/5e5b55c26dbc80372a920aef60eb774b714559b8/kotlin-stdlib-common-1.6.21.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar:/Documents/Projects/DaggerVisibilityChangeBug/build/classes/kotlin/main:/Documents/Projects/DaggerVisibilityChangeBug/build/classes/java/main:/Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/classes/main, --processor-path=/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger-compiler/2.42/656b43f4b0bd2187c98c14b3a62396f6affff7a9/dagger-compiler-2.42.jar:/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger-spi/2.42/e9599b2ff69328210da70652d59749aaf3d29116/dagger-spi-2.42.jar:/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger-producers/2.42/9b1dc2cc206ec987462ce7836e4e691652498ff6/dagger-producers-2.42.jar:/.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger/2.42/e0c9267991f4c4e167fc612947a948ffd27f3017/dagger-2.42.jar:/.gradle/caches/modules-2/files-2.1/com.google.googlejavaformat/google-java-format/1.5/fba7f130d29061d2d2ea384b4880c10cae92ef73/google-java-format-1.5.jar:/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/31.0.1-jre/119ea2b2bc205b138974d351777b20f02b92704b/guava-31.0.1-jre.jar:/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar:/.gradle/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/1dcf1de382a0bf95a3d8b0849546c88bac1292c9/failureaccess-1.0.1.jar:/.gradle/caches/modules-2/files-2.1/com.squareup/javapoet/1.13.0/d6562d385049f35eb50403fa86bb11cce76b866a/javapoet-1.13.0.jar:/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar:/.gradle/caches/modules-2/files-2.1/net.ltgt.gradle.incap/incap/0.2/c73e3db9bee414d6ee27995d951fcdbee09acad/incap-0.2.jar:/.gradle/caches/modules-2/files-2.1/org.checkerframework/checker-compat-qual/2.5.5/435dc33e3019c9f019e15f01aa111de9d6b2b79c/checker-compat-qual-2.5.5.jar:/.gradle/caches/modules-2/files-2.1/com.google.devtools.ksp/symbol-processing-api/1.5.30-1.0.0/30b80a1bcf31915e03ec3785786f9b1528727d04/symbol-processing-api-1.5.30-1.0.0.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.5.32/2d6cb56872e6c1e27ddc53ebf844fdb09879df82/kotlin-stdlib-jdk8-1.5.32.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-metadata-jvm/0.4.2/8f80407e1e84727a7e7b9edd1323081c3ab1d8da/kotlinx-metadata-jvm-0.4.2.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.5.32/2e8f666555c2a6bf10ef712be8a738e665132c8/kotlin-stdlib-jdk7-1.5.32.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.6.10/b8af3fe6f1ca88526914929add63cf5e7c5049af/kotlin-stdlib-1.6.10.jar:/.gradle/caches/modules-2/files-2.1/com.google.errorprone/javac-shaded/9-dev-r4023-3/72b688efd290280a0afde5f9892b0fde6f362d1d/javac-shaded-9-dev-r4023-3.jar:/.gradle/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/b421526c5f297295adef1c886e5246c39d4ac629/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:/.gradle/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5/checker-qual-3.12.0.jar:/.gradle/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.7.1/458d9042f7aa6fa9a634df902b37f544e15aacac/error_prone_annotations-2.7.1.jar:/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/ba035118bc8bac37d7eff77700720999acd9986d/j2objc-annotations-1.3.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar:/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.6.10/c118700e3a33c8a0d9adc920e9dec0831171925/kotlin-stdlib-common-1.6.10.jar, -s=/Documents/Projects/DaggerVisibilityChangeBug/build/generated/source/kapt/main, -d=/Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/classes/main, -encoding=UTF-8} [INFO] Kapt3 is enabled (stand-alone mode). Annotation processing mode: apt Memory leak detection mode: none Show processor time: false Verbose mode: true Info as warnings: false Use light analysis: false Correct error types: false Dump default parameter values: false Map diagnostic locations: false Strict mode: false Detect annotation processors in compile classpath: true Incremental annotation processing (apt mode): true Strip @Metadata annotations from stubs: false Keep KDoc comments in stubs: false Project base dir: /Documents/Projects/DaggerVisibilityChangeBug Compile classpath: /.sdkman/candidates/java/15.0.1.hs-adpt/lib/jrt-fs.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.6.21/eeb4d60d75e9ea9c11200d52974e522793b14fba/kotlin-stdlib-jdk8-1.6.21.jar, /.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger/2.42/e0c9267991f4c4e167fc612947a948ffd27f3017/dagger-2.42.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.6.21/568c1b78a8e17a4f35b31f0a74e2916095ed74c2/kotlin-stdlib-jdk7-1.6.21.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.6.21/11ef67f1900634fd951bad28c53ec957fabbe5b8/kotlin-stdlib-1.6.21.jar, /.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.6.21/5e5b55c26dbc80372a920aef60eb774b714559b8/kotlin-stdlib-common-1.6.21.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar Java source roots: /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/SampleKt.java, /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/StringConsumer.java, /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/SomeActivity.java, /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/error/NonExistentClass.java, /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/A.java Sources output directory: /Documents/Projects/DaggerVisibilityChangeBug/build/generated/source/kapt/main Class files output directory: /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/classes/main Stubs output directory: /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main Incremental data output directory: /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main Annotation processing classpath: /.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger-compiler/2.42/656b43f4b0bd2187c98c14b3a62396f6affff7a9/dagger-compiler-2.42.jar, /.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger-spi/2.42/e9599b2ff69328210da70652d59749aaf3d29116/dagger-spi-2.42.jar, /.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger-producers/2.42/9b1dc2cc206ec987462ce7836e4e691652498ff6/dagger-producers-2.42.jar, /.gradle/caches/modules-2/files-2.1/com.google.dagger/dagger/2.42/e0c9267991f4c4e167fc612947a948ffd27f3017/dagger-2.42.jar, /.gradle/caches/modules-2/files-2.1/com.google.googlejavaformat/google-java-format/1.5/fba7f130d29061d2d2ea384b4880c10cae92ef73/google-java-format-1.5.jar, /.gradle/caches/modules-2/files-2.1/com.google.guava/guava/31.0.1-jre/119ea2b2bc205b138974d351777b20f02b92704b/guava-31.0.1-jre.jar, /.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/3.0.2/25ea2e8b0c338a877313bd4672d3fe056ea78f0d/jsr305-3.0.2.jar, /.gradle/caches/modules-2/files-2.1/com.google.guava/failureaccess/1.0.1/1dcf1de382a0bf95a3d8b0849546c88bac1292c9/failureaccess-1.0.1.jar, /.gradle/caches/modules-2/files-2.1/com.squareup/javapoet/1.13.0/d6562d385049f35eb50403fa86bb11cce76b866a/javapoet-1.13.0.jar, /.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar, /.gradle/caches/modules-2/files-2.1/net.ltgt.gradle.incap/incap/0.2/c73e3db9bee414d6ee27995d951fcdbee09acad/incap-0.2.jar, /.gradle/caches/modules-2/files-2.1/org.checkerframework/checker-compat-qual/2.5.5/435dc33e3019c9f019e15f01aa111de9d6b2b79c/checker-compat-qual-2.5.5.jar, /.gradle/caches/modules-2/files-2.1/com.google.devtools.ksp/symbol-processing-api/1.5.30-1.0.0/30b80a1bcf31915e03ec3785786f9b1528727d04/symbol-processing-api-1.5.30-1.0.0.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.5.32/2d6cb56872e6c1e27ddc53ebf844fdb09879df82/kotlin-stdlib-jdk8-1.5.32.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-metadata-jvm/0.4.2/8f80407e1e84727a7e7b9edd1323081c3ab1d8da/kotlinx-metadata-jvm-0.4.2.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.5.32/2e8f666555c2a6bf10ef712be8a738e665132c8/kotlin-stdlib-jdk7-1.5.32.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.6.10/b8af3fe6f1ca88526914929add63cf5e7c5049af/kotlin-stdlib-1.6.10.jar, /.gradle/caches/modules-2/files-2.1/com.google.errorprone/javac-shaded/9-dev-r4023-3/72b688efd290280a0afde5f9892b0fde6f362d1d/javac-shaded-9-dev-r4023-3.jar, /.gradle/caches/modules-2/files-2.1/com.google.guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/b421526c5f297295adef1c886e5246c39d4ac629/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar, /.gradle/caches/modules-2/files-2.1/org.checkerframework/checker-qual/3.12.0/d5692f0526415fcc6de94bb5bfbd3afd9dd3b3e5/checker-qual-3.12.0.jar, /.gradle/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.7.1/458d9042f7aa6fa9a634df902b37f544e15aacac/error_prone_annotations-2.7.1.jar, /.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.3/ba035118bc8bac37d7eff77700720999acd9986d/j2objc-annotations-1.3.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar, /.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.6.10/c118700e3a33c8a0d9adc920e9dec0831171925/kotlin-stdlib-common-1.6.10.jar Annotation processors: AP options: {kapt.kotlin.generated=/Documents/Projects/DaggerVisibilityChangeBug/build/generated/source/kaptKotlin/main} Javac options: {-XprintProcessorInfo=, -XprintRounds=, --source=15} [incremental apt] Changed files: [/Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/StringConsumer.java] [incremental apt] Compiled sources directories: /Documents/Projects/DaggerVisibilityChangeBug/build/classes/kotlin/main, /Documents/Projects/DaggerVisibilityChangeBug/build/classes/java/main [incremental apt] Cache directory for incremental compilation: /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/incApCache/main [incremental apt] Changed classpath names: [INFO] Need to discovery annotation processors in the AP classpath [INFO] Use own ClassLoader for processor 'dagger.internal.codegen.ComponentProcessor' [INFO] Annotation processors: dagger.internal.codegen.ComponentProcessor [INFO] Processing java sources with annotation processors: /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/StringConsumer.java, /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/SomeActivity.java, /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/A.java, /Documents/Projects/DaggerVisibilityChangeBug/build/tmp/kapt3/stubs/main/error/NonExistentClass.java [INFO] Processing types with annotation processors: Round 1: input files: {StringConsumer, SomeActivity, A, error.NonExistentClass} annotations: [kotlin.Metadata, org.jetbrains.annotations.NotNull, java.lang.Override, org.jetbrains.annotations.Nullable, javax.inject.Inject, dagger.Component, dagger.Component.Factory, dagger.BindsInstance] last round: false Processor org.jetbrains.kotlin.kapt3.base.ProcessorWrapper matches [/dagger.Component.Factory, /dagger.Component, /javax.inject.Inject, /dagger.BindsInstance] and returns false. Round 2: input files: {DaggerA} annotations: [dagger.internal.DaggerGenerated, javax.annotation.processing.Generated, java.lang.SuppressWarnings, java.lang.Override] last round: false Processor org.jetbrains.kotlin.kapt3.base.ProcessorWrapper matches [] and returns false. Round 3: input files: {} annotations: [] last round: true [INFO] Analyzing sources structure took 2[ms]. [INFO] Annotation processing complete, errors: 0, warnings: 0 [INFO] Annotation processor stats: [INFO] dagger.internal.codegen.ComponentProcessor: total: 1275 ms, init: 192 ms, 3 round(s): 1075 ms, 8 ms, 0 ms [INFO] Annotation processing took 1364 ms File Object History : [] Open Type Names : [] Gen. Src Names : [] Gen. Cls Names : [] Agg. Gen. Src Names : [] Agg. Gen. Cls Names : [] > Task :compileKotlin 'compileJava' task (current target is 15) and 'compileKotlin' task (current target is 1.8) jvm target compatibility should be set to the same Java version. > Task :compileJava FAILED /Documents/Projects/DaggerVisibilityChangeBug/build/generated/source/kapt/main/DaggerA.java:50: error: cannot find symbol SomeActivity_MembersInjector.injectStringConsumer(instance, stringConsumer()); ^ symbol: variable SomeActivity_MembersInjector location: class AImpl 1 error FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':compileJava'. > Compilation failed; see the compiler error output for details. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 3s 4 actionable tasks: 4 executed 13:56:51: Execution finished ':classes'. ```

StringConsumer was marked as changed but i can't point the reason for which SomeActivity_MembersInjector was removed (after all it shouldn't change so that would be the expected behavior for me) or not ended up being regenerated

danysantiago commented 2 years ago

Thanks, I still believe this is an issue with KAPT and I suggest you report it to https://youtrack.jetbrains.com/

If you use no build cache things work fine: ./gradlew compileKotlin --no-build-cache which is a big indicator there is something going on with incremental compilations, something Dagger has no real control off.

Moreover, if you downgrade Kotlin to 1.5.32, the issue is not reproducible, which is a clear indicator of some type of regression with KAPT.

From Dagger's perspective, what happening is that Dagger checks if the generated members injector, SomeActivity_MembersInjector is in the classpath (meaning it was already generated) and then it skips generating it even though SomeActivity is indeed being reprocessed. This is a common scenario that happens if you run Dagger in a library module with @Inject, Dagger will generated member injectors and factories early so those don't have to be generated when processing the @Component in a module that consumed the library.

When you make a change in a source, Gradle + KAPT will delete the generated sources relevant to that class, because they are invalid, but is seems that even though the generated sources are deleted, the classes are still in the classpath, which makes Dagger believe they are already generated, but in the end they are not part of the compilation. The location from which SomeActivity_MembersInjector is coming from is interesting, when attaching a debugger it points to build/classes/java/main/SomeActivity_MembersInjector.class even though as part of the incremental compilation, the previous sources in build/generated/source/kapt were all deleted, so I think the issue relies in the cache or incremental data not being correct.

PavelKapustsin commented 2 years ago

Just a simple note here, that's the problem isn't new for the KAPT and there are already a few tickets created. https://youtrack.jetbrains.com/issue/KT-21735 https://youtrack.jetbrains.com/issue/KT-38557 https://youtrack.jetbrains.com/issue/KT-40750 etc

Though, not a one has been actually fixed so far.